From 8cd99cac90b180a3e84d17c56c5fb1f11744f263 Mon Sep 17 00:00:00 2001 From: Valentina Armenise Date: Mon, 31 Aug 2015 18:30:06 +0200 Subject: [PATCH] [JENKINS-30084] flyweight tasks gets added to the buildable list when no executor is available --- core/src/main/java/hudson/model/Queue.java | 103 +++++++++++++++++- .../hudson/model/queue/QueueListener.java | 4 + 2 files changed, 104 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index 12d3078927..8172273f53 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -194,6 +194,17 @@ public class Queue extends ResourceController implements Saveable { */ private final ItemList blockedProjects = new ItemList(); + /** + * List of type {@link FlyWeightItem}. + * + *

+ * This consists of {@link Item}s which require one additional executor, + * which is a temporary executor, to manage the execution of its nested tasks. + * This applies to Matrix project. + */ + + private final ItemList flyWeightTasks = new ItemList(); + /** * {@link Task}s that can be built immediately * that are waiting for available {@link Executor}. @@ -1427,6 +1438,20 @@ public class Queue extends ResourceController implements Saveable { } } + //this is to solve OSS-192. We iterate on the list of flyweight tasks and execute them + List flyweightItems = new ArrayList<>(flyWeightTasks.values()); + for (FlyWeightItem f : flyweightItems) { + if (!isBuildBlocked(f)) { + // ready to be executed + Runnable r = makeBuildable(new BuildableItem(f)); + if (r != null) { + f.leave(this); + r.run(); + updateSnapshot(); + } + } + } + // waitingList -> buildable/blocked while (!waitingList.isEmpty()) { WaitingItem top = peek(); @@ -1442,7 +1467,8 @@ public class Queue extends ResourceController implements Saveable { if (r != null) { r.run(); } else { - new BlockedItem(top).enter(this); + new BuildableItem(top).enter(this); + new FlyWeightItem(top).enter(this); } } else { // this can't be built now because another build is in progress @@ -1460,6 +1486,9 @@ public class Queue extends ResourceController implements Saveable { // allocate buildable jobs to executors for (BuildableItem p : new ArrayList( buildables)) {// copy as we'll mutate the list in the loop + if (p.task instanceof FlyweightTask){ + continue; + } // one last check to make sure this build is not blocked. if (isBuildBlocked(p)) { p.leave(this); @@ -1538,12 +1567,15 @@ public class Queue extends ResourceController implements Saveable { Label lbl = p.getAssignedLabel(); for (Node n : hash.list(p.task.getFullDisplayName())) { final Computer c = n.toComputer(); - if (c==null || c.isOffline()) continue; - if (lbl!=null && !lbl.contains(n)) continue; + // if (c==null || c.isOffline()) continue; + // if (lbl!=null && !lbl.contains(n)) continue; + if (n.canTake(p) != null) continue; + if (c==null || c.isOffline()) continue; return new Runnable() { @Override public void run() { c.startFlyWeightTask(new WorkUnitContext(p).createWorkUnit(p.task)); + p.leave(Queue.this); makePending(p); } }; @@ -2316,6 +2348,71 @@ public class Queue extends ResourceController implements Saveable { } } + /** + * {@link Item} in the {@link Queue#flyWeightTasks} stage. + */ + public final class FlyWeightItem extends NotWaitingItem { + + boolean buildable; + + public FlyWeightItem(WaitingItem wi) { + super(wi); + } + + public FlyWeightItem(NotWaitingItem ni) { + super(ni); + } + + public CauseOfBlockage getCauseOfBlockage() { + ResourceActivity r = getBlockingActivity(task); + if (r != null) { + if (r == task) // blocked by itself, meaning another build is in progress + return CauseOfBlockage.fromMessage(Messages._Queue_InProgress()); + return CauseOfBlockage.fromMessage(Messages._Queue_BlockedBy(r.getDisplayName())); + } + + for (QueueTaskDispatcher d : QueueTaskDispatcher.all()) { + CauseOfBlockage cause = d.canRun(this); + if (cause != null) + return cause; + } + + return task.getCauseOfBlockage(); + } + + /*package*/ void enter(Queue q) { + LOGGER.log(Level.FINE, "{0} is blocked", this); + flyWeightTasks.add(this); + buildable = true; + for (QueueListener ql : QueueListener.all()) { + try { + ql.onEnterFlyWeight(this); + } catch (Throwable e) { + // don't let this kill the queue + LOGGER.log(Level.WARNING, "QueueListener failed while processing "+this,e); + } + } + } + + /*package*/ boolean leave(Queue q) { + boolean r = flyWeightTasks.remove(this); + buildable = false; + if (r) { + LOGGER.log(Level.FINE, "{0} no longer blocked", this); + for (QueueListener ql : QueueListener.all()) { + try { + ql.onLeaveFlyWeight(this); + } catch (Throwable e) { + // don't let this kill the queue + LOGGER.log(Level.WARNING, "QueueListener failed while processing "+this,e); + } + } + } + return r; + } + } + + /** * {@link Item} in the {@link Queue#buildables} stage. */ diff --git a/core/src/main/java/hudson/model/queue/QueueListener.java b/core/src/main/java/hudson/model/queue/QueueListener.java index 527a9485b4..db21006e82 100644 --- a/core/src/main/java/hudson/model/queue/QueueListener.java +++ b/core/src/main/java/hudson/model/queue/QueueListener.java @@ -9,6 +9,7 @@ import hudson.model.Queue.BuildableItem; import hudson.model.Queue.Item; import hudson.model.Queue.LeftItem; import hudson.model.Queue.WaitingItem; +import hudson.model.Queue.FlyWeightItem; import jenkins.model.Jenkins; import java.util.concurrent.Executor; @@ -29,6 +30,9 @@ import java.util.concurrent.Executor; * @since 1.520 */ public abstract class QueueListener implements ExtensionPoint { + + public void onEnterFlyWeight(FlyWeightItem fw) {} + public void onLeaveFlyWeight(FlyWeightItem fw) {} /** * When a task is submitted to the queue, it first gets to the waiting phase, * where it spends until the quiet period runs out and the item becomes executable. -- GitLab