diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index 4b314ad78a9df99910e93d0f7cc7ebddab9a2ab9..db6cf5f7e743ae9dcff82173aa205a2ab85a9d15 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -1073,16 +1073,18 @@ public class Queue extends ResourceController implements Saveable { private void makeBuildable(BuildableItem p) { if(Jenkins.FLYWEIGHT_SUPPORT && p.task instanceof FlyweightTask && !ifBlockedByHudsonShutdown(p.task)) { - ConsistentHash hash = new ConsistentHash(new Hash() { - public String hash(Node node) { - return node.getNodeName(); - } - }); + + ConsistentHash.Builder builder = new ConsistentHash.Builder(NODE_HASH); + Jenkins h = Jenkins.getInstance(); // Even if master is configured with zero executors, we may need to run a flyweight task like MatrixProject on it. - hash.add(h, Math.max(h.getNumExecutors()*100, 1)); - for (Node n : h.getNodes()) - hash.add(n, n.getNumExecutors()*100); + builder.add(h, Math.max(h.getNumExecutors() * 100, 1)); + + for (Node n : h.getNodes()) { + builder.add(n, n.getNumExecutors() * 100); + } + + ConsistentHash hash = builder.build(); Label lbl = p.getAssignedLabel(); for (Node n : hash.list(p.task.getFullDisplayName())) { @@ -1101,6 +1103,13 @@ public class Queue extends ResourceController implements Saveable { p.enter(this); } + + private static Hash NODE_HASH = new Hash() { + public String hash(Node node) { + return node.getNodeName(); + } + }; + private boolean makePending(BuildableItem p) { // LOGGER.info("Making "+p.task+" pending"); // REMOVE p.isPending = true; diff --git a/core/src/main/java/hudson/util/ConsistentHash.java b/core/src/main/java/hudson/util/ConsistentHash.java index 71fb17d2fe7fb6811d520ae7e1205c2887e84ac3..886316b7bfdba294f31b15a81ad94d8afb2490d1 100644 --- a/core/src/main/java/hudson/util/ConsistentHash.java +++ b/core/src/main/java/hudson/util/ConsistentHash.java @@ -201,13 +201,13 @@ public class ConsistentHash { } public ConsistentHash(Hash hash) { - this(hash,100); + this(hash, 100); } public ConsistentHash(Hash hash, int defaultReplication) { this.hash = hash; this.defaultReplication = defaultReplication; - this.table = new Table(); // initial empty table + refreshTable(); } public int countAllPoints() { @@ -244,7 +244,7 @@ public class ConsistentHash { * Removes the node entirely. This is the same as {@code add(node,0)} */ public void remove(T node) { - add(node,0); + add(node, 0); } /** @@ -254,6 +254,11 @@ public class ConsistentHash { * This is the only function that manipulates {@link #items}. */ public synchronized void add(T node, int replica) { + addInternal(node, replica); + refreshTable(); + } + + private void addInternal(T node, int replica) { if(replica==0) { items.remove(node); } else { @@ -263,9 +268,13 @@ public class ConsistentHash { points[i] = new Point(md5(seed+':'+i),node); items.put(node,points); } + } + + private void refreshTable() { table = new Table(); } + /** * Compresses a string into an integer with MD5. */ @@ -335,4 +344,24 @@ public class ConsistentHash { public Iterable list(String queryPoint) { return list(md5(queryPoint)); } + + public static class Builder { + + final ConsistentHash c; + + public Builder(Hash hash) { + c = new ConsistentHash(hash); + } + + public Builder add(T node, int replica) { + c.addInternal(node, replica); + return this; + } + + public ConsistentHash build() { + c.refreshTable(); + return c; + } + } + }