mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-11-13 20:12:14 +00:00
abstracting away JobOffer.
git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@35605 71c3de6d-444a-0410-be80-ed276b4c234a
This commit is contained in:
1 parent
a9b3b5c303
commit
60390d69d4
5 files changed
+73
-30
No files matched your search
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user