|
19 | 19 |
|
20 | 20 | import static com.google.common.base.Preconditions.checkNotNull;
|
21 | 21 |
|
22 |
| -import org.apache.dolphinscheduler.common.graph.DAG; |
23 | 22 | import org.apache.dolphinscheduler.dao.entity.TaskDefinition;
|
24 | 23 | import org.apache.dolphinscheduler.dao.entity.WorkflowTaskRelation;
|
25 | 24 |
|
| 25 | +import java.util.ArrayDeque; |
26 | 26 | import java.util.ArrayList;
|
27 | 27 | import java.util.HashMap;
|
28 | 28 | import java.util.HashSet;
|
29 | 29 | import java.util.List;
|
30 | 30 | import java.util.Map;
|
| 31 | +import java.util.Queue; |
31 | 32 | import java.util.Set;
|
32 | 33 | import java.util.function.Function;
|
33 | 34 | import java.util.stream.Collectors;
|
@@ -60,18 +61,58 @@ public WorkflowGraph(List<WorkflowTaskRelation> workflowTaskRelations, List<Task
|
60 | 61 | }
|
61 | 62 |
|
62 | 63 | private void checkIfDAG(List<WorkflowTaskRelation> workflowTaskRelations, List<TaskDefinition> taskDefinitions) {
|
63 |
| - DAG<Long, TaskDefinition, WorkflowTaskRelation> graph = new DAG<>(); |
64 |
| - // Fill the vertices |
| 64 | + // If topology-sort-result`s size less than taskDefinitions`s size, then not a DAG |
| 65 | + Map<Long, List<Long>> preTaskCodeMap = workflowTaskRelations |
| 66 | + .stream() |
| 67 | + .filter(relation -> relation.getPreTaskCode() != 0) |
| 68 | + .collect(Collectors.groupingBy(WorkflowTaskRelation::getPostTaskCode, |
| 69 | + Collectors.mapping(WorkflowTaskRelation::getPreTaskCode, Collectors.toList()))); |
| 70 | + Map<Long, List<Long>> postTaskCodeMap = workflowTaskRelations |
| 71 | + .stream() |
| 72 | + .collect(Collectors.groupingBy(WorkflowTaskRelation::getPreTaskCode, |
| 73 | + Collectors.mapping(WorkflowTaskRelation::getPostTaskCode, Collectors.toList()))); |
| 74 | + |
| 75 | + // build in-degree count |
| 76 | + Map<Long, Integer> inDegreeCount = new HashMap<>(); |
65 | 77 | for (TaskDefinition taskDefinition : taskDefinitions) {
|
66 |
| - graph.addNode(taskDefinition.getCode(), taskDefinition); |
| 78 | + List<Long> preTasks = preTaskCodeMap.get(taskDefinition.getCode()); |
| 79 | + if (preTasks == null) { |
| 80 | + inDegreeCount.put(taskDefinition.getCode(), 0); |
| 81 | + } else { |
| 82 | + inDegreeCount.put(taskDefinition.getCode(), preTasks.size()); |
| 83 | + } |
| 84 | + } |
| 85 | + |
| 86 | + // Adds the task with zero-in-degree to the queue |
| 87 | + Set<Long> visitTable = new HashSet<>(); |
| 88 | + Queue<Long> queue = new ArrayDeque<>(); |
| 89 | + for (Map.Entry<Long, Integer> entry : inDegreeCount.entrySet()) { |
| 90 | + if (entry.getValue() == 0 && visitTable.add(entry.getKey())) { |
| 91 | + queue.offer(entry.getKey()); |
| 92 | + } |
67 | 93 | }
|
68 |
| - // Fill edge relations |
69 |
| - for (WorkflowTaskRelation relation : workflowTaskRelations) { |
70 |
| - long preTaskCode = relation.getPreTaskCode(); |
71 |
| - // When exist a ring cycle, then not a DAG. |
72 |
| - if (preTaskCode != 0 && !graph.addEdge(preTaskCode, relation.getPostTaskCode())) { |
73 |
| - throw new IllegalArgumentException("The workflow graph is not a DAG"); |
| 94 | + |
| 95 | + // topology sort |
| 96 | + Set<Long> resultTable = new HashSet<>(); |
| 97 | + while (!queue.isEmpty()) { |
| 98 | + Long taskCode = queue.poll(); |
| 99 | + resultTable.add(taskCode); |
| 100 | + |
| 101 | + List<Long> postCodes = postTaskCodeMap.get(taskCode); |
| 102 | + if (postCodes == null) { |
| 103 | + continue; |
74 | 104 | }
|
| 105 | + for (Long postCode : postCodes) { |
| 106 | + inDegreeCount.put(postCode, inDegreeCount.get(postCode) - 1); |
| 107 | + |
| 108 | + if (inDegreeCount.get(postCode) == 0) { |
| 109 | + queue.offer(postCode); |
| 110 | + } |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + if (resultTable.size() < taskDefinitions.size()) { |
| 115 | + throw new IllegalArgumentException("The workflow task relation is not a DAG"); |
75 | 116 | }
|
76 | 117 | }
|
77 | 118 |
|
|
0 commit comments