Program: 4616
Project: 4616
Buggy source:
/** 
 * Split this dag into multiple dags. Each subdag will contain at most a single reduce node.
 * @return list of subdags.
 */
public List<Dag> split(){
  List<Dag> dags=new ArrayList<>();
  Set<String> remainingNodes=new HashSet<>(nodes);
  Set<String> possibleNewSources=Sets.union(sources,connectors.keySet());
  Set<String> possibleNewSinks=Sets.union(sinks,connectors.keySet());
  for (  String reduceNode : reduceNodes) {
    Dag subdag=subsetAround(reduceNode,possibleNewSources,possibleNewSinks);
    remainingNodes.removeAll(subdag.getNodes());
    dags.add(subdag);
  }
  Set<String> remainingSources=new TreeSet<>(Sets.intersection(remainingNodes,possibleNewSources));
  Set<String> processedNodes=new HashSet<>();
  Map<String,Set<String>> nodesAccessibleBySources=new HashMap<>();
  for (  String remainingSource : remainingSources) {
    Dag remainingNodesDag=subsetFrom(remainingSource,possibleNewSinks);
    nodesAccessibleBySources.put(remainingSource,remainingNodesDag.getNodes());
  }
  for (  String remainingSource : remainingSources) {
    if (!processedNodes.add(remainingSource)) {
      continue;
    }
    Set<String> subdag=new HashSet<>(nodesAccessibleBySources.get(remainingSource));
    Set<String> otherSources=Sets.difference(remainingSources,processedNodes);
    boolean nodesAdded;
    do {
      nodesAdded=false;
      for (      String otherSource : otherSources) {
        Set<String> otherAccessibleNodes=nodesAccessibleBySources.get(otherSource);
        if (!Sets.intersection(subdag,otherAccessibleNodes).isEmpty()) {
          if (subdag.addAll(otherAccessibleNodes)) {
            nodesAdded=true;
          }
        }
      }
    }
 while (nodesAdded);
    dags.add(createSubDag(subdag));
    processedNodes.addAll(subdag);
  }
  return dags;
}

Fixed version (ground truth):
/** 
 * Split this dag into multiple dags. Each subdag will contain at most a single reduce node.
 * @return list of subdags.
 */
public List<Dag> split(){
  List<Dag> dags=new ArrayList<>();
  Set<String> remainingNodes=new HashSet<>(nodes);
  Set<String> possibleNewSources=Sets.union(sources,connectors.keySet());
  Set<String> possibleNewSinks=Sets.union(sinks,connectors.keySet());
  for (  String reduceNode : reduceNodes) {
    Dag subdag=subsetAround(reduceNode,possibleNewSources,possibleNewSinks);
    Set<String> subdagConnectorSinks=Sets.intersection(subdag.getSinks(),connectors.keySet());
    remainingNodes.removeAll(Sets.difference(subdag.getNodes(),subdagConnectorSinks));
    dags.add(subdag);
  }
  Set<String> remainingSources=new TreeSet<>(Sets.intersection(remainingNodes,possibleNewSources));
  Map<String,Dag> remainingDags=new HashMap<>();
  for (  String remainingSource : remainingSources) {
    remainingDags.put(remainingSource,subsetFrom(remainingSource,possibleNewSinks));
  }
  Set<String> processedSources=new HashSet<>();
  for (  String remainingSource : remainingSources) {
    if (!processedSources.add(remainingSource)) {
      continue;
    }
    Dag subdag=remainingDags.get(remainingSource);
    Set<String> subdagNodes=new HashSet<>(subdag.getNodes());
    Set<String> nonSourceNodes=Sets.difference(subdagNodes,subdag.getSources());
    Set<String> otherSources=Sets.difference(remainingSources,processedSources);
    boolean nodesAdded;
    do {
      nodesAdded=false;
      for (      String otherSource : otherSources) {
        Dag otherSubdag=remainingDags.get(otherSource);
        Set<String> otherNonSourceNodes=Sets.difference(otherSubdag.getNodes(),otherSubdag.getSources());
        if (!Sets.intersection(nonSourceNodes,otherNonSourceNodes).isEmpty()) {
          if (subdagNodes.addAll(otherSubdag.getNodes())) {
            nodesAdded=true;
          }
        }
      }
    }
 while (nodesAdded);
    Dag mergedSubdag=createSubDag(subdagNodes);
    dags.add(mergedSubdag);
    processedSources.addAll(mergedSubdag.getSources());
  }
  return dags;
}