提交 60390d69 编写于 作者: K kohsuke

abstracting away JobOffer.

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@35605 71c3de6d-444a-0410-be80-ed276b4c234a
上级 a9b3b5c3
......@@ -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<ConsistentHash<ExecutorChunk>> hashes = new ArrayList<ConsistentHash<ExecutorChunk>>(ws.works.size());
for (int i=0; i<ws.works.size(); i++) {
......@@ -133,7 +133,7 @@ public abstract class LoadBalancer /*implements ExtensionPoint*/ {
final LoadBalancer base = this;
return new LoadBalancer() {
@Override
protected Mapping map(Task task, MappingWorksheet worksheet) {
public Mapping map(Task task, MappingWorksheet worksheet) {
if (Queue.ifBlockedByHudsonShutdown(task)) {
// if we are quieting down, don't start anything new so that
// all executors will be eventually free.
......
......@@ -164,7 +164,7 @@ public class Queue extends ResourceController implements Saveable {
* a new {@link JobOffer} and gets itself {@linkplain Queue#parked parked},
* and we'll eventually hand out an {@link #workUnit} to build.
*/
public class JobOffer {
public class JobOffer extends MappingWorksheet.ExecutorSlot {
public final Executor executor;
/**
......@@ -183,12 +183,18 @@ public class Queue extends ResourceController implements Saveable {
this.executor = executor;
}
public void set(WorkUnit p) {
@Override
protected void set(WorkUnit p) {
assert this.workUnit == null;
this.workUnit = p;
event.signal();
}
@Override
public Executor getExecutor() {
return executor;
}
/**
* Verifies that the {@link Executor} represented by this object is capable of executing the given task.
*/
......
......@@ -31,6 +31,7 @@ import hudson.model.Executor;
import hudson.model.Hudson;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
......@@ -52,8 +53,29 @@ public abstract class LoadPredictor implements ExtensionPoint {
*
* @param start
* Where to start enumeration. Always bigger or equal to the current time of the execution.
* @param plan
* This is the execution plan for which we are making a load prediction. Never null. While
* this object is still being partially constructed when this method is called, some
* of its properties (like {@link MappingWorksheet#item} provide access to more contextual
* information.
* @since 1.380
*/
public abstract Iterable<FutureLoad> predict(Computer computer, long start, long end);
public Iterable<FutureLoad> 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<FutureLoad> 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<FutureLoad> predict(final Computer computer, long start, long eternity) {
public Iterable<FutureLoad> predict(MappingWorksheet plan, final Computer computer, long start, long eternity) {
long now = System.currentTimeMillis();
List<FutureLoad> fl = new ArrayList<FutureLoad>();
for (Executor e : computer.getExecutors()) {
......
......@@ -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<JobOffer> {
public final class ExecutorChunk extends ReadOnlyList<ExecutorSlot> {
public final int index;
public final Computer computer;
public final Node node;
private ExecutorChunk(List<JobOffer> base, int index) {
private ExecutorChunk(List<ExecutorSlot> 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<WorkChunk,ExecutorChunk> toMap() {
Map<WorkChunk,ExecutorChunk> r = new HashMap<WorkChunk,ExecutorChunk>();
for (int i=0; i<size(); i++)
r.put(get(i),assigned(i));
return r;
}
/**
* Checks if the assignments made thus far are valid an within the constraints.
*/
......@@ -280,17 +290,20 @@ public class MappingWorksheet {
}
}
public MappingWorksheet(BuildableItem item, List<? extends ExecutorSlot> offers) {
this(item,offers,LoadPredictor.all());
}
public MappingWorksheet(BuildableItem item, List<JobOffer> offers) {
public MappingWorksheet(BuildableItem item, List<? extends ExecutorSlot> offers, Collection<? extends LoadPredictor> loadPredictors) {
this.item = item;
// group executors by their computers
Map<Computer,List<JobOffer>> j = new HashMap<Computer, List<JobOffer>>();
for (JobOffer o : offers) {
Computer c = o.executor.getOwner();
List<Queue.JobOffer> l = j.get(c);
Map<Computer,List<ExecutorSlot>> j = new HashMap<Computer, List<ExecutorSlot>>();
for (ExecutorSlot o : offers) {
Computer c = o.getExecutor().getOwner();
List<ExecutorSlot> l = j.get(c);
if (l==null)
j.put(c,l=new ArrayList<JobOffer>());
j.put(c,l=new ArrayList<ExecutorSlot>());
l.add(o);
}
......@@ -298,16 +311,16 @@ public class MappingWorksheet {
long duration = item.task.getEstimatedDuration();
if (duration > 0) {
long now = System.currentTimeMillis();
for (Entry<Computer, List<JobOffer>> e : j.entrySet()) {
final List<JobOffer> list = e.getValue();
for (Entry<Computer, List<ExecutorSlot>> e : j.entrySet()) {
final List<ExecutorSlot> 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<ExecutorChunk> executors = new ArrayList<ExecutorChunk>();
for (List<JobOffer> group : j.values()) {
for (List<ExecutorSlot> 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;
}
}
......@@ -49,7 +49,7 @@ public class LoadPredictorTest extends HudsonTestCase {
@TestExtension
public static class LoadPredictorImpl extends LoadPredictor {
@Override
public Iterable<FutureLoad> predict(Computer computer, long start, long end) {
public Iterable<FutureLoad> 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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册