2424public class PipelineNodeGraphAdapter implements PipelineGraphBuilderApi , PipelineStepBuilderApi {
2525
2626 private static final Logger logger = LoggerFactory .getLogger (PipelineNodeGraphAdapter .class );
27- private boolean isDebugEnabled = logger .isDebugEnabled ();
28- private PipelineNodeTreeScanner treeScanner ;
29- private List <FlowNodeWrapper > pipelineNodesList ;
30- private Map <String , List <FlowNodeWrapper >> stepsMap ;
31- private Map <String , String > nodesToRemap ;
27+ private final boolean isDebugEnabled = logger .isDebugEnabled ();
28+ private final PipelineNodeTreeScanner treeScanner ;
29+ private volatile List <FlowNodeWrapper > pipelineNodesList ;
30+ private volatile Map <String , List <FlowNodeWrapper >> stepsMap ;
31+ private volatile Map <String , String > nodesToRemap ;
3232
3333 public PipelineNodeGraphAdapter (WorkflowRun run ) {
3434 treeScanner = new PipelineNodeTreeScanner (run );
3535 }
3636
37+ private final Object pipelineLock = new Object ();
38+ private final Object stepLock = new Object ();
39+ private final Object remapLock = new Object ();
40+
3741 private Map <String , String > getNodesToRemap (List <FlowNodeWrapper > pipelineNodesList ) {
3842 if (this .nodesToRemap != null ) {
3943 return this .nodesToRemap ;
4044 }
41- // Get a map of nodes to remap. The first id is the node to map from, the second
42- // is the node to
43- // map to.
44- // Most of the logic here is to recreate old behavior - it might not be to
45- // everyone's liking.
46- this .nodesToRemap = new HashMap <String , String >();
47- for (int i = pipelineNodesList .size () - 1 ; i >= 0 ; i --) {
48- FlowNodeWrapper node = pipelineNodesList .get (i );
49- for (FlowNodeWrapper parent : node .getParents ()) {
50- // Parallel Start Nodes that have a Stage with the same name as a parent will be
51- // mapped to that
52- // parent stage
53- // id.
54- if (node .getType () == FlowNodeWrapper .NodeType .PARALLEL_BLOCK
55- && parent .getType () == FlowNodeWrapper .NodeType .STAGE ) {
56- if (isDebugEnabled ) {
57- logger .debug (
58- "getNodesToRemap => Found Parallel block {id: {}, name: {}, type: {}} that has a Stage {id: {}, name: {}, type: {}} as a parent. Adding to remap list." ,
59- node .getId (),
60- node .getDisplayName (),
61- node .getType (),
62- parent .getId (),
63- parent .getDisplayName (),
64- parent .getType ());
45+ synchronized (remapLock ) {
46+ if (this .nodesToRemap != null ) {
47+ return this .nodesToRemap ;
48+ }
49+ // Get a map of nodes to remap. The first id is the node to map from, the second
50+ // is the node to
51+ // map to.
52+ // Most of the logic here is to recreate old behavior - it might not be to
53+ // everyone's liking.
54+ Map <String , String > nodesToRemap = new HashMap <>();
55+ for (int i = pipelineNodesList .size () - 1 ; i >= 0 ; i --) {
56+ FlowNodeWrapper node = pipelineNodesList .get (i );
57+ for (FlowNodeWrapper parent : node .getParents ()) {
58+ // Parallel Start Nodes that have a Stage with the same name as a parent will be
59+ // mapped to that
60+ // parent stage
61+ // id.
62+ if (node .getType () == FlowNodeWrapper .NodeType .PARALLEL_BLOCK
63+ && parent .getType () == FlowNodeWrapper .NodeType .STAGE ) {
64+ if (isDebugEnabled ) {
65+ logger .debug (
66+ "getNodesToRemap => Found Parallel block {id: {}, name: {}, type: {}} that has a Stage {id: {}, name: {}, type: {}} as a parent. Adding to remap list." ,
67+ node .getId (),
68+ node .getDisplayName (),
69+ node .getType (),
70+ parent .getId (),
71+ parent .getDisplayName (),
72+ parent .getType ());
73+ }
74+ nodesToRemap .put (node .getId (), parent .getId ());
75+ // Skip other checks.
76+ continue ;
6577 }
66- this .nodesToRemap .put (node .getId (), parent .getId ());
67- // Skip other checks.
68- continue ;
69- }
70- // If the node has a parent which is a parallel branch, with the same name and
71- // has only one child (this node)
72- // then remap child nodes to that parent. This removes some superfluous stages
73- // in parallel branches.
74- if (parent .getType () == FlowNodeWrapper .NodeType .PARALLEL
75- && node .getDisplayName ().equals (parent .getDisplayName ())) {
76- if (isDebugEnabled ) {
77- logger .debug (
78- "getNodesToRemap => Found Stage {id: {}, name: {}, type: {}} that is an only child and has a parent with the same name {id: {}, name: {}, type: {}}. Adding to remap list." ,
79- node .getId (),
80- node .getDisplayName (),
81- node .getType (),
82- parent .getId (),
83- parent .getDisplayName (),
84- parent .getType ());
78+ // If the node has a parent which is a parallel branch, with the same name and
79+ // has only one child (this node)
80+ // then remap child nodes to that parent. This removes some superfluous stages
81+ // in parallel branches.
82+ if (parent .getType () == FlowNodeWrapper .NodeType .PARALLEL
83+ && node .getDisplayName ().equals (parent .getDisplayName ())) {
84+ if (isDebugEnabled ) {
85+ logger .debug (
86+ "getNodesToRemap => Found Stage {id: {}, name: {}, type: {}} that is an only child and has a parent with the same name {id: {}, name: {}, type: {}}. Adding to remap list." ,
87+ node .getId (),
88+ node .getDisplayName (),
89+ node .getType (),
90+ parent .getId (),
91+ parent .getDisplayName (),
92+ parent .getType ());
93+ }
94+ nodesToRemap .put (node .getId (), parent .getId ());
8595 }
86- this .nodesToRemap .put (node .getId (), parent .getId ());
87- continue ;
8896 }
8997 }
90- }
91- for (String nodeId : this .nodesToRemap .keySet ()) {
92- this .nodesToRemap .put (nodeId , getFinalParent (nodeId , this .nodesToRemap ));
98+ for (String nodeId : nodesToRemap .keySet ()) {
99+ nodesToRemap .put (nodeId , getFinalParent (nodeId , nodesToRemap ));
100+ }
101+ this .nodesToRemap = nodesToRemap ;
93102 }
94103 return this .nodesToRemap ;
95104 }
@@ -117,9 +126,7 @@ private void dumpNodeGraphviz(
117126 nodes .addAll (stepsList );
118127 }
119128 }
120- if (isDebugEnabled ) {
121- logger .debug (FlowNodeWrapper .getNodeGraphviz (nodes ));
122- }
129+ logger .debug (FlowNodeWrapper .getNodeGraphviz (nodes ));
123130 }
124131 }
125132
@@ -134,26 +141,25 @@ private void remapStageParentage() {
134141 return ;
135142 }
136143 Map <String , FlowNodeWrapper > pipelineNodeMap = treeScanner .getPipelineNodeMap ();
137-
138- this .pipelineNodesList = new ArrayList <FlowNodeWrapper >(pipelineNodeMap .values ());
139- Collections .sort (this .pipelineNodesList , new FlowNodeWrapper .NodeComparator ());
144+ List <FlowNodeWrapper > pipelineNodes = new ArrayList <>(pipelineNodeMap .values ());
145+ pipelineNodes .sort (new FlowNodeWrapper .NodeComparator ());
140146 // Remove children whose parents were skipped.
141- Map <String , String > nodesToRemap = getNodesToRemap (this . pipelineNodesList );
147+ Map <String , String > nodesToRemap = getNodesToRemap (pipelineNodes );
142148 if (isDebugEnabled ) {
143149 logger .debug (
144150 "remapStageParentage => nodesToRemap: {}" ,
145151 nodesToRemap .entrySet ().stream ()
146152 .map (entrySet -> entrySet .getKey () + ":" + entrySet .getValue ())
147153 .collect (Collectors .joining ("," , "[" , "]" )));
148154 }
149- dumpNodeGraphviz (this . pipelineNodesList );
155+ dumpNodeGraphviz (pipelineNodes );
150156 // Find all nodes that have a parent to remap (see 'getNodesToRemap') and change
151157 // their parentage
152158 // to the designated parent.
153- for (int i = this . pipelineNodesList .size () - 1 ; i >= 0 ; i --) {
154- FlowNodeWrapper node = this . pipelineNodesList .get (i );
159+ for (int i = pipelineNodes .size () - 1 ; i >= 0 ; i --) {
160+ FlowNodeWrapper node = pipelineNodes .get (i );
155161 List <String > parentIds =
156- node .getParents ().stream ().map (FlowNodeWrapper ::getId ).collect ( Collectors . toList () );
162+ node .getParents ().stream ().map (FlowNodeWrapper ::getId ).toList ();
157163 for (String parentId : parentIds ) {
158164 if (nodesToRemap .containsKey (parentId )) {
159165 FlowNodeWrapper parent = pipelineNodeMap .get (parentId );
@@ -193,7 +199,7 @@ private void remapStageParentage() {
193199 }
194200 }
195201 // Remove remapped nodes from the tree
196- this .pipelineNodesList = this . pipelineNodesList .stream ()
202+ this .pipelineNodesList = pipelineNodes .stream ()
197203 .
198204 // Filter out obsolete Parallel block nodes - ones whose children were remapped
199205 // to a
@@ -212,54 +218,57 @@ private void remapStepParentage() {
212218 if (this .stepsMap != null ) {
213219 return ;
214220 }
215- this .stepsMap = treeScanner .getAllSteps ();
216- dumpNodeGraphviz (getPipelineNodes (), this .stepsMap );
217- Map <String , String > nodesToRemap = getNodesToRemap (getPipelineNodes ());
221+ Map <String , List <FlowNodeWrapper >> stepsMap = treeScanner .getAllSteps ();
222+ List <FlowNodeWrapper > pipelineNodes = getPipelineNodes ();
223+ dumpNodeGraphviz (pipelineNodes , stepsMap );
224+ Map <String , String > nodesToRemap = getNodesToRemap (pipelineNodes );
218225 for (Map .Entry <String , String > remapEntry : nodesToRemap .entrySet ()) {
219226 String originalParentId = remapEntry .getKey ();
220- if (this . stepsMap .containsKey (originalParentId )) {
227+ if (stepsMap .containsKey (originalParentId )) {
221228 String remappedParentId = remapEntry .getValue ();
222229 if (isDebugEnabled ) {
223230 logger .debug (
224231 "remapStepParentage => Remapping {} steps from stage {} to {}." ,
225- this . stepsMap .get (originalParentId ).size (),
232+ stepsMap .get (originalParentId ).size (),
226233 originalParentId ,
227234 remappedParentId );
228235 }
229236 List <FlowNodeWrapper > remappedParentStepsList =
230- this . stepsMap .getOrDefault (remappedParentId , new ArrayList <>());
231- remappedParentStepsList .addAll (this . stepsMap .get (originalParentId ));
237+ stepsMap .getOrDefault (remappedParentId , new ArrayList <>());
238+ remappedParentStepsList .addAll (stepsMap .get (originalParentId ));
232239 // Ensure steps are sorted correctly.
233- Collections .sort (remappedParentStepsList , new FlowNodeWrapper .NodeComparator ());
234- this . stepsMap .put (remappedParentId , remappedParentStepsList );
235- this . stepsMap .remove (originalParentId );
240+ remappedParentStepsList .sort (new FlowNodeWrapper .NodeComparator ());
241+ stepsMap .put (remappedParentId , remappedParentStepsList );
242+ stepsMap .remove (originalParentId );
236243 }
237244 }
238- dumpNodeGraphviz (getPipelineNodes (), this .stepsMap );
245+ this .stepsMap = stepsMap ;
246+ dumpNodeGraphviz (pipelineNodes , this .stepsMap );
239247 }
240248
241249 public List <FlowNodeWrapper > getPipelineNodes () {
242250 if (this .pipelineNodesList == null ) {
243- remapStageParentage ();
251+ synchronized (pipelineLock ) {
252+ if (this .pipelineNodesList == null ) {
253+ remapStageParentage ();
254+ }
255+ }
244256 }
245- return this .pipelineNodesList ;
257+ return Collections . unmodifiableList ( this .pipelineNodesList ) ;
246258 }
247259
248260 public Map <String , List <FlowNodeWrapper >> getAllSteps () {
249261 if (this .stepsMap == null ) {
250- remapStepParentage ();
262+ synchronized (stepLock ) {
263+ if (this .stepsMap == null ) {
264+ remapStepParentage ();
265+ }
266+ }
251267 }
252- return this .stepsMap ;
268+ return Collections . unmodifiableMap ( this .stepsMap ) ;
253269 }
254270
255271 public List <FlowNodeWrapper > getStageSteps (String startNodeId ) {
256- return getAllSteps ().getOrDefault (startNodeId , new ArrayList <FlowNodeWrapper >());
257- }
258-
259- public Map <String , List <FlowNodeWrapper >> getStep () {
260- if (this .stepsMap == null ) {
261- remapStepParentage ();
262- }
263- return this .stepsMap ;
272+ return Collections .unmodifiableList (getAllSteps ().getOrDefault (startNodeId , new ArrayList <>()));
264273 }
265274}
0 commit comments