提交 9e14a891 编写于 作者: K kohsuke

[HUDSON-833] formalized the QueueSorter.

This is a binary incomatpible change from the previous QueueSortingHandler, but given that QueueSortingHandler used one of the private classes in the method signature, I don't see how anyone could have implemented this extension point, so in practice this change shouldn't break any plugin (certainly not any plugins hosted in hudson-ci.org, according to my grep.)

I'll implement a plugin that shows how this extension point can be used, and that will mark this issue as fixed.

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@26610 71c3de6d-444a-0410-be80-ed276b4c234a
上级 fa2e85e7
......@@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import hudson.model.Queue.*;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
......@@ -45,6 +46,7 @@ import org.kohsuke.stapler.export.ExportedBean;
*
* @author Michael Donohue
* @see Run#getCauses()
* @see Queue.Item#getCauses()
*/
@ExportedBean
public abstract class Cause {
......
......@@ -30,8 +30,11 @@ import hudson.Util;
import hudson.XmlFile;
import hudson.init.Initializer;
import static hudson.init.InitMilestone.JOB_LOADED;
import static hudson.util.Iterators.reverse;
import hudson.cli.declarative.CLIMethod;
import hudson.cli.declarative.CLIResolver;
import hudson.model.queue.QueueSorter;
import hudson.remoting.AsyncFutureImpl;
import hudson.model.Node.Mode;
import hudson.model.listeners.SaveableListener;
......@@ -43,6 +46,7 @@ import hudson.model.queue.CauseOfBlockage.BecauseLabelIsOffline;
import hudson.model.queue.CauseOfBlockage.BecauseNodeIsBusy;
import hudson.triggers.SafeTimerTask;
import hudson.triggers.Trigger;
import hudson.util.Iterators;
import hudson.util.OneShotEvent;
import hudson.util.TimeUnit2;
import hudson.util.XStream2;
......@@ -58,6 +62,7 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
......@@ -130,6 +135,7 @@ public class Queue extends ResourceController implements Saveable {
/**
* {@link Task}s that can be built immediately
* that are waiting for available {@link Executor}.
* This list is sorted in such a way that earlier items are built earlier.
*/
private final ItemList<BuildableItem> buildables = new ItemList<BuildableItem>();
......@@ -207,7 +213,7 @@ public class Queue extends ResourceController implements Saveable {
private volatile transient LoadBalancer loadBalancer;
public volatile QueueSortingHandler sortingHandler = null;
private volatile transient QueueSorter sorter;
public Queue(LoadBalancer loadBalancer) {
this.loadBalancer = loadBalancer.sanitize();
......@@ -225,6 +231,14 @@ public class Queue extends ResourceController implements Saveable {
this.loadBalancer = loadBalancer;
}
public QueueSorter getSorter() {
return sorter;
}
public void setSorter(QueueSorter sorter) {
this.sorter = sorter;
}
/**
* Loads the queue contents that was {@link #save() saved}.
*/
......@@ -534,6 +548,9 @@ public class Queue extends ResourceController implements Saveable {
/**
* Gets a snapshot of items in the queue.
*
* Generally speaking the array is sorted such that the items that are most likely built sooner are
* at the end.
*/
@Exported(inline=true)
public synchronized Item[] getItems() {
......@@ -542,7 +559,7 @@ public class Queue extends ResourceController implements Saveable {
int idx = waitingList.size();
for (BlockedItem p : blockedProjects.values())
r[idx++] = p;
for (BuildableItem p : buildables.values())
for (BuildableItem p : reverse(buildables.values()))
r[idx++] = p;
return r;
}
......@@ -891,9 +908,10 @@ public class Queue extends ResourceController implements Saveable {
blockedProjects.put(p,new BlockedItem(top));
}
}
if (sortingHandler != null)
sortingHandler.sortBuildableItems(buildables);
final QueueSorter s = sorter;
if (s != null)
s.sortBuildableItems(buildables);
}
private void makeBuildable(BuildableItem p) {
......@@ -1157,6 +1175,19 @@ public class Queue extends ResourceController implements Saveable {
*/
public Future<Executable> getFuture() { return future; }
/**
* Convenience method that returns a read only view of the {@link Cause}s associated with this item in the queue.
*
* @return can be empty but never null
* @since 1.343
*/
public final List<Cause> getCauses() {
CauseAction ca = getAction(CauseAction.class);
if (ca!=null)
return Collections.unmodifiableList(ca.getCauses());
return Collections.emptyList();
}
protected Item(Task task, List<Action> actions, int id, FutureImpl future) {
this.task = task;
this.id = id;
......@@ -1278,32 +1309,6 @@ public class Queue extends ResourceController implements Saveable {
}
}
/**
* Extension point for sorting buildable items
*
* <p>
* This extension point is still a subject to change, as we are seeking more
* comprehensive Queue pluggability. See HUDSON-2072.
*
* @since 1.316
*/
public static abstract class QueueSortingHandler implements ExtensionPoint {
/**
* Sorts the buildable items list. The items at the beginning will be executed
* before the items at the end of the list
* @param buildables
*/
public abstract void sortBuildableItems(ItemList<BuildableItem> buildables);
/**
* All registered {@link QueueSortingHandler}s
* @return
*/
public static ExtensionList<QueueSortingHandler> all() {
return Hudson.getInstance().getExtensionList(QueueSortingHandler.class);
}
}
/**
* {@link Item} in the {@link Queue#waitingList} stage.
*/
......@@ -1517,8 +1522,7 @@ public class Queue extends ResourceController implements Saveable {
}
/**
* A MultiMap - LinkedMap crossover as a drop-in replacement for the previously used LinkedHashMap
* And no, I don't care about performance ;)
* {@link ArrayList} of {@link Item} with more convenience methods.
*/
private static class ItemList<T extends Item> extends ArrayList<T> {
public T get(Task task) {
......
package hudson.model.queue;
import hudson.model.Queue.BuildableItem;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Partial implementation of {@link QueueSorter} in terms of {@link Comparator}.
*
* @author Kohsuke Kawaguchi
* @since 1.343
*/
public abstract class AbstractQueueSorterImpl extends QueueSorter implements Comparator<BuildableItem> {
@Override
public void sortBuildableItems(List<BuildableItem> buildables) {
Collections.sort(buildables,this); // sort is ascending order
}
/**
* Override this method to provide the ordering of the sort.
*
* <p>
* if lhs should be build before rhs, return a negative value. Or put another way, think of the comparison
* as a process of converting a {@link BuildableItem} into a number, then doing num(lhs)-num(rhs).
*
* <p>
* The default implementation does FIFO.
*/
public int compare(BuildableItem lhs, BuildableItem rhs) {
return compare(lhs.buildableStartMilliseconds,rhs.buildableStartMilliseconds);
}
/**
* sign(a-b).
*/
protected static int compare(long a, long b) {
if (a>b) return 1;
if (a<b) return -1;
return 0;
}
/**
* sign(a-b).
*/
protected static int compare(int a, int b) {
if (a>b) return 1;
if (a<b) return -1;
return 0;
}
}
package hudson.model.queue;
import hudson.ExtensionList;
import hudson.ExtensionPoint;
import hudson.init.Initializer;
import hudson.model.Hudson;
import hudson.model.LoadBalancer;
import hudson.model.Queue;
import hudson.model.Queue.BuildableItem;
import java.util.List;
import java.util.logging.Logger;
import static hudson.init.InitMilestone.JOB_LOADED;
/**
* Singleton extension point for sorting buildable items
*
* @since 1.343
*/
public abstract class QueueSorter implements ExtensionPoint {
/**
* Sorts the buildable items list. The items at the beginning will be executed
* before the items at the end of the list.
*
* @param buildables
* List of buildable items in the queue. Never null.
*/
public abstract void sortBuildableItems(List<BuildableItem> buildables);
/**
* All registered {@link QueueSorter}s. Only the first one will be picked up,
* unless explicitly overridden by {@link Queue#setSorter(QueueSorter)}.
*/
public static ExtensionList<QueueSorter> all() {
return Hudson.getInstance().getExtensionList(QueueSorter.class);
}
/**
* Installs the default queue sorter.
*
* {@link Queue#Queue(LoadBalancer)} is too early to do this
*/
@Initializer(after=JOB_LOADED,displayName="Installing default queue sorter")
public static void installDefaultQueueSorter() {
ExtensionList<QueueSorter> all = all();
if (all.isEmpty()) return;
Queue q = Hudson.getInstance().getQueue();
if (q.getSorter()!=null) return; // someone has already installed something. leave that alone.
q.setSorter(all.get(0));
if (all.size()>1)
LOGGER.warning("Multiple QueueSorters are registered. Only the first one is used and the rest are ignored: "+all);
}
private static final Logger LOGGER = Logger.getLogger(QueueSorter.class.getName());
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册