diff --git a/apps/routerconsole/java/src/net/i2p/router/web/JobQueueHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/JobQueueHelper.java index 633e7db9f..02f18a19a 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/JobQueueHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/JobQueueHelper.java @@ -3,19 +3,28 @@ package net.i2p.router.web; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import net.i2p.data.DataHelper; +import net.i2p.router.Job; +import net.i2p.router.JobStats; public class JobQueueHelper extends HelperBase { - public JobQueueHelper() {} public String getJobQueueSummary() { try { if (_out != null) { - _context.jobQueue().renderStatusHTML(_out); + renderStatusHTML(_out); return ""; } else { ByteArrayOutputStream baos = new ByteArrayOutputStream(32*1024); - _context.jobQueue().renderStatusHTML(new OutputStreamWriter(baos)); + renderStatusHTML(new OutputStreamWriter(baos)); return new String(baos.toByteArray()); } } catch (IOException ioe) { @@ -23,4 +32,147 @@ public class JobQueueHelper extends HelperBase { return ""; } } + + /** + * Moved from JobQueue + * @since 0.8.9 + */ + private void renderStatusHTML(Writer out) throws IOException { + List readyJobs = new ArrayList(8); + List timedJobs = new ArrayList(128); + List activeJobs = new ArrayList(8); + List justFinishedJobs = new ArrayList(8); + + int numRunners = _context.jobQueue().getJobs(readyJobs, timedJobs, activeJobs, justFinishedJobs); + + StringBuilder buf = new StringBuilder(32*1024); + buf.append("

I2P Job Queue

Job runners: ").append(numRunners); + buf.append("
\n"); + + long now = _context.clock().now(); + + buf.append("
Active jobs: ").append(activeJobs.size()).append("
    \n"); + for (int i = 0; i < activeJobs.size(); i++) { + Job j = activeJobs.get(i); + buf.append("
  1. [started ").append(DataHelper.formatDuration(now-j.getTiming().getStartAfter())).append(" ago]: "); + buf.append(j.toString()).append("
  2. \n"); + } + buf.append("
\n"); + buf.append("
Just finished jobs: ").append(justFinishedJobs.size()).append("
    \n"); + for (int i = 0; i < justFinishedJobs.size(); i++) { + Job j = justFinishedJobs.get(i); + buf.append("
  1. [finished ").append(DataHelper.formatDuration(now-j.getTiming().getActualEnd())).append(" ago]: "); + buf.append(j.toString()).append("
  2. \n"); + } + buf.append("
\n"); + buf.append("
Ready/waiting jobs: ").append(readyJobs.size()).append("
    \n"); + for (int i = 0; i < readyJobs.size(); i++) { + Job j = readyJobs.get(i); + buf.append("
  1. [waiting "); + buf.append(DataHelper.formatDuration(now-j.getTiming().getStartAfter())); + buf.append("]: "); + buf.append(j.toString()).append("
  2. \n"); + } + buf.append("
\n"); + out.flush(); + + buf.append("
Scheduled jobs: ").append(timedJobs.size()).append("
    \n"); + TreeMap ordered = new TreeMap(); + for (int i = 0; i < timedJobs.size(); i++) { + Job j = timedJobs.get(i); + ordered.put(Long.valueOf(j.getTiming().getStartAfter()), j); + } + for (Job j : ordered.values()) { + long time = j.getTiming().getStartAfter() - now; + buf.append("
  1. ").append(j.getName()).append(" in "); + buf.append(DataHelper.formatDuration(time)).append("
  2. \n"); + } + buf.append("
\n"); + + out.flush(); + + getJobStats(buf); + + out.flush(); + + out.write(buf.toString()); + } + + /** + * Render the HTML for the job stats. + * Moved from JobQueue + * @since 0.8.9 + */ + private void getJobStats(StringBuilder buf) { + buf.append("\n" + + "" + + "" + + "\n"); + long totRuns = 0; + long totExecTime = 0; + long avgExecTime = 0; + long maxExecTime = -1; + long minExecTime = -1; + long totPendingTime = 0; + long avgPendingTime = 0; + long maxPendingTime = -1; + long minPendingTime = -1; + + List tstats = new ArrayList(_context.jobQueue().getJobStats()); + Collections.sort(tstats, new JobStatsComparator()); + + for (JobStats stats : tstats) { + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append("\n"); + totRuns += stats.getRuns(); + totExecTime += stats.getTotalTime(); + if (stats.getMaxTime() > maxExecTime) + maxExecTime = stats.getMaxTime(); + if ( (minExecTime < 0) || (minExecTime > stats.getMinTime()) ) + minExecTime = stats.getMinTime(); + totPendingTime += stats.getTotalPendingTime(); + if (stats.getMaxPendingTime() > maxPendingTime) + maxPendingTime = stats.getMaxPendingTime(); + if ( (minPendingTime < 0) || (minPendingTime > stats.getMinPendingTime()) ) + minPendingTime = stats.getMinPendingTime(); + } + + if (totRuns != 0) { + if (totExecTime != 0) + avgExecTime = totExecTime / totRuns; + if (totPendingTime != 0) + avgPendingTime = totPendingTime / totRuns; + } + + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append("
JobRunsTimeAvgMaxMinPendingAvgMaxMin
").append(stats.getName()).append("").append(stats.getRuns()).append("").append(stats.getTotalTime()).append("").append(stats.getAvgTime()).append("").append(stats.getMaxTime()).append("").append(stats.getMinTime()).append("").append(stats.getTotalPendingTime()).append("").append(stats.getAvgPendingTime()).append("").append(stats.getMaxPendingTime()).append("").append(stats.getMinPendingTime()).append("
").append("SUMMARY").append("").append(totRuns).append("").append(totExecTime).append("").append(avgExecTime).append("").append(maxExecTime).append("").append(minExecTime).append("").append(totPendingTime).append("").append(avgPendingTime).append("").append(maxPendingTime).append("").append(minPendingTime).append("
\n"); + } + + /** @since 0.8.9 */ + private static class JobStatsComparator implements Comparator { + public int compare(JobStats l, JobStats r) { + return l.getName().compareTo(r.getName()); + } + } + } diff --git a/history.txt b/history.txt index 4b5418954..479ff3eb0 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,6 @@ 2011-09-06 zzz + * Console: Move configservice.jsp rendering code from + the router to the console * Crypto: Rework use of SHA256 for efficiency and to avoid clogging the Hash cache with one-time hashes, and avoiding the global cache lock. diff --git a/router/java/src/net/i2p/router/JobQueue.java b/router/java/src/net/i2p/router/JobQueue.java index 8cd15c90e..b78f1a53f 100644 --- a/router/java/src/net/i2p/router/JobQueue.java +++ b/router/java/src/net/i2p/router/JobQueue.java @@ -609,184 +609,47 @@ public class JobQueue { public void dropped() {} } - //// - // the remainder are utility methods for dumping status info - //// - - public void renderStatusHTML(Writer out) throws IOException { - List readyJobs = null; - List timedJobs = null; - List activeJobs = new ArrayList(RUNNERS); - List justFinishedJobs = new ArrayList(RUNNERS); - //out.write("\n"); - out.flush(); - - //int states[] = null; - int numRunners = 0; - - { - //states = new int[_queueRunners.size()]; - int i = 0; - for (Iterator iter = _queueRunners.values().iterator(); iter.hasNext(); i++) { - JobQueueRunner runner = iter.next(); - //states[i] = runner.getState(); - Job job = runner.getCurrentJob(); - if (job != null) { - activeJobs.add(job); - } else { - job = runner.getLastJob(); - if (job != null) - justFinishedJobs.add(job); - } + /** + * Dump the current state. + * For the router console jobs status page. + * + * @param readyJobs out parameter + * @param timedJobs out parameter + * @param activeJobs out parameter + * @param justFinishedJobs out parameter + * @return number of job runners + * @since 0.8.9 + */ + public int getJobs(Collection readyJobs, Collection timedJobs, + Collection activeJobs, Collection justFinishedJobs) { + for (JobQueueRunner runner :_queueRunners.values()) { + Job job = runner.getCurrentJob(); + if (job != null) { + activeJobs.add(job); + } else { + job = runner.getLastJob(); + if (job != null) + justFinishedJobs.add(job); } - numRunners = _queueRunners.size(); } - -/******* - StringBuilder str = new StringBuilder(128); - str.append("\n"); - str.append("\n"); - out.write(str.toString()); - out.flush(); -*******/ - synchronized (_jobLock) { - readyJobs = new ArrayList(_readyJobs); - timedJobs = new ArrayList(_timedJobs); + readyJobs.addAll(_readyJobs); + timedJobs.addAll(_timedJobs); } - //out.write("\n"); - //out.flush(); - - StringBuilder buf = new StringBuilder(32*1024); - buf.append("

I2P Job Queue

Job runners: ").append(numRunners); - //buf.append(" [states="); - //if (states != null) - // for (int i = 0; i < states.length; i++) - // buf.append(states[i]).append(" "); - //buf.append(']'); - buf.append("
\n"); - - long now = _context.clock().now(); - - buf.append("
Active jobs: ").append(activeJobs.size()).append("
    \n"); - for (int i = 0; i < activeJobs.size(); i++) { - Job j = activeJobs.get(i); - buf.append("
  1. [started ").append(DataHelper.formatDuration(now-j.getTiming().getStartAfter())).append(" ago]: "); - buf.append(j.toString()).append("
  2. \n"); - } - buf.append("
\n"); - buf.append("
Just finished jobs: ").append(justFinishedJobs.size()).append("
    \n"); - for (int i = 0; i < justFinishedJobs.size(); i++) { - Job j = justFinishedJobs.get(i); - buf.append("
  1. [finished ").append(DataHelper.formatDuration(now-j.getTiming().getActualEnd())).append(" ago]: "); - buf.append(j.toString()).append("
  2. \n"); - } - buf.append("
\n"); - buf.append("
Ready/waiting jobs: ").append(readyJobs.size()).append("
    \n"); - for (int i = 0; i < readyJobs.size(); i++) { - Job j = readyJobs.get(i); - buf.append("
  1. [waiting "); - buf.append(DataHelper.formatDuration(now-j.getTiming().getStartAfter())); - buf.append("]: "); - buf.append(j.toString()).append("
  2. \n"); - } - buf.append("
\n"); - out.flush(); - - buf.append("
Scheduled jobs: ").append(timedJobs.size()).append("
    \n"); - TreeMap ordered = new TreeMap(); - for (int i = 0; i < timedJobs.size(); i++) { - Job j = timedJobs.get(i); - ordered.put(Long.valueOf(j.getTiming().getStartAfter()), j); - } - for (Iterator iter = ordered.values().iterator(); iter.hasNext(); ) { - Job j = iter.next(); - long time = j.getTiming().getStartAfter() - now; - buf.append("
  1. ").append(j.getName()).append(" in "); - buf.append(DataHelper.formatDuration(time)).append("
  2. \n"); - } - buf.append("
\n"); - - //out.write("\n"); - out.flush(); - - getJobStats(buf); - - //out.write("\n"); - out.flush(); - - out.write(buf.toString()); + return _queueRunners.size(); } - - /** render the HTML for the job stats */ - private void getJobStats(StringBuilder buf) { - buf.append("\n" + - "" + - "" + - "\n"); - long totRuns = 0; - long totExecTime = 0; - long avgExecTime = 0; - long maxExecTime = -1; - long minExecTime = -1; - long totPendingTime = 0; - long avgPendingTime = 0; - long maxPendingTime = -1; - long minPendingTime = -1; - TreeMap tstats = new TreeMap(_jobStats); - - for (Iterator iter = tstats.values().iterator(); iter.hasNext(); ) { - JobStats stats = iter.next(); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append("\n"); - totRuns += stats.getRuns(); - totExecTime += stats.getTotalTime(); - if (stats.getMaxTime() > maxExecTime) - maxExecTime = stats.getMaxTime(); - if ( (minExecTime < 0) || (minExecTime > stats.getMinTime()) ) - minExecTime = stats.getMinTime(); - totPendingTime += stats.getTotalPendingTime(); - if (stats.getMaxPendingTime() > maxPendingTime) - maxPendingTime = stats.getMaxPendingTime(); - if ( (minPendingTime < 0) || (minPendingTime > stats.getMinPendingTime()) ) - minPendingTime = stats.getMinPendingTime(); - } + /** + * Current job stats. + * For the router console jobs status page. + * + * @since 0.8.9 + */ + public Collection getJobStats() { + return Collections.unmodifiableCollection(_jobStats.values()); + } - if (totRuns != 0) { - if (totExecTime != 0) - avgExecTime = totExecTime / totRuns; - if (totPendingTime != 0) - avgPendingTime = totPendingTime / totRuns; - } - - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append("
JobRunsTimeAvgMaxMinPendingAvgMaxMin
").append(stats.getName()).append("").append(stats.getRuns()).append("").append(stats.getTotalTime()).append("").append(stats.getAvgTime()).append("").append(stats.getMaxTime()).append("").append(stats.getMinTime()).append("").append(stats.getTotalPendingTime()).append("").append(stats.getAvgPendingTime()).append("").append(stats.getMaxPendingTime()).append("").append(stats.getMinPendingTime()).append("
").append("SUMMARY").append("").append(totRuns).append("").append(totExecTime).append("").append(avgExecTime).append("").append(maxExecTime).append("").append(minExecTime).append("").append(totPendingTime).append("").append(avgPendingTime).append("").append(maxPendingTime).append("").append(minPendingTime).append("
\n"); + /** @deprecated moved to router console */ + public void renderStatusHTML(Writer out) throws IOException { } } diff --git a/router/java/src/net/i2p/router/JobStats.java b/router/java/src/net/i2p/router/JobStats.java index f9cfdc9cc..eadcbf235 100644 --- a/router/java/src/net/i2p/router/JobStats.java +++ b/router/java/src/net/i2p/router/JobStats.java @@ -2,8 +2,11 @@ package net.i2p.router; import net.i2p.data.DataHelper; -/** glorified struct to contain basic job stats */ -class JobStats { +/** + * Glorified struct to contain basic job stats. + * Public for router console only. + */ +public class JobStats { private final String _job; private volatile long _numRuns; private volatile long _totalTime;