public void executeNoDupes(Runnable job, int prio, String jobName) { synchronized (jobs) { if (jobs[prio].contains(job)) { if (logMINOR) Logger.minor(this, "Not queueing job: Job already queued: " + job); return; } if (logMINOR) Logger.minor( this, "Queueing " + jobName + " : " + job + " priority " + prio + ", executor state: running=" + running + " waiting=" + waiting); jobs[prio].addLast(job); jobs.notifyAll(); if (!running && realExecutor != null) { reallyStart(); } } }
public void run() { long lastDumped = System.currentTimeMillis(); synchronized (jobs) { if (current != null) { if (current.isAlive()) { Logger.error( this, "Already running a thread for " + this + " !!", new Exception("error")); return; } } current = Thread.currentThread(); } try { while (true) { Runnable job = null; synchronized (jobs) { job = checkQueue(); if (job == null) { waiting = true; try { // NB: notify only on adding work or this quits early. jobs.wait(jobTimeout); } catch (InterruptedException e) { // Ignore } waiting = false; job = checkQueue(); if (job == null) { running = false; return; } } } try { if (logMINOR) Logger.minor(this, "Running job " + job); long start = System.currentTimeMillis(); job.run(); long end = System.currentTimeMillis(); if (logMINOR) { Logger.minor(this, "Job " + job + " took " + (end - start) + "ms"); } if (statistics != null) { statistics.reportDatabaseJob(job.toString(), end - start); } } catch (Throwable t) { Logger.error(this, "Caught " + t, t); Logger.error(this, "While running " + job + " on " + this); } } } finally { synchronized (jobs) { current = null; running = false; } } }
private RemoveRandomReturn removeRandomExhaustive( RandomGrabArrayItemExclusionList excluding, ClientContext context, long now) { synchronized (root) { long wakeupTime = Long.MAX_VALUE; if (grabArrays.length == 0) return null; int x = context.fastWeakRandom.nextInt(grabArrays.length); for (int i = 0; i < grabArrays.length; i++) { x++; if (x >= grabArrays.length) x = 0; RemoveRandomWithObject<T> rga = grabArrays[x]; long excludeTime = rga.getWakeupTime(context, now); if (excludeTime > 0) { if (wakeupTime > excludeTime) wakeupTime = excludeTime; continue; } if (logMINOR) Logger.minor( this, "Picked " + x + " of " + grabArrays.length + " : " + rga + " on " + this); RandomGrabArrayItem item = null; RemoveRandomReturn val = rga.removeRandom(excluding, context, now); if (val != null) { if (val.item != null) item = val.item; else { if (wakeupTime > val.wakeupTime) wakeupTime = val.wakeupTime; } } if (logMINOR) Logger.minor( this, "RGA has picked " + x + "/" + grabArrays.length + ": " + item + " rga.isEmpty=" + rga.isEmpty()); if (item != null) { return new RemoveRandomReturn(item); } else if (rga.isEmpty()) { if (logMINOR) Logger.minor(this, "Removing grab array " + x + " : " + rga + " (is empty)"); removeElement(x); } } reduceWakeupTime(wakeupTime, context); return new RemoveRandomReturn(wakeupTime); } }
private void reallyStart() { synchronized (syncLock) { threadStarted = true; } if (logMINOR) Logger.minor(this, "Starting thread... " + name + " : " + runner); realExecutor.execute(runner, name); }
@Override public void maybeRemove(RemoveRandom r, ClientContext context) { int count = 0; int finalSize; synchronized (root) { while (true) { int found = -1; for (int i = 0; i < grabArrays.length; i++) { if (grabArrays[i] == r) { found = i; break; } } if (found != -1) { count++; if (count > 1) Logger.error(this, "Found " + r + " many times in " + this, new Exception("error")); removeElement(found); } else { break; } } finalSize = grabArrays.length; } if (count == 0) { // This is not unusual, it was e.g. removed because of being empty. // And it has already been removeFrom()'ed. if (logMINOR) Logger.minor(this, "Not in parent: " + r + " for " + this, new Exception("error")); } if (finalSize == 0 && parent != null) { parent.maybeRemove(this, context); } }
@Override public void clearWakeupTime(ClientContext context) { if (logMINOR) Logger.minor(this, "clearCooldownTime() on " + this); synchronized (root) { wakeupTime = 0; if (parent != null) parent.clearWakeupTime(context); } }
private Runnable checkQueue() { if (!invertOrder) { for (int i = 0; i < jobs.length; i++) { if (!jobs[i].isEmpty()) { if (logMINOR) Logger.minor(this, "Chosen job at priority " + i); return jobs[i].removeFirst(); } } } else { for (int i = jobs.length - 1; i >= 0; i--) { if (!jobs[i].isEmpty()) { if (logMINOR) Logger.minor(this, "Chosen job at priority " + i); return jobs[i].removeFirst(); } } } return null; }
private void reallyStart() { synchronized (jobs) { if (running) { Logger.error(this, "Not reallyStart()ing: ALREADY RUNNING", new Exception("error")); return; } running = true; if (logMINOR) Logger.minor(this, "Starting thread... " + name + " : " + runner, new Exception("debug")); realExecutor.execute(runner, name); } }
private RemoveRandomReturn removeRandomOneOnly( RandomGrabArrayItemExclusionList excluding, ClientContext context, long now) { synchronized (root) { long wakeupTime = Long.MAX_VALUE; // Optimise the common case RemoveRandomWithObject<T> rga = grabArrays[0]; if (logMINOR) Logger.minor(this, "Only one RGA: " + rga); long excludeTime = rga.getWakeupTime(context, now); if (excludeTime > 0) return new RemoveRandomReturn(excludeTime); if (rga == null) { Logger.error(this, "Only one entry and that is null"); // We are sure grabArrays = (C[]) new RemoveRandomWithObject[0]; grabClients = (T[]) new Object[0]; return null; } RemoveRandomReturn val = rga.removeRandom(excluding, context, now); RandomGrabArrayItem item = null; if (val != null) { // val == null => remove it if (val.item != null) item = val.item; else { wakeupTime = val.wakeupTime; } } if (rga.isEmpty()) { if (logMINOR) Logger.minor(this, "Removing only grab array (0) : " + rga); grabArrays = (C[]) new RemoveRandomWithObject[0]; grabClients = (T[]) new Object[0]; } if (logMINOR) Logger.minor(this, "Returning (one item only) " + item + " for " + rga); if (item == null) { if (grabArrays.length == 0) { if (logMINOR) Logger.minor(this, "Arrays are empty on " + this); return null; // Remove this as well } reduceWakeupTime(wakeupTime, context); return new RemoveRandomReturn(wakeupTime); } else return new RemoveRandomReturn(item); } }
@Override public boolean reduceWakeupTime(long wakeupTime, ClientContext context) { if (logMINOR) Logger.minor( this, "reduceCooldownTime(" + (wakeupTime - System.currentTimeMillis()) + ") on " + this); boolean reachedRoot = false; synchronized (root) { if (this.wakeupTime > wakeupTime) { this.wakeupTime = wakeupTime; if (parent != null) parent.reduceWakeupTime(wakeupTime, context); else reachedRoot = true; // Even if it reduces it we need to wake it up. } else return false; } if (reachedRoot) root.wakeUp(context); return true; }
@Override public void execute(Runnable job, String jobName) { if (logMINOR) Logger.minor( this, "Running " + jobName + " : " + job + " started=" + threadStarted + " waiting=" + threadWaiting); jobs.add(job); synchronized (syncLock) { if (!threadStarted && realExecutor != null) reallyStart(); } }
private RemoveRandomReturn removeRandomTwoOnly( RandomGrabArrayItemExclusionList excluding, ClientContext context, long now) { synchronized (root) { long wakeupTime = Long.MAX_VALUE; // Another simple common case int x = context.fastWeakRandom.nextBoolean() ? 1 : 0; RemoveRandomWithObject<T> rga = grabArrays[x]; RemoveRandomWithObject<T> firstRGA = rga; if (rga == null) { Logger.error(this, "rga = null on " + this); if (grabArrays[1 - x] == null) { Logger.error(this, "other rga is also null on " + this); grabArrays = (C[]) new RemoveRandomWithObject[0]; grabClients = (T[]) new Object[0]; return null; } else { Logger.error( this, "grabArrays[" + (1 - x) + "] is valid but [" + x + "] is null, correcting..."); grabArrays = (C[]) new RemoveRandomWithObject[] {grabArrays[1 - x]}; grabClients = (T[]) new Object[] {grabClients[1 - x]}; return null; } } RandomGrabArrayItem item = null; RemoveRandomReturn val = null; if (logMINOR) Logger.minor(this, "Only 2, trying " + rga); long excludeTime = rga.getWakeupTime(context, now); if (excludeTime > 0) { wakeupTime = excludeTime; rga = null; firstRGA = null; } else { val = rga.removeRandom(excluding, context, now); if (val != null) { if (val.item != null) item = val.item; else { if (wakeupTime > val.wakeupTime) wakeupTime = val.wakeupTime; } } } if (item != null) { if (logMINOR) Logger.minor(this, "Returning (two items only) " + item + " for " + rga); return new RemoveRandomReturn(item); } else { x = 1 - x; rga = grabArrays[x]; if (rga == null) { Logger.error(this, "Other RGA is null later on on " + this); grabArrays = (C[]) new RemoveRandomWithObject[] {grabArrays[1 - x]}; grabClients = (T[]) new Object[] {grabClients[1 - x]}; reduceWakeupTime(wakeupTime, context); return new RemoveRandomReturn(wakeupTime); } excludeTime = rga.getWakeupTime(context, now); if (excludeTime > 0) { if (wakeupTime > excludeTime) wakeupTime = excludeTime; rga = null; } else { val = rga.removeRandom(excluding, context, now); if (val != null) { if (val.item != null) item = val.item; else { if (wakeupTime > val.wakeupTime) wakeupTime = val.wakeupTime; } } } if (firstRGA != null && firstRGA.isEmpty() && rga != null && rga.isEmpty()) { if (logMINOR) Logger.minor( this, "Removing both on " + this + " : " + firstRGA + " and " + rga + " are empty"); grabArrays = (C[]) new RemoveRandomWithObject[0]; grabClients = (T[]) new Object[0]; } else if (firstRGA != null && firstRGA.isEmpty()) { if (logMINOR) Logger.minor(this, "Removing first: " + firstRGA + " is empty on " + this); grabArrays = (C[]) new RemoveRandomWithObject[] { grabArrays[x] }; // don't use RGA, it may be nulled out grabClients = (T[]) new Object[] {grabClients[x]}; } if (logMINOR) Logger.minor(this, "Returning (two items only) " + item + " for " + rga); if (item == null) { if (grabArrays.length == 0) return null; // Remove this as well reduceWakeupTime(wakeupTime, context); return new RemoveRandomReturn(wakeupTime); } else return new RemoveRandomReturn(item); } } }
private RandomGrabArrayItem removeRandomLimited( RandomGrabArrayItemExclusionList excluding, ClientContext context, long now) { synchronized (root) { /** Count of arrays that have items but didn't return anything because of exclusions */ final int MAX_EXCLUDED = 10; int excluded = 0; while (true) { if (grabArrays.length == 0) return null; int x = context.fastWeakRandom.nextInt(grabArrays.length); RemoveRandomWithObject<T> rga = grabArrays[x]; if (rga == null) { // We handle this in the other cases so we should handle it here. Logger.error(this, "Slot " + x + " is null for client " + grabClients[x]); excluded++; if (excluded > MAX_EXCLUDED) { Logger.normal( this, "Too many sub-arrays are entirely excluded on " + this + " length = " + grabArrays.length, new Exception("error")); return null; } continue; } long excludeTime = rga.getWakeupTime(context, now); if (excludeTime > 0) { excluded++; if (excluded > MAX_EXCLUDED) { Logger.normal( this, "Too many sub-arrays are entirely excluded on " + this + " length = " + grabArrays.length, new Exception("error")); return null; } continue; } if (logMINOR) Logger.minor( this, "Picked " + x + " of " + grabArrays.length + " : " + rga + " on " + this); RandomGrabArrayItem item = null; RemoveRandomReturn val = rga.removeRandom(excluding, context, now); if (val != null && val.item != null) item = val.item; if (logMINOR) Logger.minor( this, "RGA has picked " + x + "/" + grabArrays.length + ": " + item + " rga.isEmpty=" + rga.isEmpty()); // If it is not empty but returns null we exclude it, and count the exclusion. // If it is empty we remove it, and don't count the exclusion. if (item != null) { return item; } else { if (rga.isEmpty()) { if (logMINOR) Logger.minor(this, "Removing grab array " + x + " : " + rga + " (is empty)"); removeElement(x); } else { excluded++; if (excluded > MAX_EXCLUDED) { Logger.normal( this, "Too many sub-arrays are entirely excluded on " + this + " length = " + grabArrays.length, new Exception("error")); return null; } } continue; } } } }
public void run() { long lastDumped = System.currentTimeMillis(); synchronized (jobs) { if (current != null) { if (current.isAlive()) { Logger.error( this, "Already running a thread for " + this + " !!", new Exception("error")); return; } } current = Thread.currentThread(); } try { while (true) { Runnable job = null; synchronized (jobs) { job = checkQueue(); if (job == null) { waiting = true; try { // NB: notify only on adding work or this quits early. jobs.wait(jobTimeout); } catch (InterruptedException e) { // Ignore } waiting = false; job = checkQueue(); if (job == null) { running = false; return; } } } try { if (logMINOR) Logger.minor(this, "Running job " + job); long start = System.currentTimeMillis(); job.run(); long end = System.currentTimeMillis(); if (logMINOR) { Logger.minor(this, "Job " + job + " took " + (end - start) + "ms"); synchronized (timeByJobClasses) { String name = job.toString(); if (name.indexOf('@') > 0) name = name.substring(0, name.indexOf('@')); Long l = timeByJobClasses.get(name); if (l != null) { l = Long.valueOf(l.longValue() + (end - start)); } else { l = Long.valueOf(end - start); } timeByJobClasses.put(name, l); if (logMINOR) { Logger.minor(this, "Total for class " + name + " : " + l); if (System.currentTimeMillis() > (lastDumped + 60 * 1000)) { Iterator i = timeByJobClasses.entrySet().iterator(); while (i.hasNext()) { Map.Entry e = (Map.Entry) i.next(); Logger.minor(this, "Class " + e.getKey() + " : total time " + e.getValue()); } lastDumped = System.currentTimeMillis(); } } } } } catch (Throwable t) { Logger.error(this, "Caught " + t, t); Logger.error(this, "While running " + job + " on " + this); } } } finally { synchronized (jobs) { current = null; running = false; } } }