Search in sources :

Example 6 with AffinityRulesSet

use of com.datatorrent.api.AffinityRulesSet 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));
            }
        }
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) AffinityRulesSet(com.datatorrent.api.AffinityRulesSet) LinkedHashSet(java.util.LinkedHashSet) ValidationException(javax.validation.ValidationException) AffinityRule(com.datatorrent.api.AffinityRule) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ArrayList(java.util.ArrayList) AffinityRulesSet(com.datatorrent.api.AffinityRulesSet) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Aggregations

AffinityRulesSet (com.datatorrent.api.AffinityRulesSet)6 AffinityRule (com.datatorrent.api.AffinityRule)5 ArrayList (java.util.ArrayList)5 GenericTestOperator (com.datatorrent.stram.engine.GenericTestOperator)4 Test (org.junit.Test)4 ContainerStartRequest (com.datatorrent.stram.StreamingContainerAgent.ContainerStartRequest)2 TestGeneratorInputOperator (com.datatorrent.stram.engine.TestGeneratorInputOperator)2 LogicalPlan (com.datatorrent.stram.plan.logical.LogicalPlan)2 PTContainer (com.datatorrent.stram.plan.physical.PTContainer)2 PTOperator (com.datatorrent.stram.plan.physical.PTOperator)2 MemoryStorageAgent (com.datatorrent.stram.support.StramTestSupport.MemoryStorageAgent)2 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 LinkedHashMap (java.util.LinkedHashMap)2 ValidationException (javax.validation.ValidationException)2 NodeReport (org.apache.hadoop.yarn.api.records.NodeReport)2 Operator (com.datatorrent.api.Operator)1 Checkpoint (com.datatorrent.stram.api.Checkpoint)1 TestPlanContext (com.datatorrent.stram.plan.TestPlanContext)1 StreamMeta (com.datatorrent.stram.plan.logical.LogicalPlan.StreamMeta)1