@@ -1615,6 +1615,9 @@ public void maintain() {
16151615 // Ensure that identification of blocked tasks is using the live state: JENKINS-27708 & JENKINS-27871
16161616 updateSnapshot ();
16171617
1618+ // JENKINS-75152. Save the label and blockage reasons of items that have no candidates into this map.
1619+ // It is used to speed up the judgement of other buildable items with the same label.
1620+ Map <Label , List <CauseOfBlockage >> noCandidateLabelsMap = new HashMap <>();
16181621 // allocate buildable jobs to executors
16191622 for (BuildableItem p : new ArrayList <>(
16201623 buildables )) { // copy as we'll mutate the list in the loop
@@ -1641,6 +1644,13 @@ public void maintain() {
16411644 updateSnapshot ();
16421645 }
16431646 } else {
1647+ // JENKINS-75152. Skip the remaining steps if the label of this item has been determined
1648+ // to have no candidate executors in the previous allocation process.
1649+ Label itemLabel = p .getAssignedLabel ();
1650+ if (noCandidateLabelsMap .containsKey (itemLabel )) {
1651+ p .transientCausesOfBlockage = noCandidateLabelsMap .get (itemLabel );
1652+ continue ;
1653+ }
16441654
16451655 List <JobOffer > candidates = new ArrayList <>(parked .size ());
16461656 Map <Node , CauseOfBlockage > reasonMap = new HashMap <>();
@@ -1673,6 +1683,11 @@ public void maintain() {
16731683 new Object []{p , candidates , parked .values ()});
16741684 List <CauseOfBlockage > reasons = reasonMap .values ().stream ().filter (Objects ::nonNull ).collect (Collectors .toList ());
16751685 p .transientCausesOfBlockage = reasons .isEmpty () ? null : reasons ;
1686+ // If no candidates, save the label and blockage reasons.
1687+ if (candidates .isEmpty ()) {
1688+ noCandidateLabelsMap .put (itemLabel , p .transientCausesOfBlockage );
1689+ LOGGER .log (Level .FINEST , "{0} changes to the state of no candidate executor" , itemLabel );
1690+ }
16761691 continue ;
16771692 }
16781693
0 commit comments