use of org.ow2.proactive.scheduler.common.job.factories.FlowError in project scheduling by ow2-proactive.
the class FlowChecker method checkBlocks.
/**
* Checks all declared blocks are correct
*
* @param job the job to check
* @return a list of valid blocks
* @throws FlowError
*/
private void checkBlocks() throws FlowError {
Set<String> done = new HashSet<>();
// detect blocks
for (TaskTree tt : roots) {
Stack<TaskTree> env = new Stack<>();
Stack<TaskTree> join = new Stack<>();
dfsBlocks(tt, done, env, join);
if (env.size() > 0) {
throw new FlowError("Unmatched start block", FlowErrorType.BLOCK, env.firstElement().element.getName());
}
}
// check blocks
for (Block b : blocks) {
checkBlockDown(b.end, b.start);
checkBlockUp(b.start, b.end);
}
}
use of org.ow2.proactive.scheduler.common.job.factories.FlowError in project scheduling by ow2-proactive.
the class FlowChecker method checkReplicate.
/**
* Checks the provided taskflow against rules specific to the REPLICATE control flow action
*
* @param job the job to check
* @throws FlowError
*/
private void checkReplicate() throws FlowError {
for (TaskTree tree : tasksFlat) {
if (tree.element.getFlowScript() != null && tree.element.getFlowScript().getActionType().equals(FlowActionType.REPLICATE.toString())) {
for (TaskTree child : tree.children) {
if (child.parents.size() != 1) {
throw new FlowError("The Target of a REPLICATE must have only one dependency", FlowErrorType.REPLICATE, child.element.getName());
}
if (child.element.getFlowBlock().equals(FlowBlock.END)) {
throw new FlowError("The target of a REPLICATE cannot be the end of a task block", FlowErrorType.REPLICATE, child.element.getName());
}
Block block = null;
for (Block b : this.blocks) {
if (b.start.element.getName().equals(child.element.getName())) {
block = b;
}
}
TaskTree endBlock = null;
if (block != null) {
endBlock = block.end;
} else {
endBlock = child;
}
if (endBlock.children.size() < 1) {
throw new FlowError("No merge point for REPLICATE block", FlowErrorType.REPLICATE, endBlock.element.getName());
}
if (endBlock.element.getFlowScript() != null) {
if (endBlock.element.getFlowScript().getActionType().equals(FlowActionType.REPLICATE.toString()) || endBlock.element.getFlowScript().getActionType().equals(FlowActionType.IF.toString())) {
throw new FlowError("Last action of a REPLICATE block cannot perform IF or REPLICATE action", FlowErrorType.REPLICATE, endBlock.element.getName());
}
}
}
}
}
}
use of org.ow2.proactive.scheduler.common.job.factories.FlowError in project scheduling by ow2-proactive.
the class FlowChecker method checkReachable.
/**
* Check whether or not every tasks of the given tasks flow can be reached.
* Happens with dependency cycles.
*
* @return FlowError
*/
private void checkReachable() throws FlowError {
HashSet<Task> tasks = new HashSet<>();
HashSet<Task> reached = new HashSet<>();
for (Task t : job.getTasks()) {
if (t.getDependencesList() == null) {
reached.add(t);
} else {
tasks.add(t);
}
}
boolean change;
do {
change = false;
Iterator<Task> it = tasks.iterator();
while (it.hasNext()) {
Task t = it.next();
if (reached.containsAll(t.getDependencesList())) {
it.remove();
reached.add(t);
change = true;
}
}
} while (change);
if (reached.size() != job.getTasks().size()) {
for (Task t : job.getTasks()) {
if (!reached.contains(t)) {
throw new FlowError("Unreachable task", FlowErrorType.UNREACHABLE, t.getName());
}
}
}
}
use of org.ow2.proactive.scheduler.common.job.factories.FlowError in project scheduling by ow2-proactive.
the class FlowChecker method checkIf.
/**
* Checks the provided taskflow against rules specific to the IF control flow action
*
* @throws FlowError
*/
private void checkIf() throws FlowError {
for (TaskTree tree : tasksFlat) {
if (tree.element.getFlowScript() != null && tree.element.getFlowScript().getActionType().equals(FlowActionType.IF.toString())) {
TaskTree targetIf = findTask(tree.element.getFlowScript().getActionTarget());
TaskTree targetElse = findTask(tree.element.getFlowScript().getActionTargetElse());
TaskTree targetJoin = findTask(tree.element.getFlowScript().getActionContinuation());
if (targetIf == null) {
throw new FlowError("IF action has no target", FlowErrorType.IF, tree.element.getName());
}
if (targetElse == null) {
throw new FlowError("IF action has no ELSE target", FlowErrorType.IF, tree.element.getName());
}
if (targetIf.equals(targetElse)) {
throw new FlowError("IF and ELSE targets are the same", FlowErrorType.IF, targetIf.element.getName());
}
// No join : IF and ELSE are /loose/ blocks
if (targetJoin == null) {
if (targetIf.parents.size() > 0) {
throw new FlowError("IF target task cannot have dependencies", FlowErrorType.IF, targetIf.element.getName());
}
if (targetElse.parents.size() > 0) {
throw new FlowError("IF target task ELSE cannot have dependencies", FlowErrorType.IF, targetElse.element.getName());
}
List<TaskTree> targets = new ArrayList<>(2);
targets.add(targetIf);
targets.add(targetElse);
for (TaskTree target : targets) {
Map<String, TaskTree> ifTasks = new HashMap<>();
Stack<TaskTree> stack = new Stack<>();
stack.push(target);
while (stack.size() > 0) {
TaskTree cur = stack.pop();
if (ifTasks.containsKey(cur.element.getName())) {
continue;
} else {
ifTasks.put(cur.element.getName(), cur);
for (TaskTree t : cur.children) {
stack.push(t);
}
for (TaskTree t : cur.targets) {
stack.push(t);
}
}
}
for (TaskTree t : ifTasks.values()) {
if (t.element.getName().equals(target.element.getName())) {
continue;
}
try {
checkBlockUp(target, t);
} catch (FlowError e) {
throw new FlowError("IF block at " + target.element.getName() + " has external dependencies", FlowErrorType.IF, e.getTask());
}
}
}
} else // join : IF and ELSE are blocks
{
Block ifBlock = null;
Block elseBlock = null;
// detect blocks
for (Block b : this.blocks) {
if (b.start.element.getName().equals(targetIf.element.getName())) {
ifBlock = b;
}
if (b.start.element.getName().equals(targetElse.element.getName())) {
elseBlock = b;
}
}
// if is a block or a single task
if (ifBlock == null) {
if (!(targetIf.children.size() > 0 || targetIf.targets.size() > 0)) {
ifBlock = new Block(targetIf, targetIf);
} else {
throw new FlowError("IF action target is not a Task Block", FlowErrorType.IF, targetIf.element.getName());
}
}
// else is a block or a single task
if (elseBlock == null) {
if (!(targetElse.children.size() > 0 || targetElse.targets.size() > 0)) {
elseBlock = new Block(targetElse, targetElse);
} else {
throw new FlowError("IF action ELSE target is not a Task Block", FlowErrorType.IF, targetElse.element.getName());
}
}
// join joins only one if
if (targetJoin != null) {
for (TaskTree join : targetJoin.joins) {
String jN = join.element.getName();
if (!(jN.equals(ifBlock.end.element.getName()) || jN.equals(elseBlock.end.element.getName()))) {
throw new FlowError("JOIN task merges multiple IF actions", FlowErrorType.IF, targetJoin.element.getName());
}
}
}
if (ifBlock.start.parents.size() > 0) {
throw new FlowError("IF task block cannot have dependencies", FlowErrorType.IF, ifBlock.start.element.getName());
}
if (ifBlock.end.children.size() > 0) {
throw new FlowError("IF task block cannot have children", FlowErrorType.IF, ifBlock.end.element.getName());
}
if (elseBlock.start.parents.size() > 0) {
throw new FlowError("ELSE task block cannot have dependencies", FlowErrorType.IF, elseBlock.start.element.getName());
}
if (elseBlock.end.children.size() > 0) {
throw new FlowError("ELSE task block cannot have children", FlowErrorType.IF, elseBlock.end.element.getName());
}
if (targetJoin.parents.size() > 0) {
throw new FlowError("JOIN task cannot have dependencies", FlowErrorType.IF, targetJoin.element.getName());
}
}
}
}
}
use of org.ow2.proactive.scheduler.common.job.factories.FlowError in project scheduling by ow2-proactive.
the class FlowChecker method dfsBlocks.
/**
* Find matching start and end blocks in a task tree using depth first search
*
* @param tree task tree to search
* @param done already treated tasks; multiple dependencies: multiple passes
* @param env accumulates the previously read start tags
* @param join stacks previous join targets
* @throws FlowError
*/
private void dfsBlocks(TaskTree tree, Set<String> done, Stack<TaskTree> env, Stack<TaskTree> join) throws FlowError {
if (tree.joins.size() > 0 && !tree.joinTrigger) {
return;
}
if (tree.targetOf != null && !done.contains(tree.targetOf.element.getName())) {
return;
}
FlowBlock fb = tree.element.getFlowBlock();
String name = tree.element.getName();
if (done.contains(name)) {
return;
} else {
done.add(name);
}
switch(fb) {
case START:
// push new opening tag in the environment
env.push(tree);
break;
case END:
// close the last opened block
TaskTree start = null;
try {
start = env.pop();
} catch (EmptyStackException e) {
throw new FlowError("Unmatched end block", FlowErrorType.BLOCK, name);
}
Block blk = new Block(start, tree);
blocks.add(blk);
break;
case NONE:
break;
}
List<TaskTree> children = new ArrayList<>();
children.addAll(tree.children);
if (tree.children.size() == 0) {
if (tree.element.getFlowScript() != null && tree.element.getFlowScript().getActionType().equals(FlowActionType.IF.toString())) {
if (tree.targetJoin != null) {
join.add(tree.targetJoin);
}
for (TaskTree t : tree.targets) {
children.add(t);
}
} else if (join.size() > 0) {
TaskTree pop = join.pop();
children.add(pop);
pop.joinTrigger = true;
}
}
// recursive call
for (TaskTree child : children) {
dfsBlocks(child, done, env, join);
}
}
Aggregations