jdbc-protolib/src/main/java/com/streamsets/pipeline/lib/jdbc/multithread/util/TopologicalSorter.java
public SortedSet<V> sort() {
    Utils.checkState(!new CycleDetector<>(directedGraph).isGraphCyclic(), "Cycles found in the graph");
    final Map<V, Integer> vertexToSortedNumber = new HashMap<>();
    Map<V, Integer> inEdgesCount = new TreeMap<>();

    SortedSet<V> sortedSet = new TreeSet<>((o1, o2) -> {
      Integer sortedNumber1 = vertexToSortedNumber.get(o1);
      Integer sortedNumber2 = vertexToSortedNumber.get(o2);
      if (sortedNumber1.intValue() == sortedNumber2.intValue()) {
        //If there is no tie comparator and there is a tie, arrange o1 before o2.
        return (tieComparator != null)? tieComparator.compare(o1, o2) : -1;
      }
      return sortedNumber1.compareTo(sortedNumber2);
    });

    final AtomicInteger startNumber = new AtomicInteger(1);

    directedGraph.vertices().forEach(vertex -> {
      Collection<V> inwardVertices = directedGraph.getInwardEdgeVertices(vertex);
      inEdgesCount.put(vertex, inwardVertices.size());
    });

    while (!inEdgesCount.isEmpty()) {
      Set<V> nextVertices = nextVerticesForProcessing(inEdgesCount);
      nextVertices.forEach(vertexForProcessing -> {
        inEdgesCount.remove(vertexForProcessing);
        updateCounts(vertexForProcessing, inEdgesCount);
        vertexToSortedNumber.put(vertexForProcessing, startNumber.getAndIncrement());
      });
    }
    sortedSet.addAll(vertexToSortedNumber.keySet());
    return sortedSet;
  }
public SortedSet<V> sort() {
    Utils.checkState(!new CycleDetector<>(directedGraph).isGraphCyclic(), "Cycles found in the graph");
    final Map<V, Integer> vertexToSortedNumber = new HashMap<>();
    Map<V, Integer> inEdgesCount = new TreeMap<>();

    SortedSet<V> sortedSet = new TreeSet<>((o1, o2) -> {
      Integer sortedNumber1 = vertexToSortedNumber.get(o1);
      Integer sortedNumber2 = vertexToSortedNumber.get(o2);
      if (sortedNumber1.intValue() == sortedNumber2.intValue()) {
        //If there is no tie comparator and there is a tie, arrange o1 before o2.
        return (tieComparator != null)? tieComparator.compare(o1, o2) : -1;
      }
      return sortedNumber1.compareTo(sortedNumber2);
    });

    final AtomicInteger startNumber = new AtomicInteger(1);

    directedGraph.vertices().forEach(vertex -> {
      Collection<V> inwardVertices = directedGraph.getInwardEdgeVertices(vertex);
      inEdgesCount.put(vertex, inwardVertices.size());
    });

    while (!inEdgesCount.isEmpty()) {
      Set<V> nextVertices = nextVerticesForProcessing(inEdgesCount);
      nextVertices.forEach(vertexForProcessing -> {
        inEdgesCount.remove(vertexForProcessing);
        updateCounts(vertexForProcessing, inEdgesCount);
        vertexToSortedNumber.put(vertexForProcessing, startNumber.getAndIncrement());
      });
    }
    sortedSet.addAll(vertexToSortedNumber.keySet());
    return sortedSet;
  }
Sorts the vertices in the topological order using {@link #tieComparator} if needed to break ties.
Throws {@link IllegalStateException} if there is a cycle detected.

@return Topological sorted order for the @{@link DirectedGraph}