// things: We can get a race condition between thread A reading the tree,
// finding nothing and setCachedWakeup(), and thread B waking up a request,
// resulting in the request not being accessible.
val = chosenTracker.removeRandom(starter, context, now);
}
SendableRequest req;
if(val == null) {
Logger.normal(this, "Priority "+choosenPriorityClass+" returned null - nothing to schedule, should remove priority");
continue outer;
} else if(val.item == null) {
if(val.wakeupTime == -1)
Logger.normal(this, "Priority "+choosenPriorityClass+" returned cooldown time of -1 - nothing to schedule, should remove priority");
else {
Logger.normal(this, "Priority "+choosenPriorityClass+" returned cooldown time of "+(val.wakeupTime - now)+" = "+TimeUtil.formatTime(val.wakeupTime - now));
if(val.wakeupTime > 0 && val.wakeupTime < wakeupTime)
wakeupTime = val.wakeupTime;
}
continue outer;
} else {
req = (SendableRequest) val.item;
}
if(req.getPriorityClass() != choosenPriorityClass) {
// Reinsert it : shouldn't happen if we are calling reregisterAll,
// maybe we should ask people to report that error if seen
Logger.normal(this, "In wrong priority class: "+req+" (req.prio="+req.getPriorityClass()+" but chosen="+choosenPriorityClass+ ')');
// Remove it.
ClientRequestRGANode clientGrabber = chosenTracker.getGrabber(req.getClient());
if(clientGrabber != null) {
RandomGrabArray baseRGA = clientGrabber.getGrabber(req.getSchedulerGroup());
if(baseRGA != null) {
// Must synchronize to avoid nasty race conditions with cooldown.
synchronized(this) {
baseRGA.remove(req, context);
}
} else {
// Okay, it's been removed already. Cool.
}
} else {
Logger.error(this, "Could not find client grabber for client "+req.getClient()+" from "+chosenTracker);
}
innerRegister(req, context, null);
continue;
}
// Check recentSuccesses
/** Choose a recently succeeded request.
* 50% chance of using a recently succeeded request, if there is one.
* We keep a list of recently succeeded BaseSendableGet's, because transient
* requests are chosen individually. */
if(!isInsertScheduler) {
BaseSendableGet altReq = null;
synchronized(recentSuccesses) {
if(!recentSuccesses.isEmpty()) {
if(random.nextBoolean()) {
altReq = recentSuccesses.poll();
}
}
}
if(altReq != null && (altReq.isCancelled())) {
if(logMINOR)
Logger.minor(this, "Ignoring cancelled recently succeeded item "+altReq);
altReq = null;
}
if(altReq != null && (l = altReq.getWakeupTime(context, now)) != 0) {
if(logMINOR) {
Logger.minor(this, "Ignoring recently succeeded item, cooldown time = "+l+((l > 0) ? " ("+TimeUtil.formatTime(l - now)+")" : ""));
altReq = null;
}
}
if (altReq != null && altReq != req) {
int prio = altReq.getPriorityClass();
if(prio <= choosenPriorityClass) {
// Use the recent one instead
if(logMINOR)
Logger.minor(this, "Recently succeeded (transient) req "+altReq+" (prio="+altReq.getPriorityClass()+") is better than "+req+" (prio="+req.getPriorityClass()+"), using that");
// Don't need to reregister, because removeRandom doesn't actually remove!
req = altReq;
} else {
// Don't use the recent one
if(logMINOR)
Logger.minor(this, "Chosen req "+req+" is better, reregistering recently succeeded "+altReq);
synchronized(recentSuccesses) {
recentSuccesses.add(altReq);
}
}
}
}
// Now we have chosen a request.
if(logMINOR) Logger.minor(this, "removeFirst() returning "+req+" (prio "+
req.getPriorityClass()+", client "+req.getClient()+", client-req "+req.getClientRequest()+ ')');
if(logMINOR) Logger.minor(this, "removeFirst() returning "+req+" of "+req.getClientRequest());
assert(req.realTimeFlag() == realTime);
return new SelectorReturn(req);
}
}
if(logMINOR) Logger.minor(this, "No requests to run");