package net.i2p.router; import net.i2p.util.I2PThread; import net.i2p.util.Log; import net.i2p.util.SystemVersion; /** a do run run run a do run run */ class JobQueueRunner extends I2PThread { private final Log _log; private final RouterContext _context; private volatile boolean _keepRunning; private final int _id; private volatile Job _currentJob; private volatile Job _lastJob; private volatile long _lastBegin; private volatile long _lastEnd; //private volatile int _state; public JobQueueRunner(RouterContext context, int id) { _context = context; _id = id; _keepRunning = true; _log = _context.logManager().getLog(JobQueueRunner.class); setPriority(NORM_PRIORITY + 1); // all createRateStat in JobQueue //_state = 1; } //final int getState() { return _state; } public Job getCurrentJob() { return _currentJob; } public Job getLastJob() { return _lastJob; } public int getRunnerId() { return _id; } public void stopRunning() { _keepRunning = false; } public void startRunning() { _keepRunning = true; } public long getLastBegin() { return _lastBegin; } public long getLastEnd() { return _lastEnd; } public void run() { //_state = 2; long lastActive = _context.clock().now(); while ( (_keepRunning) && (_context.jobQueue().isAlive()) ) { //_state = 3; try { Job job = _context.jobQueue().getNext(); //_state = 4; if (job == null) { //_state = 5; if (_context.router().isAlive()) if (_log.shouldLog(Log.ERROR)) _log.error("getNext returned null - dead?"); continue; } long now = _context.clock().now(); long enqueuedTime = 0; if (job instanceof JobImpl) { //_state = 6; long when = ((JobImpl)job).getMadeReadyOn(); if (when <= 0) { //_state = 7; _log.error("Job was not made ready?! " + job, new Exception("Not made ready?!")); } else { //_state = 8; enqueuedTime = now - when; } } _currentJob = job; _lastJob = null; //_state = 9; if (_log.shouldLog(Log.DEBUG)) _log.debug("Runner " + _id + " running job " + job.getJobId() + ": " + job.getName()); long origStartAfter = job.getTiming().getStartAfter(); long doStart = _context.clock().now(); //_state = 10; job.getTiming().start(); runCurrentJob(); job.getTiming().end(); //_state = 11; long duration = job.getTiming().getActualEnd() - job.getTiming().getActualStart(); long beforeUpdate = _context.clock().now(); //_state = 12; _context.jobQueue().updateStats(job, doStart, origStartAfter, duration); //_state = 13; long diff = _context.clock().now() - beforeUpdate; long lag = doStart - origStartAfter; if (lag < 0) lag = 0; //_context.statManager().addRateData("jobQueue.jobRunnerInactive", betweenJobs, betweenJobs); _context.statManager().addRateData("jobQueue.jobRun", duration, duration); _context.statManager().addRateData("jobQueue.jobLag", lag); _context.statManager().addRateData("jobQueue.jobWait", enqueuedTime, enqueuedTime); if (duration > 1000) { _context.statManager().addRateData("jobQueue.jobRunSlow", duration, duration); if (_log.shouldLog(Log.WARN)) _log.warn("Duration of " + duration + " (lag "+ (doStart-origStartAfter) + ") on job " + _currentJob); } //_state = 14; if (diff > 100) { if (_log.shouldLog(Log.WARN)) _log.warn("Updating statistics for the job took too long [" + diff + "ms]"); } if (_log.shouldLog(Log.DEBUG)) _log.debug("Job duration " + duration + "ms for " + job.getName() + " with lag of " + (doStart-origStartAfter) + "ms"); lastActive = _context.clock().now(); _lastJob = _currentJob; _currentJob = null; _lastEnd = lastActive; //_state = 15; //if ( (jobNum % 10) == 0) // System.gc(); } catch (Throwable t) { _log.log(Log.CRIT, "error running?", t); } } //_state = 16; if (_context.router().isAlive()) _log.log(Log.CRIT, "Queue runner " + _id + " exiting"); _context.jobQueue().removeRunner(_id); //_state = 17; } private void runCurrentJob() { try { //_state = 18; _lastBegin = _context.clock().now(); _currentJob.runJob(); //_state = 19; } catch (OutOfMemoryError oom) { try { if (SystemVersion.isAndroid()) _context.router().shutdown(Router.EXIT_OOM); else fireOOM(oom); } catch (Throwable t) {} } catch (Throwable t) { //_state = 21; _log.log(Log.CRIT, "Error processing job [" + _currentJob.getName() + "] on thread " + _id + ": " + t.getMessage(), t); //if (_log.shouldLog(Log.ERROR)) // _log.error("The above job was enqueued by: ", _currentJob.getAddedBy()); } } }