diff --git a/core/src/main/java/hudson/model/LoadBalancer.java b/core/src/main/java/hudson/model/LoadBalancer.java index 9f88b01dc7..39e2e5789b 100644 --- a/core/src/main/java/hudson/model/LoadBalancer.java +++ b/core/src/main/java/hudson/model/LoadBalancer.java @@ -62,14 +62,14 @@ public abstract class LoadBalancer /*implements ExtensionPoint*/ { * Return null if you don't want the task to be executed right now, * in which case this method will be called some time later with the same task. */ - protected abstract Mapping map(Task task, MappingWorksheet worksheet); + public abstract Mapping map(Task task, MappingWorksheet worksheet); /** * Uses a consistent hash for scheduling. */ public static final LoadBalancer CONSISTENT_HASH = new LoadBalancer() { @Override - protected Mapping map(Task task, MappingWorksheet ws) { + public Mapping map(Task task, MappingWorksheet ws) { // build consistent hash for each work chunk List> hashes = new ArrayList>(ws.works.size()); for (int i=0; i predict(Computer computer, long start, long end); + public Iterable predict(MappingWorksheet plan, Computer computer, long start, long end) { + // maintain backward compatibility by calling the old signature. + return predict(computer,start,end); + } + + /** + * Estimates load starting from the 'start' timestamp, up to the 'end' timestamp. + * + * @param start + * Where to start enumeration. Always bigger or equal to the current time of the execution. + * @deprecated as of 1.380 + * Use {@link #predict(MappingWorksheet, Computer, long, long)} + */ + public Iterable predict(Computer computer, long start, long end) { + return Collections.emptyList(); + } /** * All the registered instances. @@ -68,7 +90,7 @@ public abstract class LoadPredictor implements ExtensionPoint { @Extension public static class CurrentlyRunningTasks extends LoadPredictor { @Override - public Iterable predict(final Computer computer, long start, long eternity) { + public Iterable predict(MappingWorksheet plan, final Computer computer, long start, long eternity) { long now = System.currentTimeMillis(); List fl = new ArrayList(); for (Executor e : computer.getExecutors()) { diff --git a/core/src/main/java/hudson/model/queue/MappingWorksheet.java b/core/src/main/java/hudson/model/queue/MappingWorksheet.java index 32ff6a78bc..c0ab3a8580 100644 --- a/core/src/main/java/hudson/model/queue/MappingWorksheet.java +++ b/core/src/main/java/hudson/model/queue/MappingWorksheet.java @@ -30,7 +30,6 @@ import hudson.model.Executor; import hudson.model.Label; import hudson.model.LoadBalancer; import hudson.model.Node; -import hudson.model.Queue; import hudson.model.Queue.BuildableItem; import hudson.model.Queue.Executable; import hudson.model.Queue.JobOffer; @@ -38,6 +37,7 @@ import hudson.model.Queue.Task; import java.util.AbstractList; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -106,16 +106,16 @@ public class MappingWorksheet { } } - public final class ExecutorChunk extends ReadOnlyList { + public final class ExecutorChunk extends ReadOnlyList { public final int index; public final Computer computer; public final Node node; - private ExecutorChunk(List base, int index) { + private ExecutorChunk(List base, int index) { super(base); this.index = index; assert !base.isEmpty(); - computer = base.get(0).executor.getOwner(); + computer = base.get(0).getExecutor().getOwner(); node = computer.getNode(); } @@ -242,6 +242,16 @@ public class MappingWorksheet { return mapping.length; } + /** + * Returns the assignment as a map. + */ + public Map toMap() { + Map r = new HashMap(); + for (int i=0; i offers) { + this(item,offers,LoadPredictor.all()); + } - public MappingWorksheet(BuildableItem item, List offers) { + public MappingWorksheet(BuildableItem item, List offers, Collection loadPredictors) { this.item = item; // group executors by their computers - Map> j = new HashMap>(); - for (JobOffer o : offers) { - Computer c = o.executor.getOwner(); - List l = j.get(c); + Map> j = new HashMap>(); + for (ExecutorSlot o : offers) { + Computer c = o.getExecutor().getOwner(); + List l = j.get(c); if (l==null) - j.put(c,l=new ArrayList()); + j.put(c,l=new ArrayList()); l.add(o); } @@ -298,16 +311,16 @@ public class MappingWorksheet { long duration = item.task.getEstimatedDuration(); if (duration > 0) { long now = System.currentTimeMillis(); - for (Entry> e : j.entrySet()) { - final List list = e.getValue(); + for (Entry> e : j.entrySet()) { + final List list = e.getValue(); final int max = e.getKey().countExecutors(); // build up the prediction model. cut the chase if we hit the max. Timeline timeline = new Timeline(); int peak = 0; OUTER: - for (LoadPredictor lp : LoadPredictor.all()) { - for (FutureLoad fl : Iterables.limit(lp.predict(e.getKey(), now, now + duration),100)) { + for (LoadPredictor lp : loadPredictors) { + for (FutureLoad fl : Iterables.limit(lp.predict(this,e.getKey(), now, now + duration),100)) { peak = max(peak,timeline.insert(fl.startTime, fl.startTime+fl.duration, fl.numExecutors)); if (peak>=max) break OUTER; } @@ -322,7 +335,7 @@ public class MappingWorksheet { // build into the final shape List executors = new ArrayList(); - for (List group : j.values()) { + for (List group : j.values()) { if (group.isEmpty()) continue; // evict empty group ExecutorChunk ec = new ExecutorChunk(group, executors.size()); if (ec.node==null) continue; // evict out of sync node @@ -357,4 +370,12 @@ public class MappingWorksheet { public ExecutorChunk executors(int index) { return executors.get(index); } + + public static abstract class ExecutorSlot { + public abstract Executor getExecutor(); + + public abstract boolean isAvailable(); + + protected abstract void set(WorkUnit p) throws UnsupportedOperationException; + } } diff --git a/test/src/test/java/hudson/model/queue/LoadPredictorTest.java b/test/src/test/java/hudson/model/queue/LoadPredictorTest.java index 4517480877..d89139c79b 100644 --- a/test/src/test/java/hudson/model/queue/LoadPredictorTest.java +++ b/test/src/test/java/hudson/model/queue/LoadPredictorTest.java @@ -49,7 +49,7 @@ public class LoadPredictorTest extends HudsonTestCase { @TestExtension public static class LoadPredictorImpl extends LoadPredictor { @Override - public Iterable predict(Computer computer, long start, long end) { + public Iterable predict(MappingWorksheet plan, Computer computer, long start, long end) { return asList(new FutureLoad(start+5000, end-(start+5000), 1)); } } @@ -114,16 +114,10 @@ public class LoadPredictorTest extends HudsonTestCase { private JobOffer createMockOffer(Executor e) throws NoSuchFieldException, IllegalAccessException { JobOffer o = mock(JobOffer.class); - setExecutor(o, e); + when(o.getExecutor()).thenReturn(e); return o; } - private void setExecutor(JobOffer o, Executor e) throws NoSuchFieldException, IllegalAccessException { - Field f = o.getClass().getField("executor"); - f.setAccessible(true); - f.set(o, e); - } - private Computer createMockComputer(int nExecutors) throws Exception { Node n = mock(Node.class); Computer c = mock(Computer.class);