2005-12-09 08:05:44 +00:00
|
|
|
package net.i2p.router.web;
|
|
|
|
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.OutputStreamWriter;
|
2011-09-06 15:02:28 +00:00
|
|
|
import java.io.Writer;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.Comparator;
|
|
|
|
import java.util.List;
|
2005-12-09 08:05:44 +00:00
|
|
|
|
2011-09-06 15:02:28 +00:00
|
|
|
import net.i2p.data.DataHelper;
|
|
|
|
import net.i2p.router.Job;
|
|
|
|
import net.i2p.router.JobStats;
|
2013-01-12 18:13:19 +00:00
|
|
|
import net.i2p.util.ObjectCounter;
|
2005-12-09 08:05:44 +00:00
|
|
|
|
2009-01-29 02:16:18 +00:00
|
|
|
public class JobQueueHelper extends HelperBase {
|
2005-12-09 08:05:44 +00:00
|
|
|
|
2013-01-12 18:13:19 +00:00
|
|
|
private static final int MAX_JOBS = 50;
|
|
|
|
|
2005-12-09 08:05:44 +00:00
|
|
|
public String getJobQueueSummary() {
|
|
|
|
try {
|
|
|
|
if (_out != null) {
|
2011-09-06 15:02:28 +00:00
|
|
|
renderStatusHTML(_out);
|
2005-12-09 08:05:44 +00:00
|
|
|
return "";
|
|
|
|
} else {
|
|
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(32*1024);
|
2011-09-06 15:02:28 +00:00
|
|
|
renderStatusHTML(new OutputStreamWriter(baos));
|
2005-12-09 08:05:44 +00:00
|
|
|
return new String(baos.toByteArray());
|
|
|
|
}
|
|
|
|
} catch (IOException ioe) {
|
|
|
|
ioe.printStackTrace();
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
2011-09-06 15:02:28 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Moved from JobQueue
|
|
|
|
* @since 0.8.9
|
|
|
|
*/
|
|
|
|
private void renderStatusHTML(Writer out) throws IOException {
|
|
|
|
List<Job> readyJobs = new ArrayList(8);
|
|
|
|
List<Job> timedJobs = new ArrayList(128);
|
|
|
|
List<Job> activeJobs = new ArrayList(8);
|
|
|
|
List<Job> justFinishedJobs = new ArrayList(8);
|
|
|
|
|
|
|
|
int numRunners = _context.jobQueue().getJobs(readyJobs, timedJobs, activeJobs, justFinishedJobs);
|
|
|
|
|
|
|
|
StringBuilder buf = new StringBuilder(32*1024);
|
2013-01-12 18:13:19 +00:00
|
|
|
buf.append("<b><div class=\"joblog\"><h3>I2P Job Queue</h3><br><div class=\"wideload\">Job runners: ").append(numRunners);
|
2011-09-06 15:02:28 +00:00
|
|
|
buf.append("</b><br>\n");
|
|
|
|
|
|
|
|
long now = _context.clock().now();
|
|
|
|
|
|
|
|
buf.append("<hr><b>Active jobs: ").append(activeJobs.size()).append("</b><ol>\n");
|
|
|
|
for (int i = 0; i < activeJobs.size(); i++) {
|
|
|
|
Job j = activeJobs.get(i);
|
2011-09-06 15:29:49 +00:00
|
|
|
buf.append("<li>[started ").append(DataHelper.formatDuration2(now-j.getTiming().getStartAfter())).append(" ago]: ");
|
2011-09-06 15:02:28 +00:00
|
|
|
buf.append(j.toString()).append("</li>\n");
|
|
|
|
}
|
|
|
|
buf.append("</ol>\n");
|
2013-01-12 18:13:19 +00:00
|
|
|
|
2011-09-06 15:02:28 +00:00
|
|
|
buf.append("<hr><b>Just finished jobs: ").append(justFinishedJobs.size()).append("</b><ol>\n");
|
|
|
|
for (int i = 0; i < justFinishedJobs.size(); i++) {
|
|
|
|
Job j = justFinishedJobs.get(i);
|
2011-09-06 15:29:49 +00:00
|
|
|
buf.append("<li>[finished ").append(DataHelper.formatDuration2(now-j.getTiming().getActualEnd())).append(" ago]: ");
|
2011-09-06 15:02:28 +00:00
|
|
|
buf.append(j.toString()).append("</li>\n");
|
|
|
|
}
|
|
|
|
buf.append("</ol>\n");
|
2013-01-12 18:13:19 +00:00
|
|
|
|
2011-09-06 15:02:28 +00:00
|
|
|
buf.append("<hr><b>Ready/waiting jobs: ").append(readyJobs.size()).append("</b><ol>\n");
|
2013-01-12 18:13:19 +00:00
|
|
|
ObjectCounter<String> counter = new ObjectCounter();
|
2011-09-06 15:02:28 +00:00
|
|
|
for (int i = 0; i < readyJobs.size(); i++) {
|
|
|
|
Job j = readyJobs.get(i);
|
2013-01-12 18:13:19 +00:00
|
|
|
counter.increment(j.getName());
|
|
|
|
if (i >= MAX_JOBS)
|
|
|
|
continue;
|
2011-09-06 15:02:28 +00:00
|
|
|
buf.append("<li>[waiting ");
|
2011-09-06 15:29:49 +00:00
|
|
|
buf.append(DataHelper.formatDuration2(now-j.getTiming().getStartAfter()));
|
2011-09-06 15:02:28 +00:00
|
|
|
buf.append("]: ");
|
|
|
|
buf.append(j.toString()).append("</li>\n");
|
|
|
|
}
|
|
|
|
buf.append("</ol>\n");
|
2013-01-12 18:13:19 +00:00
|
|
|
getJobCounts(buf, counter);
|
|
|
|
out.write(buf.toString());
|
|
|
|
buf.setLength(0);
|
2011-09-06 15:02:28 +00:00
|
|
|
|
|
|
|
buf.append("<hr><b>Scheduled jobs: ").append(timedJobs.size()).append("</b><ol>\n");
|
2012-05-23 16:37:43 +00:00
|
|
|
long prev = Long.MIN_VALUE;
|
2013-01-12 18:13:19 +00:00
|
|
|
counter.clear();
|
|
|
|
for (int i = 0; i < timedJobs.size(); i++) {
|
|
|
|
Job j = timedJobs.get(i);
|
|
|
|
counter.increment(j.getName());
|
|
|
|
if (i >= MAX_JOBS)
|
|
|
|
continue;
|
2011-09-06 15:02:28 +00:00
|
|
|
long time = j.getTiming().getStartAfter() - now;
|
|
|
|
buf.append("<li>").append(j.getName()).append(" in ");
|
2012-05-23 16:37:43 +00:00
|
|
|
buf.append(DataHelper.formatDuration2(time));
|
|
|
|
if (time < 0)
|
|
|
|
buf.append(" <b>DELAYED</b>");
|
|
|
|
if (time < prev)
|
|
|
|
buf.append(" <b>** OUT OF ORDER **</b>");
|
|
|
|
prev = time;
|
|
|
|
buf.append("</li>\n");
|
2011-09-06 15:02:28 +00:00
|
|
|
}
|
|
|
|
buf.append("</ol></div>\n");
|
2013-01-12 18:13:19 +00:00
|
|
|
getJobCounts(buf, counter);
|
|
|
|
out.write(buf.toString());
|
|
|
|
buf.setLength(0);
|
2011-09-06 15:02:28 +00:00
|
|
|
|
2013-01-12 18:13:19 +00:00
|
|
|
buf.append("<hr><b>Total Job Stats</b>\n");
|
2011-09-06 15:02:28 +00:00
|
|
|
getJobStats(buf);
|
|
|
|
out.write(buf.toString());
|
|
|
|
}
|
|
|
|
|
2013-01-12 18:13:19 +00:00
|
|
|
/** @since 0.9.5 */
|
|
|
|
private static void getJobCounts(StringBuilder buf, ObjectCounter<String> counter) {
|
|
|
|
List<String> names = new ArrayList(counter.objects());
|
|
|
|
if (names.size() < 4)
|
|
|
|
return;
|
|
|
|
buf.append("<table style=\"width: 30%; margin-left: 100px;\">\n" +
|
|
|
|
"<tr><th>Job</th><th>Queued<th>");
|
|
|
|
Collections.sort(names, new JobCountComparator(counter));
|
|
|
|
for (String name : names) {
|
|
|
|
buf.append("<tr><td>").append(name)
|
|
|
|
.append("</td><td>").append(counter.count(name))
|
|
|
|
.append("</td></tr>\n");
|
|
|
|
}
|
|
|
|
buf.append("</table>\n");
|
|
|
|
}
|
|
|
|
|
2011-09-06 15:02:28 +00:00
|
|
|
/**
|
|
|
|
* Render the HTML for the job stats.
|
|
|
|
* Moved from JobQueue
|
|
|
|
* @since 0.8.9
|
|
|
|
*/
|
|
|
|
private void getJobStats(StringBuilder buf) {
|
|
|
|
buf.append("<table>\n" +
|
|
|
|
"<tr><th>Job</th><th>Runs</th>" +
|
|
|
|
"<th>Time</th><th><i>Avg</i></th><th><i>Max</i></th><th><i>Min</i></th>" +
|
|
|
|
"<th>Pending</th><th><i>Avg</i></th><th><i>Max</i></th><th><i>Min</i></th></tr>\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<JobStats> tstats = new ArrayList(_context.jobQueue().getJobStats());
|
|
|
|
Collections.sort(tstats, new JobStatsComparator());
|
|
|
|
|
|
|
|
for (JobStats stats : tstats) {
|
|
|
|
buf.append("<tr>");
|
|
|
|
buf.append("<td><b>").append(stats.getName()).append("</b></td>");
|
|
|
|
buf.append("<td align=\"right\">").append(stats.getRuns()).append("</td>");
|
2011-09-06 15:29:49 +00:00
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(stats.getTotalTime())).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(stats.getAvgTime())).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(stats.getMaxTime())).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(stats.getMinTime())).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(stats.getTotalPendingTime())).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(stats.getAvgPendingTime())).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(stats.getMaxPendingTime())).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(stats.getMinPendingTime())).append("</td>");
|
2011-09-06 15:02:28 +00:00
|
|
|
buf.append("</tr>\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("<tr class=\"tablefooter\">");
|
|
|
|
buf.append("<td><b>").append("SUMMARY").append("</b></td>");
|
|
|
|
buf.append("<td align=\"right\">").append(totRuns).append("</td>");
|
2011-09-06 15:29:49 +00:00
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(totExecTime)).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(avgExecTime)).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(maxExecTime)).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(minExecTime)).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(totPendingTime)).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(avgPendingTime)).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(maxPendingTime)).append("</td>");
|
|
|
|
buf.append("<td align=\"right\">").append(DataHelper.formatDuration2(minPendingTime)).append("</td>");
|
2011-09-06 15:02:28 +00:00
|
|
|
buf.append("</tr></table></div>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @since 0.8.9 */
|
|
|
|
private static class JobStatsComparator implements Comparator<JobStats> {
|
|
|
|
public int compare(JobStats l, JobStats r) {
|
|
|
|
return l.getName().compareTo(r.getName());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-12 18:13:19 +00:00
|
|
|
/** @since 0.9.5 */
|
|
|
|
private static class JobCountComparator implements Comparator<String> {
|
|
|
|
private final ObjectCounter<String> _counter;
|
|
|
|
|
|
|
|
public JobCountComparator(ObjectCounter<String> counter) {
|
|
|
|
_counter = counter;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int compare(String l, String r) {
|
|
|
|
// reverse
|
|
|
|
int lc = _counter.count(l);
|
|
|
|
int rc = _counter.count(r);
|
|
|
|
if (lc > rc)
|
|
|
|
return -1;
|
|
|
|
if (lc < rc)
|
|
|
|
return 1;
|
|
|
|
return l.compareTo(r);
|
|
|
|
}
|
|
|
|
}
|
2005-12-09 08:05:44 +00:00
|
|
|
}
|