Skip to content

Commit

Permalink
Merge commit '2b65837442a37561aee046ac9ac7ac9224aea5d4' into feature/…
Browse files Browse the repository at this point in the history
…performance-stable
  • Loading branch information
1azyman committed Apr 19, 2018
2 parents 539090e + 2b65837 commit 6ca9569
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 13 deletions.
Expand Up @@ -31,9 +31,7 @@
import com.evolveum.midpoint.web.component.input.ExpressionValuePanel;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.util.InfoTooltipBehavior;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.prism.xml.ns._public.types_3.ItemDeltaType;
import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType;

Expand Down Expand Up @@ -261,7 +259,11 @@ public boolean isVisible() {
@Override
protected void populateItem(final ListItem<ValueWrapper> item) {
BasePanel panel;
if (item.getModelObject().getItem().getItemDefinition().getTypeName().equals(ExpressionType.COMPLEX_TYPE)){
ItemWrapper itemWrapper = item.getModelObject().getItem();
if (itemWrapper.getPath().containsName(AssignmentType.F_CONSTRUCTION) &&
itemWrapper.getPath().containsName(ConstructionType.F_ASSOCIATION) &&
itemWrapper.getPath().containsName(ResourceObjectAssociationType.F_OUTBOUND) &&
itemWrapper.getPath().containsName(MappingType.F_EXPRESSION)){
ExpressionWrapper expressionWrapper = (ExpressionWrapper)item.getModelObject().getItem();
panel = new ExpressionValuePanel("value", new PropertyModel(item.getModel(), "value.value"),
expressionWrapper.getConstruction(), pageBase);
Expand Down
Expand Up @@ -102,6 +102,8 @@
public class SqlRepositoryServiceImpl extends SqlBaseService implements RepositoryService {

public static final String PERFORMANCE_LOG_NAME = SqlRepositoryServiceImpl.class.getName() + ".performance";
public static final String CONTENTION_LOG_NAME = SqlRepositoryServiceImpl.class.getName() + ".contention";
public static final int CONTENTION_LOG_DEBUG_THRESHOLD = 3;

private static final Trace LOGGER = TraceManager.getTrace(SqlRepositoryServiceImpl.class);
private static final Trace LOGGER_PERFORMANCE = TraceManager.getTrace(PERFORMANCE_LOG_NAME);
Expand Down
Expand Up @@ -53,6 +53,7 @@
public class BaseHelper {

private static final Trace LOGGER = TraceManager.getTrace(BaseHelper.class);
private static final Trace CONTENTION_LOGGER = TraceManager.getTrace(SqlRepositoryServiceImpl.CONTENTION_LOG_NAME);

@Autowired
private SessionFactory sessionFactory;
Expand Down Expand Up @@ -202,15 +203,22 @@ public int logOperationAttempt(String oid, String operation, int attempt, @NotNu
try {
waitTime = backoffComputer.computeDelay(attempt);
} catch (BackoffComputer.NoMoreRetriesException e) {
LOGGER.error("A serialization-related problem occurred, maximum attempts (" + attempt + ") reached.", ex);
CONTENTION_LOGGER.error("A serialization-related problem occurred, maximum attempts ({}) reached.", attempt, ex);
LOGGER.error("A serialization-related problem occurred, maximum attempts ({}) reached.", attempt, ex);
if (result != null) {
result.recordFatalError("A serialization-related problem occurred.", ex);
}
throw new SystemException(ex.getMessage() + " [attempts: " + attempt + "]", ex);
}
LOGGER.debug("A serialization-related problem occurred when {} object with oid '{}', retrying after "
+ "{} ms (this is retry {} of {})\n{}: {}", operation, oid, waitTime,
attempt, LOCKING_MAX_RETRIES, ex.getClass().getSimpleName(), ex.getMessage());
String message = "A serialization-related problem occurred when {} object with oid '{}', retrying after "
+ "{} ms (this is retry {} of {})\n{}: {}";
Object[] objects = { operation, oid, waitTime, attempt, LOCKING_MAX_RETRIES, ex.getClass().getSimpleName(), ex.getMessage() };
if (attempt >= SqlRepositoryServiceImpl.CONTENTION_LOG_DEBUG_THRESHOLD) {
CONTENTION_LOGGER.debug(message, objects);
} else {
CONTENTION_LOGGER.trace(message, objects);
}
LOGGER.debug(message, objects);
if (waitTime > 0) {
try {
Thread.sleep(waitTime);
Expand Down
Expand Up @@ -118,6 +118,7 @@ public class TaskManagerQuartzImpl implements TaskManager, BeanFactoryAware {
private static final String DOT_INTERFACE = TaskManager.class.getName() + ".";
private static final String DOT_IMPL_CLASS = TaskManagerQuartzImpl.class.getName() + ".";
private static final String CLEANUP_TASKS = DOT_INTERFACE + "cleanupTasks";
public static final String CONTENTION_LOG_NAME = TaskManagerQuartzImpl.class.getName() + ".contention";

@Autowired
private TaskManagerConfiguration configuration;
Expand Down
Expand Up @@ -35,6 +35,7 @@
import com.evolveum.midpoint.task.api.TaskExecutionStatus;
import com.evolveum.midpoint.task.api.TaskManager;
import com.evolveum.midpoint.task.quartzimpl.TaskManagerConfiguration;
import com.evolveum.midpoint.task.quartzimpl.TaskManagerQuartzImpl;
import com.evolveum.midpoint.task.quartzimpl.TaskQuartzImpl;
import com.evolveum.midpoint.task.quartzimpl.work.segmentation.content.WorkBucketContentHandler;
import com.evolveum.midpoint.task.quartzimpl.work.segmentation.content.WorkBucketContentHandlerRegistry;
Expand Down Expand Up @@ -78,6 +79,7 @@
public class WorkStateManager {

private static final Trace LOGGER = TraceManager.getTrace(WorkStateManager.class);
private static final Trace CONTENTION_LOGGER = TraceManager.getTrace(TaskManagerQuartzImpl.CONTENTION_LOG_NAME);

@Autowired private TaskManager taskManager;
@Autowired private RepositoryService repositoryService;
Expand Down Expand Up @@ -169,6 +171,7 @@ private WorkBucketType findSelfAllocatedBucket(Context ctx) {
private WorkBucketType getWorkBucketMultiNode(Context ctx, long freeBucketWaitTime, OperationResult result)
throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException, InterruptedException {
long start = System.currentTimeMillis();
int globalAttempt = 0; // just for statistics
WorkSegmentationStrategy workStateStrategy = strategyFactory.createStrategy(ctx.coordinatorTask.getWorkManagement());
setOrUpdateEstimatedNumberOfBuckets(ctx.coordinatorTask, workStateStrategy, result);

Expand All @@ -179,6 +182,7 @@ private WorkBucketType getWorkBucketMultiNode(Context ctx, long freeBucketWaitTi
waitForConflictLessUpdate: // this cycle exits when coordinator task update succeeds
for (;;) {
TaskWorkStateType coordinatorWorkState = getWorkStateOrNew(ctx.coordinatorTask.getTaskPrismObject());
globalAttempt++;
GetBucketResult response = workStateStrategy.getBucket(coordinatorWorkState);
LOGGER.trace("getWorkBucketMultiNode: workStateStrategy returned {} for worker task {}, coordinator {}", response, ctx.workerTask, ctx.coordinatorTask);
try {
Expand All @@ -198,6 +202,7 @@ private WorkBucketType getWorkBucketMultiNode(Context ctx, long freeBucketWaitTi
bucketsReplacePrecondition(coordinatorWorkState.getBucket()), null, result);
repositoryService.modifyObject(TaskType.class, ctx.workerTask.getOid(),
bucketsAddDeltas(newBucketsResponse.newBuckets.subList(selected, selected+1)), null, result);
CONTENTION_LOGGER.trace("New bucket(s) acquired after {} ms (attempt #{}) in {}", System.currentTimeMillis() - start, globalAttempt, ctx.workerTask);
return newBucketsResponse.newBuckets.get(selected);
} else if (response instanceof FoundExisting) {
FoundExisting existingResponse = (FoundExisting) response;
Expand All @@ -207,20 +212,26 @@ private WorkBucketType getWorkBucketMultiNode(Context ctx, long freeBucketWaitTi
WorkBucketType foundBucket = existingResponse.bucket.clone();
repositoryService.modifyObject(TaskType.class, ctx.workerTask.getOid(),
bucketsAddDeltas(singletonList(foundBucket)), null, result);
CONTENTION_LOGGER.trace("Existing bucket acquired after {} ms (attempt #{}) in {}", System.currentTimeMillis() - start, globalAttempt, ctx.workerTask);
return foundBucket;
} else if (response instanceof NothingFound) {
if (((NothingFound) response).definite || freeBucketWaitTime == 0L) {
markWorkComplete(ctx.coordinatorTask, result); // TODO also if response is not definite?
CONTENTION_LOGGER.trace("'No bucket' found after {} ms (attempt #{}) in {}", System.currentTimeMillis() - start, globalAttempt, ctx.workerTask);
return null;
} else {
long waitDeadline = freeBucketWaitTime >= 0 ? start + freeBucketWaitTime : Long.MAX_VALUE;
long toWait = waitDeadline - System.currentTimeMillis();
if (toWait <= 0) {
markWorkComplete(ctx.coordinatorTask, result); // TODO also if response is not definite?
CONTENTION_LOGGER.trace("'No bucket' found (wait time elapsed) after {} ms (attempt #{}) in {}", System.currentTimeMillis() - start, globalAttempt, ctx.workerTask);
return null;
}
//System.out.println("*** No free work bucket -- waiting ***");
dynamicSleep(Math.min(toWait, getFreeBucketWaitInterval()), ctx);
long sleepFor = Math.min(toWait, getFreeBucketWaitInterval());
CONTENTION_LOGGER.trace("Entering waiting for free bucket (waiting for {}) - after {} ms (attempt #{}) in {}",
sleepFor, System.currentTimeMillis() - start, globalAttempt, ctx.workerTask);
dynamicSleep(sleepFor, ctx);
ctx.reloadCoordinatorTask(result);
ctx.reloadWorkerTask(result);
if (reclaimWronglyAllocatedBuckets(ctx.coordinatorTask, result)) {
Expand All @@ -239,11 +250,16 @@ private WorkBucketType getWorkBucketMultiNode(Context ctx, long freeBucketWaitTi
try {
delay = backoffComputer.computeDelay(retry);
} catch (BackoffComputer.NoMoreRetriesException e1) {
throw new SystemException(
"Couldn't allocate work bucket because of repeated database conflicts (retry limit reached); coordinator task = " + ctx.coordinatorTask, e1);
String message =
"Couldn't allocate work bucket because of repeated database conflicts (retry limit reached); coordinator task = "
+ ctx.coordinatorTask;
CONTENTION_LOGGER.error(message, e1);
throw new SystemException(message, e1);
}
LOGGER.info("getWorkBucketMultiNode: conflict; continuing as retry #{}; waiting {} ms in {}, worker {}",
retry, delay, ctx.coordinatorTask, ctx.workerTask, e);
String message = "getWorkBucketMultiNode: conflict; continuing as retry #{}; waiting {} ms in {}, worker {}";
Object[] objects = { retry, delay, ctx.coordinatorTask, ctx.workerTask, e };
CONTENTION_LOGGER.debug(message, objects);
LOGGER.info(message, objects); // todo change to trace
dynamicSleep(delay, ctx);
ctx.reloadCoordinatorTask(result);
ctx.reloadWorkerTask(result);
Expand Down Expand Up @@ -320,6 +336,7 @@ private boolean reclaimWronglyAllocatedBuckets(Task coordinatorTask, OperationRe
}
LOGGER.trace("Reclaiming wrongly allocated buckets found {} buckets to reclaim in {}", reclaiming, coordinatorTask);
if (reclaiming > 0) {
CONTENTION_LOGGER.debug("Reclaiming wrongly allocated buckets found {} buckets to reclaim in {}", reclaiming, coordinatorTask);
repositoryService.modifyObject(TaskType.class, coordinatorTask.getOid(),
bucketsReplaceDeltas(newState.getBucket()),
bucketsReplacePrecondition(originalState.getBucket()), null, result);
Expand Down
61 changes: 61 additions & 0 deletions samples/objects/function-library-mail-templates.xml
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2010-2018 Evolveum
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<functionLibrary oid="bc5d74e6-4317-11e8-9dec-8fd64e20fbe0"
xmlns='http://midpoint.evolveum.com/xml/ns/public/common/common-3'
xmlns:c='http://midpoint.evolveum.com/xml/ns/public/common/common-3'
xmlns:t='http://prism.evolveum.com/xml/ns/public/types-3'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
<name>mailTemplates</name>
<description>Velocity mail templates for various languages</description>
<function>
<name>en</name>
<parameter>
<name>username</name>
<type>xsd:string</type>
</parameter>
<script>
<language>http://midpoint.evolveum.com/xml/ns/public/expression/language#velocity</language>
<code>Hello $username</code>
</script>
<returnType>xsd:string</returnType>
</function>
<function>
<name>sk</name>
<parameter>
<name>username</name>
<type>xsd:string</type>
</parameter>
<script>
<language>http://midpoint.evolveum.com/xml/ns/public/expression/language#velocity</language>
<code>Ahoj $username</code>
</script>
<returnType>xsd:string</returnType>
</function>
<function>
<name>default</name>
<parameter>
<name>username</name>
<type>xsd:string</type>
</parameter>
<script>
<language>http://midpoint.evolveum.com/xml/ns/public/expression/language#velocity</language>
<code>Ugh $username !!!</code>
</script>
<returnType>xsd:string</returnType>
</function>
</functionLibrary>
85 changes: 85 additions & 0 deletions samples/objects/system-configuration-multilanguage-notifier.xml
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2010-2018 Evolveum
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<systemConfiguration
xmlns='http://midpoint.evolveum.com/xml/ns/public/common/common-3'
xmlns:c='http://midpoint.evolveum.com/xml/ns/public/common/common-3'
xmlns:t='http://prism.evolveum.com/xml/ns/public/types-3'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
<name>System Configuration</name>

<!-- ... -->

<notificationConfiguration>
<handler>
<generalNotifier>
<name>Welcome new user</name>
<expressionFilter>
<script>
<code>
import com.evolveum.midpoint.notifications.api.events.ModelEvent
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType

(event instanceof ModelEvent &amp;&amp; event.getFocusContext() != null &amp;&amp; UserType.class.isAssignableFrom(event.getFocusContext().getObjectTypeClass()) &amp;&amp; event.getFocusContext().isAdd()))
</code>
</script>
</expressionFilter>
<recipientExpression>
<value>iam@localhost</value>
</recipientExpression>
<subjectExpression>
<script>
<code>
return 'New user notification'
</code>
</script>
</subjectExpression>
<bodyExpression>
<script>
<code>
import com.evolveum.midpoint.notifications.api.events.ModelEvent;

focusContext = ((ModelEvent) event).getFocusContext();
objectNew = focusContext.getObjectNew();
username = basic.stringify(objectNew.getName());

language = objectNew.asObjectable().getPreferredLanguage();
if (!language) {
language = 'default'
}

templateParams = new HashMap()
templateParams.put("username", username)
return mailTemplates.execute(language, templateParams)
</code>
</script>
</bodyExpression>
<transport>mail</transport>
</generalNotifier>
</handler>
<!-- configurations suitable for testing - they redirect all notifications to log files; some more real configurations are show below -->
<mail>
<redirectToFile>mail-notifications.log</redirectToFile>
</mail>
<sms>
<redirectToFile>sms-notifications.log</redirectToFile>
</sms>
</notificationConfiguration>

<!-- ... -->

</systemConfiguration>

0 comments on commit 6ca9569

Please sign in to comment.