use of javax.validation.ValidationException in project apex-core by apache.
the class LogicalPlanModificationTest method testRemoveOperator.
@Test
public void testRemoveOperator() {
GenericTestOperator o1 = dag.addOperator("o1", GenericTestOperator.class);
OperatorMeta o1Meta = dag.getMeta(o1);
GenericTestOperator o12 = dag.addOperator("o12", GenericTestOperator.class);
OperatorMeta o12Meta = dag.getMeta(o12);
GenericTestOperator o2 = dag.addOperator("o2", GenericTestOperator.class);
OperatorMeta o2Meta = dag.getMeta(o2);
GenericTestOperator o3 = dag.addOperator("o3", GenericTestOperator.class);
OperatorMeta o3Meta = dag.getMeta(o3);
LogicalPlan.StreamMeta s1 = dag.addStream("o1.outport1", o1.outport1, o2.inport1, o12.inport1);
LogicalPlan.StreamMeta s2 = dag.addStream("o2.outport1", o2.outport1, o3.inport1);
TestPlanContext ctx = new TestPlanContext();
dag.setAttribute(OperatorContext.STORAGE_AGENT, ctx);
PhysicalPlan plan = new PhysicalPlan(dag, ctx);
ctx.deploy.clear();
ctx.undeploy.clear();
Assert.assertEquals("containers " + plan.getContainers(), 4, plan.getContainers().size());
Assert.assertEquals("physical operators " + plan.getAllOperators(), 4, plan.getAllOperators().size());
Assert.assertEquals("sinks s1 " + s1.getSinks(), 2, s1.getSinks().size());
List<PTOperator> o2PhysicalOpers = plan.getOperators(o2Meta);
Assert.assertEquals("instances " + o2Meta, 1, o2PhysicalOpers.size());
PlanModifier pm = new PlanModifier(plan);
try {
pm.removeOperator(o2Meta.getName());
Assert.fail("validation error (connected output stream) expected");
} catch (ValidationException ve) {
// all good
}
// remove output stream required before removing operator
pm.removeStream(s2.getName());
pm.removeOperator(o2Meta.getName());
pm.applyChanges(ctx);
Assert.assertEquals("sinks s1 " + s1.getSinks(), 1, s1.getSinks().size());
Assert.assertTrue("undeploy " + ctx.undeploy, ctx.undeploy.containsAll(o2PhysicalOpers));
Assert.assertTrue("deploy " + ctx.deploy, !ctx.deploy.containsAll(o2PhysicalOpers));
Assert.assertEquals("streams " + dag.getAllStreams(), 1, dag.getAllStreams().size());
Assert.assertEquals("operators " + dag.getAllOperators(), 3, dag.getAllOperators().size());
Assert.assertTrue("operators " + dag.getAllOperators(), dag.getAllOperators().containsAll(Sets.newHashSet(o1Meta, o3Meta)));
try {
plan.getOperators(o2Meta);
Assert.fail("removed from physical plan: " + o2Meta);
} catch (Exception e) {
// all good
}
Assert.assertEquals("containers " + plan.getContainers(), 3, plan.getContainers().size());
Assert.assertEquals("physical operators " + plan.getAllOperators(), 3, plan.getAllOperators().size());
Assert.assertEquals("removed containers " + ctx.releaseContainers, 1, ctx.releaseContainers.size());
try {
pm.removeOperator(o12Meta.getName());
Assert.fail("cannot remove operator prior to removing input stream");
} catch (ValidationException ve) {
Assert.assertTrue("" + ve.getMessage(), ve.getMessage().matches(".*Operator o12 connected to input streams.*"));
}
pm.removeStream(s1.getName());
pm.removeOperator(o12Meta.getName());
}
use of javax.validation.ValidationException in project apex-core by apache.
the class PlanModifier method addStream.
/**
* Add stream to logical plan. If a stream with same name and source already
* exists, the new downstream operator will be attached to it.
*
* @param streamName
* @param sourceOperName
* @param sourcePortName
* @param targetOperName
* @param targetPortName
*/
public void addStream(String streamName, String sourceOperName, String sourcePortName, String targetOperName, String targetPortName) {
OperatorMeta om = logicalPlan.getOperatorMeta(sourceOperName);
if (om == null) {
throw new ValidationException("Invalid operator name " + sourceOperName);
}
Operators.PortMappingDescriptor portMap = new Operators.PortMappingDescriptor();
Operators.describe(om.getOperator(), portMap);
PortContextPair<OutputPort<?>> sourcePort = portMap.outputPorts.get(sourcePortName);
if (sourcePort == null) {
throw new AssertionError(String.format("Invalid port %s (%s)", sourcePortName, om));
}
addStream(streamName, sourcePort.component, getInputPort(targetOperName, targetPortName));
}
use of javax.validation.ValidationException in project apex-core by apache.
the class LogicalPlan method validateAffinityRules.
/**
* validation for affinity rules validates following:
* 1. The operator names specified in affinity rule are part of the dag
* 2. Affinity rules do not conflict with anti-affinity rules directly or indirectly
* 3. Anti-affinity rules do not conflict with Stream Locality
* 4. Anti-affinity rules do not conflict with host-locality attribute
* 5. Affinity rule between non stream operators does not have Thread_Local locality
* 6. Affinity rules do not conflict with host-locality attribute
*/
private void validateAffinityRules() {
AffinityRulesSet affinityRuleSet = getAttributes().get(DAGContext.AFFINITY_RULES_SET);
if (affinityRuleSet == null || affinityRuleSet.getAffinityRules() == null) {
return;
}
Collection<AffinityRule> affinityRules = affinityRuleSet.getAffinityRules();
HashMap<String, Set<String>> containerAffinities = new HashMap<>();
HashMap<String, Set<String>> nodeAffinities = new HashMap<>();
HashMap<String, String> hostNamesMapping = new HashMap<>();
HashMap<OperatorPair, AffinityRule> affinities = new HashMap<>();
HashMap<OperatorPair, AffinityRule> antiAffinities = new HashMap<>();
HashMap<OperatorPair, AffinityRule> threadLocalAffinities = new HashMap<>();
List<String> operatorNames = new ArrayList<>();
for (OperatorMeta operator : getAllOperators()) {
operatorNames.add(operator.getName());
Set<String> containerSet = new HashSet<>();
containerSet.add(operator.getName());
containerAffinities.put(operator.getName(), containerSet);
Set<String> nodeSet = new HashSet<>();
nodeSet.add(operator.getName());
nodeAffinities.put(operator.getName(), nodeSet);
if (operator.getAttributes().get(OperatorContext.LOCALITY_HOST) != null) {
hostNamesMapping.put(operator.getName(), operator.getAttributes().get(OperatorContext.LOCALITY_HOST));
}
}
// Identify operators set as Regex and add to list
for (AffinityRule rule : affinityRules) {
if (rule.getOperatorRegex() != null) {
convertRegexToList(operatorNames, rule);
}
}
// Convert operators with list of operator to rules with operator pairs for validation
for (AffinityRule rule : affinityRules) {
if (rule.getOperatorsList() != null) {
List<String> list = rule.getOperatorsList();
for (int i = 0; i < list.size(); i++) {
for (int j = i + 1; j < list.size(); j++) {
OperatorPair pair = new OperatorPair(list.get(i), list.get(j));
if (rule.getType() == com.datatorrent.api.AffinityRule.Type.AFFINITY) {
addToMap(affinities, rule, pair);
} else {
addToMap(antiAffinities, rule, pair);
}
}
}
}
}
for (Entry<OperatorPair, AffinityRule> ruleEntry : affinities.entrySet()) {
OperatorPair pair = ruleEntry.getKey();
AffinityRule rule = ruleEntry.getValue();
if (hostNamesMapping.containsKey(pair.first) && hostNamesMapping.containsKey(pair.second) && !hostNamesMapping.get(pair.first).equals(hostNamesMapping.get(pair.second))) {
throw new ValidationException(String.format("Host Locality for operators: %s(host: %s) & %s(host: %s) conflicts with affinity rules", pair.first, hostNamesMapping.get(pair.first), pair.second, hostNamesMapping.get(pair.second)));
}
if (rule.getLocality() == Locality.THREAD_LOCAL) {
addToMap(threadLocalAffinities, rule, pair);
} else if (rule.getLocality() == Locality.CONTAINER_LOCAL) {
// Combine the sets
combineSets(containerAffinities, pair);
// Also update node list
combineSets(nodeAffinities, pair);
} else if (rule.getLocality() == Locality.NODE_LOCAL) {
combineSets(nodeAffinities, pair);
}
}
for (StreamMeta stream : getAllStreams()) {
String source = stream.source.getOperatorMeta().getName();
for (InputPortMeta sink : stream.sinks) {
String sinkOperator = sink.getOperatorMeta().getName();
OperatorPair pair = new OperatorPair(source, sinkOperator);
if (stream.getLocality() != null && stream.getLocality().ordinal() <= Locality.NODE_LOCAL.ordinal() && hostNamesMapping.containsKey(pair.first) && hostNamesMapping.containsKey(pair.second) && !hostNamesMapping.get(pair.first).equals(hostNamesMapping.get(pair.second))) {
throw new ValidationException(String.format("Host Locality for operators: %s(host: %s) & %s(host: %s) conflicts with stream locality", pair.first, hostNamesMapping.get(pair.first), pair.second, hostNamesMapping.get(pair.second)));
}
if (stream.locality == Locality.CONTAINER_LOCAL) {
combineSets(containerAffinities, pair);
combineSets(nodeAffinities, pair);
} else if (stream.locality == Locality.NODE_LOCAL) {
combineSets(nodeAffinities, pair);
}
if (affinities.containsKey(pair)) {
// Choose the lower bound on locality
AffinityRule rule = affinities.get(pair);
if (rule.getLocality() == Locality.THREAD_LOCAL) {
stream.setLocality(rule.getLocality());
threadLocalAffinities.remove(rule);
affinityRules.remove(rule);
}
if (stream.locality != null && rule.getLocality().ordinal() > stream.getLocality().ordinal()) {
// Remove the affinity rule from attributes, as it is redundant
affinityRules.remove(rule);
}
}
}
}
// Validate that all Thread local affinities were for stream connected operators
if (!threadLocalAffinities.isEmpty()) {
OperatorPair pair = threadLocalAffinities.keySet().iterator().next();
throw new ValidationException(String.format("Affinity rule specified THREAD_LOCAL affinity for operators %s & %s which are not connected by stream", pair.first, pair.second));
}
for (Entry<OperatorPair, AffinityRule> ruleEntry : antiAffinities.entrySet()) {
OperatorPair pair = ruleEntry.getKey();
AffinityRule rule = ruleEntry.getValue();
if (pair.first.equals(pair.second)) {
continue;
}
if (rule.getLocality() == Locality.CONTAINER_LOCAL) {
if (containerAffinities.get(pair.first).contains(pair.second)) {
throw new ValidationException(String.format("Anti Affinity rule for operators %s & %s conflicts with affinity rules or Stream locality", pair.first, pair.second));
}
} else if (rule.getLocality() == Locality.NODE_LOCAL) {
if (nodeAffinities.get(pair.first).contains(pair.second)) {
throw new ValidationException(String.format("Anti Affinity rule for operators %s & %s conflicts with affinity rules or Stream locality", pair.first, pair.second));
}
// Check host locality for both operators
// Check host attribute for all operators in node local set for both
// anti-affinity operators
String firstOperatorLocality = getHostLocality(nodeAffinities, pair.first, hostNamesMapping);
String secondOperatorLocality = getHostLocality(nodeAffinities, pair.second, hostNamesMapping);
if (firstOperatorLocality != null && secondOperatorLocality != null && firstOperatorLocality == secondOperatorLocality) {
throw new ValidationException(String.format("Host Locality for operators: %s(host: %s) & %s(host: %s) conflict with anti-affinity rules", pair.first, firstOperatorLocality, pair.second, secondOperatorLocality));
}
}
}
}
use of javax.validation.ValidationException in project apex-core by apache.
the class LogicalPlan method validateThreadLocal.
/*
* Validates OIO constraints for operators with more than one input streams
* For a node to be OIO,
* 1. all its input streams should be OIO
* 2. all its input streams should have OIO from single source node
*/
private void validateThreadLocal(OperatorMeta om) {
Integer oioRoot = null;
// already visited and validated
if (om.oioRoot != null) {
return;
}
if (om.getOperator() instanceof Operator.DelayOperator) {
String msg = String.format("Locality %s invalid for delay operator %s", Locality.THREAD_LOCAL, om);
throw new ValidationException(msg);
}
for (StreamMeta sm : om.inputStreams.values()) {
// validation fail as each input stream should be OIO
if (sm.locality != Locality.THREAD_LOCAL) {
String msg = String.format("Locality %s invalid for operator %s with multiple input streams as at least one of the input streams is not %s", Locality.THREAD_LOCAL, om, Locality.THREAD_LOCAL);
throw new ValidationException(msg);
}
if (sm.source.operatorMeta.getOperator() instanceof Operator.DelayOperator) {
String msg = String.format("Locality %s invalid for delay operator %s", Locality.THREAD_LOCAL, sm.source.operatorMeta);
throw new ValidationException(msg);
}
// gets oio root for input operator for the stream
Integer oioStreamRoot = getOioRoot(sm.source.operatorMeta);
// validation fail as each input stream should have a common OIO root
if (om.oioRoot != null && oioStreamRoot != om.oioRoot) {
String msg = String.format("Locality %s invalid for operator %s with multiple input streams as at least one of the input streams is not originating from common OIO owner node", Locality.THREAD_LOCAL, om, Locality.THREAD_LOCAL);
throw new ValidationException(msg);
}
// populate oioRoot with root OIO node id for first stream, then validate for subsequent streams to have same root OIO node
if (oioRoot == null) {
oioRoot = oioStreamRoot;
} else if (oioRoot.intValue() != oioStreamRoot.intValue()) {
String msg = String.format("Locality %s invalid for operator %s with multiple input streams as they origin from different owner OIO operators", sm.locality, om);
throw new ValidationException(msg);
}
}
om.oioRoot = oioRoot;
}
use of javax.validation.ValidationException in project apex-core by apache.
the class PlanModifier method setOperatorProperty.
/**
* Set the property on a new operator. Since this is only intended to modify
* previously added operators, no change to the physical plan is required.
*
* @param operatorName
* @param propertyName
* @param propertyValue
*/
public void setOperatorProperty(String operatorName, String propertyName, String propertyValue) {
OperatorMeta om = assertGetOperator(operatorName);
if (physicalPlan != null) {
for (PTOperator oper : physicalPlan.getOperators(om)) {
if (!physicalPlan.newOpers.containsKey(oper)) {
throw new ValidationException("Properties can only be set on new operators: " + om + " " + propertyName + " " + propertyValue);
}
}
}
Map<String, String> props = Collections.singletonMap(propertyName, propertyValue);
LogicalPlanConfiguration.setOperatorProperties(om.getOperator(), props);
}
Aggregations