use of com.evolveum.midpoint.xml.ns._public.common.common_3.TaskExecutionStateType.RUNNABLE in project midpoint by Evolveum.
the class OrgClosureConcurrencyTest method _test300AddRemoveNodesMT.
protected void _test300AddRemoveNodesMT(final boolean random) throws Exception {
OperationResult opResult = new OperationResult("===[ test300AddRemoveNodesMT ]===");
info("test300AddRemoveNodes starting with random = " + random);
final Set<ObjectType> nodesToRemove = Collections.synchronizedSet(new HashSet<>());
final Set<ObjectType> nodesToAdd = Collections.synchronizedSet(new HashSet<>());
final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<>());
for (int level = 0; level < getConfiguration().getNodeRoundsForLevel().length; level++) {
int rounds = getConfiguration().getNodeRoundsForLevel()[level];
List<String> levelOids = orgsByLevels.get(level);
generateNodesAtOneLevel(nodesToRemove, nodesToAdd, OrgType.class, rounds, levelOids, opResult);
}
int numberOfRunners = THREADS;
final List<Thread> runners = Collections.synchronizedList(new ArrayList<>());
for (int i = 0; i < numberOfRunners; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
ObjectType objectType = getNext(nodesToRemove, random);
if (objectType == null) {
break;
}
logger.info("Removing {}", objectType);
int remaining;
try {
removeObject(objectType);
synchronized (OrgClosureConcurrencyTest.this) {
nodesToRemove.remove(objectType);
remaining = nodesToRemove.size();
}
info(Thread.currentThread().getName() + " removed " + objectType + "; remaining: " + remaining);
} catch (ObjectNotFoundException e) {
// this is OK
info(Thread.currentThread().getName() + ": " + objectType + " already deleted");
// give other threads a chance
Thread.sleep(300);
}
}
} catch (Throwable e) {
e.printStackTrace();
exceptions.add(e);
} finally {
runners.remove(Thread.currentThread());
}
}
};
Thread t = new Thread(runnable);
runners.add(t);
t.start();
}
waitForRunnersCompletion(runners);
if (!nodesToRemove.isEmpty()) {
throw new AssertionError("Nodes to remove is not empty, see the console or log: " + nodesToRemove);
}
if (!exceptions.isEmpty()) {
throw new AssertionError("Found exceptions: " + exceptions);
}
rebuildGraph();
checkClosure(orgGraph.vertexSet());
info("Consistency after removing OK");
numberOfRunners = THREADS;
for (int i = 0; i < numberOfRunners; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
ObjectType objectType = getNext(nodesToAdd, random);
if (objectType == null) {
break;
}
logger.info("Adding {}", objectType);
try {
addObject(objectType.clone());
// rebuildGraph();
// checkClosure(orgGraph.vertexSet());
int remaining;
synchronized (OrgClosureConcurrencyTest.this) {
nodesToAdd.remove(objectType);
remaining = nodesToAdd.size();
}
info(Thread.currentThread().getName() + " re-added " + objectType + "; remaining: " + remaining);
} catch (ObjectAlreadyExistsException e) {
// this is OK
info(Thread.currentThread().getName() + ": " + objectType + " already exists");
// give other threads a chance
Thread.sleep(300);
}
}
} catch (Throwable e) {
e.printStackTrace();
exceptions.add(e);
} finally {
runners.remove(Thread.currentThread());
}
}
};
Thread t = new Thread(runnable);
runners.add(t);
t.start();
}
waitForRunnersCompletion(runners);
if (!nodesToAdd.isEmpty()) {
throw new AssertionError("Nodes to add is not empty, see the console or log: " + nodesToAdd);
}
if (!exceptions.isEmpty()) {
throw new AssertionError("Found exceptions: " + exceptions);
}
rebuildGraph();
checkClosure(orgGraph.vertexSet());
info("Consistency after re-adding OK");
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.TaskExecutionStateType.RUNNABLE in project midpoint by Evolveum.
the class OrgClosureConcurrencyTest method _test200AddRemoveLinksMT.
/**
* We randomly select a set of links to be removed.
* Then we remove them, using a given set of threads.
* After all threads are done, we will check the closure table consistency.
* <p>
* And after that, we will do the reverse, re-adding all the links previously removed.
* In the end, we again check the consistency.
*/
protected void _test200AddRemoveLinksMT(final boolean random) throws Exception {
OperationResult opResult = new OperationResult("===[ test200AddRemoveLinksMT ]===");
info("test200AddRemoveLinks starting with random = " + random);
final Set<Edge> edgesToRemove = Collections.synchronizedSet(new HashSet<>());
final Set<Edge> edgesToAdd = Collections.synchronizedSet(new HashSet<>());
final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<>());
// parentRef link removal + addition
for (int level = 0; level < getConfiguration().getLinkRoundsForLevel().length; level++) {
int rounds = getConfiguration().getLinkRoundsForLevel()[level];
List<String> levelOids = orgsByLevels.get(level);
int retries = 0;
for (int round = 0; round < rounds; round++) {
int index = (int) Math.floor(Math.random() * levelOids.size());
String oid = levelOids.get(index);
OrgType org = repositoryService.getObject(OrgType.class, oid, null, opResult).asObjectable();
// check if it has no parents (shouldn't occur here!)
if (org.getParentOrgRef().isEmpty()) {
throw new IllegalStateException("No parents in " + org);
}
int i = (int) Math.floor(Math.random() * org.getParentOrgRef().size());
ObjectReferenceType parentOrgRef = org.getParentOrgRef().get(i);
Edge edge = new Edge(oid, parentOrgRef.getOid());
if (edgesToRemove.contains(edge)) {
round--;
if (++retries == 1000) {
// primitive attempt to break potential cycles when there is not enough edges to process
throw new IllegalStateException("Too many retries");
} else {
continue;
}
}
edgesToRemove.add(edge);
edgesToAdd.add(edge);
}
}
int numberOfRunners = THREADS;
info("Edges to remove/add (" + edgesToRemove.size() + ": " + edgesToRemove);
info("Number of runners: " + numberOfRunners);
final List<Thread> runners = Collections.synchronizedList(new ArrayList<>());
for (int i = 0; i < numberOfRunners; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
Edge edge = getNext(edgesToRemove, random);
if (edge == null) {
break;
}
logger.info("Removing {}", edge);
removeEdge(edge);
int remaining;
synchronized (OrgClosureConcurrencyTest.this) {
edgesToRemove.remove(edge);
remaining = edgesToRemove.size();
}
info(Thread.currentThread().getName() + " removed " + edge + "; remaining: " + remaining);
}
} catch (Throwable e) {
e.printStackTrace();
exceptions.add(e);
} finally {
runners.remove(Thread.currentThread());
}
}
};
Thread t = new Thread(runnable);
runners.add(t);
t.start();
}
waitForRunnersCompletion(runners);
if (!edgesToRemove.isEmpty()) {
throw new AssertionError("Edges to remove is not empty, see the console or log: " + edgesToRemove);
}
if (!exceptions.isEmpty()) {
throw new AssertionError("Found exceptions: " + exceptions);
}
checkClosure(orgGraph.vertexSet());
info("Consistency after removal OK");
for (int i = 0; i < numberOfRunners; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
Edge edge = getNext(edgesToAdd, random);
if (edge == null) {
break;
}
logger.info("Adding {}", edge);
addEdge(edge);
int remaining;
synchronized (OrgClosureConcurrencyTest.this) {
edgesToAdd.remove(edge);
remaining = edgesToAdd.size();
}
info(Thread.currentThread().getName() + " re-added " + edge + "; remaining: " + remaining);
}
} catch (Throwable e) {
e.printStackTrace();
exceptions.add(e);
} finally {
runners.remove(Thread.currentThread());
}
}
};
Thread t = new Thread(runnable);
runners.add(t);
t.start();
}
waitForRunnersCompletion(runners);
if (!edgesToAdd.isEmpty()) {
throw new AssertionError("Edges to add is not empty, see the console or log: " + edgesToAdd);
}
if (!exceptions.isEmpty()) {
throw new AssertionError("Found exceptions: " + exceptions);
}
checkClosure(orgGraph.vertexSet());
info("Consistency after re-adding OK");
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.TaskExecutionStateType.RUNNABLE in project midpoint by Evolveum.
the class ExtDictionaryTest method test100ParallelAdd.
@Test
public void test100ParallelAdd() throws Exception {
for (int round = 0; round < ROUNDS; round++) {
List<TestingThread> threads = new ArrayList<>();
for (int i = 0; i < THREADS; i++) {
final int round1 = round;
final int thread1 = i;
Runnable runnable = () -> {
try {
UserType user = new UserType(prismContext).name("u-" + round1 + "-" + thread1);
QName propertyName = new QName(NS_TEST, "round" + round1);
MutablePrismPropertyDefinition<String> propertyDefinition = prismContext.definitionFactory().createPropertyDefinition(propertyName, DOMUtil.XSD_STRING);
PrismProperty<String> property = propertyDefinition.instantiate();
property.setRealValue("value");
user.asPrismObject().addExtensionItem(property);
repositoryService.addObject(user.asPrismObject(), null, new OperationResult("addObject"));
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new SystemException(e);
}
};
TestingThread thread = new TestingThread(runnable);
threads.add(thread);
thread.start();
}
for (int i = 0; i < THREADS; i++) {
TestingThread thread = threads.get(i);
thread.join(60000L);
if (thread.throwable != null) {
fail("Exception in " + thread + ": " + thread.throwable);
}
}
}
Session session = open();
// noinspection unchecked
List<RExtItem> extItems = session.createQuery("from RExtItem").list();
System.out.println("ext items: " + extItems.size());
for (RExtItem extItem : extItems) {
System.out.println(extItem);
logger.info("{}", extItem);
}
session.close();
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.TaskExecutionStateType.RUNNABLE in project midpoint by Evolveum.
the class TaskSynchronizer method synchronizeTask.
/**
* Task should be refreshed when entering this method.
*
* @return true if task info in Quartz was updated
*/
public boolean synchronizeTask(TaskQuartzImpl task, OperationResult parentResult) {
if (!task.isPersistent()) {
// transient tasks are not scheduled via Quartz!
return false;
}
boolean changed = false;
StringBuilder message = new StringBuilder();
OperationResult result = parentResult.createSubresult(OP_SYNCHRONIZE_TASK);
result.addArbitraryObjectAsParam("task", task);
try {
taskMigrator.migrateIfNeeded(task, result);
LOGGER.trace("Synchronizing task {}; isRecreateQuartzTrigger = {}", task, task.isRecreateQuartzTrigger());
Scheduler scheduler = localScheduler.getQuartzScheduler();
String oid = task.getOid();
JobKey jobKey = QuartzUtil.createJobKeyForTask(task);
TriggerKey standardTriggerKey = QuartzUtil.createTriggerKeyForTask(task);
TaskSchedulingStateType schedulingState = task.getSchedulingState();
boolean waitingOrClosedOrSuspended = schedulingState == TaskSchedulingStateType.WAITING || schedulingState == TaskSchedulingStateType.CLOSED || schedulingState == TaskSchedulingStateType.SUSPENDED;
if (!scheduler.checkExists(jobKey) && !waitingOrClosedOrSuspended) {
String m1 = "Quartz job does not exist for a task, adding it. Task = " + task;
message.append("[").append(m1).append("] ");
LOGGER.trace(" - {}", m1);
scheduler.addJob(QuartzUtil.createJobDetailForTask(task), false);
changed = true;
}
// CLOSED tasks should have no triggers; SUSPENDED and WAITING tasks should have no extra triggers
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
boolean standardTriggerExists = triggers.stream().anyMatch(t -> t.getKey().equals(standardTriggerKey));
if (waitingOrClosedOrSuspended) {
for (Trigger trigger : triggers) {
if (schedulingState == TaskSchedulingStateType.CLOSED || !trigger.getKey().equals(standardTriggerKey)) {
String m1 = "Removing Quartz trigger " + trigger.getKey() + " for WAITING/CLOSED/SUSPENDED task " + task;
message.append("[").append(m1).append("] ");
LOGGER.trace(" - {}", m1);
scheduler.unscheduleJob(trigger.getKey());
changed = true;
} else {
// For SUSPENDED/WAITING tasks, we keep the standard trigger untouched. We want to preserve original
// scheduled time. (This might or might not be what the user wants ... but it has been so for so
// many years, so let's not change it now.)
//
// It's harmless to keep the standard trigger, because:
// 1) If a trigger is mistakenly alive, JobExecutor will take care of it.
// 2) If a trigger has wrong parameters, this will be corrected on task resume/unpause.
}
}
} else if (schedulingState == TaskSchedulingStateType.READY) {
Trigger triggerToBe;
try {
triggerToBe = QuartzUtil.createTriggerForTask(task);
} catch (ParseException e) {
String message2 = "Cannot create a trigger for a task " + this + " because of a cron expression parsing exception";
LoggingUtils.logUnexpectedException(LOGGER, message2, e);
result.recordFatalError(message2, e);
// TODO: implement error handling correctly
throw new SystemException("Cannot a trigger for a task because of a cron expression parsing exception", e);
}
if (triggerToBe == null) {
if (standardTriggerExists) {
// TODO what about non-standard triggers?
// These may be legal here (e.g. for a manually-run recurring task waiting to get a chance to run)
String m1 = "Removing standard Quartz trigger for RUNNABLE task that should not have it; task = " + task;
message.append("[").append(m1).append("] ");
LOGGER.trace(" - " + m1);
scheduler.unscheduleJob(TriggerKey.triggerKey(oid));
changed = true;
}
} else {
// if the trigger should exist and it does not...
if (!standardTriggerExists) {
String m1 = "Creating standard trigger for a RUNNABLE task " + task;
LOGGER.trace(" - " + m1);
message.append("[").append(m1).append("] ");
scheduler.scheduleJob(triggerToBe);
changed = true;
} else {
// we have to compare trigger parameters with the task's ones
Trigger triggerAsIs = scheduler.getTrigger(standardTriggerKey);
if (task.isRecreateQuartzTrigger() || QuartzUtil.triggersDiffer(triggerAsIs, triggerToBe)) {
String m1 = "Existing trigger has incompatible parameters or was explicitly requested to be recreated; recreating it. Task = " + task;
LOGGER.trace(" - " + m1);
message.append("[").append(m1).append("] ");
scheduler.rescheduleJob(standardTriggerKey, triggerToBe);
changed = true;
} else {
String m1 = "Existing trigger is OK, leaving it as is; task = " + task;
LOGGER.trace(" - " + m1);
message.append("[").append(m1).append("] ");
Trigger.TriggerState state = scheduler.getTriggerState(standardTriggerKey);
if (state == Trigger.TriggerState.PAUSED) {
String m2 = "However, the trigger is paused, resuming it; task = " + task;
LOGGER.trace(" - " + m2);
message.append("[").append(m2).append("] ");
scheduler.resumeTrigger(standardTriggerKey);
changed = true;
}
}
}
}
}
} catch (Exception e) {
String message2 = "Cannot synchronize repository/Quartz Job Store information for task " + task;
LoggingUtils.logUnexpectedException(LOGGER, message2, e);
result.recordFatalError(message2, e);
} finally {
if (result.isUnknown()) {
result.computeStatus();
result.recordStatus(result.getStatus(), message.toString());
}
}
LOGGER.trace("synchronizeTask finishing (changed: {}) for {}", changed, task);
return changed;
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.TaskExecutionStateType.RUNNABLE in project midpoint by Evolveum.
the class AbstractRepositorySearchAction method execute.
@Override
public void execute() throws Exception {
OperationResult result = new OperationResult(getOperationName());
OperationStatus operation = new OperationStatus(context, result);
// "+ 2" will be used for consumer and progress reporter
ExecutorService executor = Executors.newFixedThreadPool(options.getMultiThread() + 2);
BlockingQueue<ObjectType> queue = new LinkedBlockingQueue<>(QUEUE_CAPACITY_PER_THREAD * options.getMultiThread());
List<SearchProducerWorker> producers = createProducers(queue, operation);
log.info("Starting " + getOperationShortName());
operation.start();
// execute as many producers as there are threads for them
for (int i = 0; i < producers.size() && i < options.getMultiThread(); i++) {
executor.execute(producers.get(i));
}
Thread.sleep(CONSUMERS_WAIT_FOR_START);
executor.execute(new ProgressReporterWorker<>(context, options, queue, operation));
Runnable consumer = createConsumer(queue, operation);
executor.execute(consumer);
// execute rest of the producers
for (int i = options.getMultiThread(); i < producers.size(); i++) {
executor.execute(producers.get(i));
}
executor.shutdown();
boolean awaitResult = executor.awaitTermination(NinjaUtils.WAIT_FOR_EXECUTOR_FINISH, TimeUnit.DAYS);
if (!awaitResult) {
log.error("Executor did not finish before timeout");
}
handleResultOnFinish(operation, "Finished " + getOperationShortName());
}
Aggregations