Skip to content

Commit a7adb78

Browse files
authored
Reduce number of calculations when finding a nodes relationships (#882)
1 parent 595395f commit a7adb78

File tree

2 files changed

+47
-46
lines changed

2 files changed

+47
-46
lines changed

src/main/java/io/jenkins/plugins/pipelinegraphview/treescanner/NodeRelationshipFinder.java

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
import io.jenkins.plugins.pipelinegraphview.utils.FlowNodeWrapper;
66
import io.jenkins.plugins.pipelinegraphview.utils.PipelineNodeUtil;
77
import java.util.ArrayDeque;
8-
import java.util.ArrayList;
9-
import java.util.Collections;
8+
import java.util.Collection;
109
import java.util.LinkedHashMap;
1110
import java.util.List;
1211
import java.util.Map;
12+
import java.util.stream.Collectors;
1313
import org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode;
1414
import org.jenkinsci.plugins.workflow.graph.BlockEndNode;
1515
import org.jenkinsci.plugins.workflow.graph.BlockStartNode;
@@ -48,35 +48,39 @@ public NodeRelationshipFinder() {}
4848
* Determines the relationship between FlowNodes {@link FlowNode#getParents()}.
4949
*/
5050
@NonNull
51-
public LinkedHashMap<String, NodeRelationship> getNodeRelationships(
52-
@NonNull LinkedHashMap<String, FlowNode> nodeMap) {
51+
public Map<String, NodeRelationship> getNodeRelationships(@NonNull Collection<FlowNode> nodes) {
5352
if (isDebugEnabled) {
54-
logger.debug("Original Ids: {}", String.join(", ", nodeMap.keySet()));
53+
logger.atDebug()
54+
.addArgument(() -> nodes.stream().map(FlowNode::getId).collect(Collectors.joining(", ")))
55+
.log("Original Ids: {}");
5556
}
56-
// This is important, determining the the relationships depends on the order of
57+
// This is important, determining the relationships depends on the order of
5758
// iteration.
5859
// If there was a method to tell if a node was a parallel block this might be
5960
// less of an issue.
60-
List<String> sortedIds = new ArrayList<>(nodeMap.keySet());
61-
Collections.sort(sortedIds, new FlowNodeWrapper.NodeIdComparator().reversed());
61+
List<FlowNode> sorted = nodes.stream()
62+
.sorted(new FlowNodeWrapper.FlowNodeComparator().reversed())
63+
.toList();
6264
if (isDebugEnabled) {
63-
logger.debug("Sorted Ids: {}", String.join(", ", sortedIds));
65+
logger.atDebug()
66+
.addArgument(() -> sorted.stream().map(FlowNode::getId).collect(Collectors.joining(", ")))
67+
.log("Sorted Ids: {}");
6468
}
65-
for (String id : sortedIds) {
66-
getRelationshipForNode(nodeMap.get(id));
69+
sorted.forEach(node -> {
70+
getRelationshipForNode(node);
6771
// Add this node to the parents's stack as the last of it's child nodes that
6872
// we have seen.
69-
addSeenNodes(nodeMap.get(id));
70-
}
73+
addSeenNodes(node);
74+
});
7175
return relationships;
7276
}
7377

7478
private void getRelationshipForNode(@NonNull FlowNode node) {
7579
// Assign start node to end node.
76-
if (node instanceof StepAtomNode) {
77-
addStepRelationship((StepAtomNode) node);
78-
} else if (node instanceof BlockEndNode<?>) {
79-
handleBlockEnd((BlockEndNode<?>) node);
80+
if (node instanceof StepAtomNode atomNode) {
81+
addStepRelationship(atomNode);
82+
} else if (node instanceof BlockEndNode<?> endNode) {
83+
handleBlockEnd(endNode);
8084
} else {
8185
handleBlockStart(node);
8286
}
@@ -92,8 +96,8 @@ private void handleBlockStart(@NonNull FlowNode node) {
9296
}
9397

9498
private void addSeenNodes(FlowNode node) {
95-
if (!seenChildNodes.keySet().contains(node.getEnclosingId())) {
96-
seenChildNodes.put(node.getEnclosingId(), new ArrayDeque<FlowNode>());
99+
if (!seenChildNodes.containsKey(node.getEnclosingId())) {
100+
seenChildNodes.put(node.getEnclosingId(), new ArrayDeque<>());
97101
}
98102
if (isDebugEnabled) {
99103
logger.debug("Adding {} to seenChildNodes {}", node.getId(), node.getEnclosingId());
@@ -126,16 +130,15 @@ private FlowNode getAfterNode(FlowNode node) {
126130

127131
@CheckForNull
128132
private BlockStartNode getFirstEnclosingNode(FlowNode node) {
129-
return node.getEnclosingBlocks().isEmpty()
130-
? null
131-
: node.getEnclosingBlocks().get(0);
133+
List<? extends BlockStartNode> enclosingBlocks = node.getEnclosingBlocks();
134+
return enclosingBlocks.isEmpty() ? null : enclosingBlocks.get(0);
132135
}
133136

134137
private ArrayDeque<FlowNode> getProcessedChildren(@CheckForNull FlowNode node) {
135-
if (node != null && seenChildNodes.keySet().contains(node.getId())) {
138+
if (node != null && seenChildNodes.containsKey(node.getId())) {
136139
return seenChildNodes.get(node.getId());
137140
}
138-
return new ArrayDeque<FlowNode>();
141+
return new ArrayDeque<>();
139142
}
140143

141144
private void addStepRelationship(@NonNull StepAtomNode step) {

src/main/java/io/jenkins/plugins/pipelinegraphview/treescanner/PipelineNodeTreeScanner.java

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import io.jenkins.plugins.pipelinegraphview.utils.PipelineNodeUtil;
99
import java.io.IOException;
1010
import java.util.ArrayList;
11-
import java.util.Collections;
11+
import java.util.Collection;
1212
import java.util.LinkedHashMap;
1313
import java.util.List;
1414
import java.util.Map;
@@ -72,9 +72,9 @@ public void build() {
7272
logger.debug("Building graph");
7373
}
7474
if (execution != null) {
75-
LinkedHashMap<String, FlowNode> nodes = getAllNodes();
75+
Collection<FlowNode> nodes = getAllNodes();
7676
NodeRelationshipFinder finder = new NodeRelationshipFinder();
77-
LinkedHashMap<String, NodeRelationship> relationships = finder.getNodeRelationships(nodes);
77+
Map<String, NodeRelationship> relationships = finder.getNodeRelationships(nodes);
7878
GraphBuilder builder = new GraphBuilder(nodes, relationships, this.run, this.execution);
7979
if (isDebugEnabled) {
8080
logger.debug("Original nodes:");
@@ -100,18 +100,17 @@ public void build() {
100100
/**
101101
* Gets all the nodes that are reachable in the graph.
102102
*/
103-
private LinkedHashMap<String, FlowNode> getAllNodes() {
103+
private List<FlowNode> getAllNodes() {
104104
heads = execution.getCurrentHeads();
105105
final DepthFirstScanner scanner = new DepthFirstScanner();
106106
scanner.setup(heads);
107107

108108
// nodes that we've visited
109-
final LinkedHashMap<String, FlowNode> nodeMap = new LinkedHashMap<>();
110-
109+
final List<FlowNode> nodes = new ArrayList<>();
111110
for (FlowNode n : scanner) {
112-
nodeMap.put(n.getId(), n);
111+
nodes.add(n);
113112
}
114-
return nodeMap;
113+
return nodes;
115114
}
116115

117116
@NonNull
@@ -123,7 +122,7 @@ public List<FlowNodeWrapper> getStageSteps(String startNodeId) {
123122
stageSteps.add(wrappedStep);
124123
}
125124
}
126-
Collections.sort(stageSteps, new FlowNodeWrapper.NodeComparator());
125+
stageSteps.sort(new FlowNodeWrapper.NodeComparator());
127126
if (isDebugEnabled) {
128127
logger.debug("Returning {} steps for node '{}'", stageSteps.size(), startNodeId);
129128
}
@@ -142,7 +141,7 @@ public Map<String, List<FlowNodeWrapper>> getAllSteps() {
142141
@NonNull
143142
public List<FlowNodeWrapper> getPipelineNodes() {
144143
List<FlowNodeWrapper> stageNodes = new ArrayList<>(this.stageNodeMap.values());
145-
Collections.sort(stageNodes, new FlowNodeWrapper.NodeComparator());
144+
stageNodes.sort(new FlowNodeWrapper.NodeComparator());
146145
return stageNodes;
147146
}
148147

@@ -157,7 +156,7 @@ public boolean isDeclarative() {
157156
}
158157

159158
private static class GraphBuilder {
160-
private final Map<String, FlowNode> nodeMap;
159+
private final Collection<FlowNode> nodes;
161160
private final Map<String, NodeRelationship> relationships;
162161
private final WorkflowRun run;
163162

@@ -182,11 +181,11 @@ private static class GraphBuilder {
182181
* in the same graph.
183182
*/
184183
public GraphBuilder(
185-
@NonNull Map<String, FlowNode> nodeMap,
184+
Collection<FlowNode> nodes,
186185
@NonNull Map<String, NodeRelationship> relationships,
187186
@NonNull WorkflowRun run,
188187
@NonNull FlowExecution execution) {
189-
this.nodeMap = nodeMap;
188+
this.nodes = nodes;
190189
this.relationships = relationships;
191190
this.run = run;
192191
this.inputAction = run.getAction(InputAction.class);
@@ -195,9 +194,7 @@ public GraphBuilder(
195194
}
196195

197196
protected List<FlowNodeWrapper> getNodes() {
198-
return wrappedNodeMap.entrySet().stream()
199-
.map(entrySet -> entrySet.getValue())
200-
.collect(Collectors.toList());
197+
return new ArrayList<>(wrappedNodeMap.values());
201198
}
202199

203200
/*
@@ -307,11 +304,11 @@ private boolean isStartNode(FlowNodeWrapper n) {
307304
}
308305
Map<String, FlowNodeWrapper> stepMap = this.wrappedNodeMap.entrySet().stream()
309306
.filter(e -> shouldBeInStepMap(e.getValue()))
310-
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
307+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
311308

312309
Map<String, FlowNodeWrapper> stageMap = this.getStageMapping();
313-
List<FlowNodeWrapper> nodeList = new ArrayList<FlowNodeWrapper>(stepMap.values());
314-
Collections.sort(nodeList, new FlowNodeWrapper.NodeComparator());
310+
List<FlowNodeWrapper> nodeList = new ArrayList<>(stepMap.values());
311+
nodeList.sort(new FlowNodeWrapper.NodeComparator());
315312
for (FlowNodeWrapper step : nodeList) {
316313
FlowNodeWrapper firstParent = step.getFirstParent();
317314
// Remap parentage of steps that aren't children of stages (e.g. are in Step
@@ -341,8 +338,9 @@ private boolean isExceptionStep(FlowNodeWrapper n) {
341338
* Builds a graph from the list of nodes and relationships given to the class.
342339
*/
343340
private void buildGraph() {
344-
List<FlowNode> nodeList = new ArrayList<FlowNode>(nodeMap.values());
345-
Collections.sort(nodeList, new FlowNodeWrapper.FlowNodeComparator());
341+
List<FlowNode> nodeList = nodes.stream()
342+
.sorted(new FlowNodeWrapper.FlowNodeComparator())
343+
.toList();
346344
// If the Pipeline ended with an unhandled exception, then we want to catch the
347345
// node which threw it.
348346
BlockEndNode<?> nodeThatThrewException = null;
@@ -404,7 +402,7 @@ private void buildGraph() {
404402
* to the graph, we use the end node that we were given to act as the step
405403
* - this might need additional logic when getting the log for the exception.
406404
*/
407-
if (node instanceof BlockEndNode<?> && nodeMap.values().size() <= 2) {
405+
if (node instanceof BlockEndNode<?> && nodes.size() <= 2) {
408406
if (isDebugEnabled) {
409407
logger.debug("getUnhandledException => Returning node: {}", node.getId());
410408
}

0 commit comments

Comments
 (0)