Console: Remove static StatSummarizer ref, hang off ClientAppManager

This commit is contained in:
zzz
2018-10-08 19:31:54 +00:00
parent 184b6179e5
commit bdd7c35ab3
6 changed files with 116 additions and 48 deletions

View File

@ -833,7 +833,7 @@ public class RouterConsoleRunner implements RouterApp {
} }
} }
Thread t = new I2PAppThread(new StatSummarizer(), "StatSummarizer", true); Thread t = new I2PAppThread(new StatSummarizer(_context), "StatSummarizer", true);
t.setPriority(Thread.NORM_PRIORITY - 1); t.setPriority(Thread.NORM_PRIORITY - 1);
t.start(); t.start();

View File

@ -11,6 +11,9 @@ import java.util.StringTokenizer;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import net.i2p.I2PAppContext;
import net.i2p.app.ClientApp;
import net.i2p.app.ClientAppState;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import static net.i2p.router.web.GraphConstants.*; import static net.i2p.router.web.GraphConstants.*;
@ -32,29 +35,40 @@ import net.i2p.util.SystemVersion;
* *
* @since 0.6.1.13 * @since 0.6.1.13
*/ */
public class StatSummarizer implements Runnable { public class StatSummarizer implements Runnable, ClientApp {
private final RouterContext _context; private final RouterContext _context;
private final Log _log; private final Log _log;
/** list of SummaryListener instances */ /** list of SummaryListener instances */
private final List<SummaryListener> _listeners; private final List<SummaryListener> _listeners;
// TODO remove static instance
private static StatSummarizer _instance;
private static final int MAX_CONCURRENT_PNG = SystemVersion.isARM() ? 2 : 3; private static final int MAX_CONCURRENT_PNG = SystemVersion.isARM() ? 2 : 3;
private final Semaphore _sem; private final Semaphore _sem;
private volatile boolean _isRunning = true; private volatile boolean _isRunning;
private boolean _isDisabled; private volatile Thread _thread;
private Thread _thread; private static final String NAME = "StatSummarizer";
public StatSummarizer() { public StatSummarizer(RouterContext ctx) {
_context = RouterContext.listContexts().get(0); // only summarize one per jvm _context = ctx;
_log = _context.logManager().getLog(getClass()); _log = _context.logManager().getLog(getClass());
_listeners = new CopyOnWriteArrayList<SummaryListener>(); _listeners = new CopyOnWriteArrayList<SummaryListener>();
_instance = this;
_sem = new Semaphore(MAX_CONCURRENT_PNG, true); _sem = new Semaphore(MAX_CONCURRENT_PNG, true);
_context.addShutdownTask(new Shutdown()); _context.addShutdownTask(new Shutdown());
} }
public static StatSummarizer instance() { return _instance; } /**
* @return null if disabled
*/
public static StatSummarizer instance() {
return instance(I2PAppContext.getGlobalContext());
}
/**
* @return null if disabled
* @since 0.0.38
*/
public static StatSummarizer instance(I2PAppContext ctx) {
ClientApp app = ctx.clientAppManager().getRegisteredApp(NAME);
return (app != null) ? (StatSummarizer) app : null;
}
public void run() { public void run() {
// JRobin 1.5.9 crashes these JVMs // JRobin 1.5.9 crashes these JVMs
@ -65,24 +79,29 @@ public class StatSummarizer implements Runnable {
System.getProperty("java.version") + " (" + System.getProperty("java.version") + " (" +
System.getProperty("java.runtime.name") + ' ' + System.getProperty("java.runtime.name") + ' ' +
System.getProperty("java.runtime.version") + ')'); System.getProperty("java.runtime.version") + ')');
_isDisabled = true;
_isRunning = false;
return; return;
} }
_isRunning = true;
boolean isPersistent = _context.getBooleanPropertyDefaultTrue(SummaryListener.PROP_PERSISTENT); boolean isPersistent = _context.getBooleanPropertyDefaultTrue(SummaryListener.PROP_PERSISTENT);
if (!isPersistent) if (!isPersistent)
deleteOldRRDs(); deleteOldRRDs();
_thread = Thread.currentThread(); _thread = Thread.currentThread();
_context.clientAppManager().register(this);
String specs = ""; String specs = "";
try {
while (_isRunning && _context.router().isAlive()) { while (_isRunning && _context.router().isAlive()) {
specs = adjustDatabases(specs); specs = adjustDatabases(specs);
try { Thread.sleep(60*1000); } catch (InterruptedException ie) {} try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
} }
} finally {
_isRunning = false;
_context.clientAppManager().unregister(this);
}
} }
/** @since 0.8.7, public since 0.9.33, was package private */ /** @since 0.0.38 */
public static boolean isDisabled() { public static boolean isDisabled(I2PAppContext ctx) {
return _instance == null || _instance._isDisabled; return ctx.clientAppManager().getRegisteredApp(NAME) == null;
} }
/** /**
@ -90,13 +109,57 @@ public class StatSummarizer implements Runnable {
* See SummaryRenderer.render() * See SummaryRenderer.render()
* @since 0.9.6 * @since 0.9.6
*/ */
static void setDisabled() { static void setDisabled(I2PAppContext ctx) {
if (_instance != null) { StatSummarizer ss = instance(ctx);
_instance._isDisabled = true; if (ss != null)
_instance._isRunning = false; ss.setDisabled();
}
/**
* Disable graph generation until restart
* See SummaryRenderer.render()
* @since 0.9.38
*/
synchronized void setDisabled() {
if (_isRunning) {
_isRunning = false;
Thread t = _thread;
if (t != null)
t.interrupt();
} }
} }
/////// ClientApp methods
/**
* Does nothing, we aren't tracked
* @since 0.9.38
*/
public void startup() {}
/**
* Does nothing, we aren't tracked
* @since 0.9.38
*/
public void shutdown(String[] args) {}
/** @since 0.9.38 */
public ClientAppState getState() {
return ClientAppState.RUNNING;
}
/** @since 0.9.38 */
public String getName() {
return NAME;
}
/** @since 0.9.38 */
public String getDisplayName() {
return "Console stats summarizer";
}
/////// End ClientApp methods
/** /**
* List of SummaryListener instances * List of SummaryListener instances
* @since public since 0.9.33, was package private * @since public since 0.9.33, was package private
@ -206,8 +269,7 @@ public class StatSummarizer implements Runnable {
// at java.lang.Class.forName0(Native Method) // at java.lang.Class.forName0(Native Method)
// at java.lang.Class.forName(Class.java:270) // at java.lang.Class.forName(Class.java:270)
// at sun.font.FontManagerFactory$1.run(FontManagerFactory.java:82) // at sun.font.FontManagerFactory$1.run(FontManagerFactory.java:82)
_isDisabled = true; setDisabled();
_isRunning = false;
String s = "Error rendering - disabling graph generation. Install ttf-dejavu font package?"; String s = "Error rendering - disabling graph generation. Install ttf-dejavu font package?";
_log.logAlways(Log.WARN, s); _log.logAlways(Log.WARN, s);
IOException ioe = new IOException(s); IOException ioe = new IOException(s);
@ -296,8 +358,7 @@ public class StatSummarizer implements Runnable {
// at java.lang.Class.forName0(Native Method) // at java.lang.Class.forName0(Native Method)
// at java.lang.Class.forName(Class.java:270) // at java.lang.Class.forName(Class.java:270)
// at sun.font.FontManagerFactory$1.run(FontManagerFactory.java:82) // at sun.font.FontManagerFactory$1.run(FontManagerFactory.java:82)
_isDisabled = true; setDisabled();
_isRunning = false;
String s = "Error rendering - disabling graph generation. Install ttf-dejavu font package?"; String s = "Error rendering - disabling graph generation. Install ttf-dejavu font package?";
_log.logAlways(Log.WARN, s); _log.logAlways(Log.WARN, s);
IOException ioe = new IOException(s); IOException ioe = new IOException(s);
@ -316,7 +377,7 @@ public class StatSummarizer implements Runnable {
// go to some trouble to see if we have the data for the combined bw graph // go to some trouble to see if we have the data for the combined bw graph
SummaryListener txLsnr = null; SummaryListener txLsnr = null;
SummaryListener rxLsnr = null; SummaryListener rxLsnr = null;
for (SummaryListener lsnr : StatSummarizer.instance().getListeners()) { for (SummaryListener lsnr : getListeners()) {
String title = lsnr.getRate().getRateStat().getName(); String title = lsnr.getRate().getRateStat().getName();
if (title.equals("bw.sendRate")) if (title.equals("bw.sendRate"))
txLsnr = lsnr; txLsnr = lsnr;
@ -396,9 +457,7 @@ public class StatSummarizer implements Runnable {
*/ */
private class Shutdown implements Runnable { private class Shutdown implements Runnable {
public void run() { public void run() {
_isRunning = false; setDisabled();
if (_thread != null)
_thread.interrupt();
for (SummaryListener lsnr : _listeners) { for (SummaryListener lsnr : _listeners) {
// FIXME could cause exceptions if rendering? // FIXME could cause exceptions if rendering?
lsnr.stopListening(); lsnr.stopListening();

View File

@ -289,7 +289,7 @@ class SummaryRenderer {
graph = new RrdGraph(def); graph = new RrdGraph(def);
} catch (NullPointerException npe) { } catch (NullPointerException npe) {
_log.error("Error rendering", npe); _log.error("Error rendering", npe);
StatSummarizer.setDisabled(); StatSummarizer.setDisabled(_context);
throw new IOException("Error rendering - disabling graph generation. Missing font? See http://trac.i2p2.i2p/ticket/915"); throw new IOException("Error rendering - disabling graph generation. Missing font? See http://trac.i2p2.i2p/ticket/915");
} }
int totalWidth = graph.getRrdGraphInfo().getWidth(); int totalWidth = graph.getRrdGraphInfo().getWidth();

View File

@ -147,10 +147,11 @@ public class GraphHelper extends FormHandler {
} }
public String getImages() { public String getImages() {
if (StatSummarizer.isDisabled()) StatSummarizer ss = StatSummarizer.instance(_context);
if (ss == null)
return ""; return "";
try { try {
List<SummaryListener> listeners = StatSummarizer.instance().getListeners(); List<SummaryListener> listeners = ss.getListeners();
TreeSet<SummaryListener> ordered = new TreeSet<SummaryListener>(new AlphaComparator()); TreeSet<SummaryListener> ordered = new TreeSet<SummaryListener>(new AlphaComparator());
ordered.addAll(listeners); ordered.addAll(listeners);
@ -235,9 +236,10 @@ public class GraphHelper extends FormHandler {
* @since 0.9 * @since 0.9
*/ */
public String getSingleStat() { public String getSingleStat() {
try { StatSummarizer ss = StatSummarizer.instance(_context);
if (StatSummarizer.isDisabled()) if (ss == null)
return ""; return "";
try {
if (_stat == null) { if (_stat == null) {
_out.write("No stat specified"); _out.write("No stat specified");
return ""; return "";
@ -249,7 +251,7 @@ public class GraphHelper extends FormHandler {
name = _stat; name = _stat;
displayName = _t("Bandwidth usage"); displayName = _t("Bandwidth usage");
} else { } else {
Set<Rate> rates = StatSummarizer.instance().parseSpecs(_stat); Set<Rate> rates = ss.parseSpecs(_stat);
if (rates.size() != 1) { if (rates.size() != 1) {
_out.write("Graphs not enabled for " + _stat); _out.write("Graphs not enabled for " + _stat);
return ""; return "";
@ -376,7 +378,8 @@ public class GraphHelper extends FormHandler {
private static final int[] times = { 15, 30, 60, 2*60, 5*60, 10*60, 30*60, 60*60, -1 }; private static final int[] times = { 15, 30, 60, 2*60, 5*60, 10*60, 30*60, 60*60, -1 };
public String getForm() { public String getForm() {
if (StatSummarizer.isDisabled()) StatSummarizer ss = StatSummarizer.instance(_context);
if (ss == null)
return ""; return "";
// too hard to use the standard formhandler.jsi / FormHandler.java session nonces // too hard to use the standard formhandler.jsi / FormHandler.java session nonces
// since graphs.jsp needs the refresh value in its <head>. // since graphs.jsp needs the refresh value in its <head>.
@ -440,7 +443,7 @@ public class GraphHelper extends FormHandler {
*/ */
@Override @Override
public String getAllMessages() { public String getAllMessages() {
if (StatSummarizer.isDisabled()) { if (StatSummarizer.isDisabled(_context)) {
addFormError("Graphing not supported with this JVM: " + addFormError("Graphing not supported with this JVM: " +
System.getProperty("java.vendor") + ' ' + System.getProperty("java.vendor") + ' ' +
System.getProperty("java.version") + " (" + System.getProperty("java.version") + " (" +

View File

@ -277,7 +277,7 @@ class SummaryBarRenderer {
.append("</a>\n"); .append("</a>\n");
} }
if (!StatSummarizer.isDisabled()) { if (!StatSummarizer.isDisabled(_context)) {
buf.append("<a href=\"/graphs\" target=\"_top\" title=\"") buf.append("<a href=\"/graphs\" target=\"_top\" title=\"")
.append(_t("Graph router performance")) .append(_t("Graph router performance"))
.append("\">") .append("\">")
@ -822,13 +822,14 @@ class SummaryBarRenderer {
public String renderBandwidthGraphHTML() { public String renderBandwidthGraphHTML() {
if (_helper == null) return ""; if (_helper == null) return "";
StringBuilder buf = new StringBuilder(512); StringBuilder buf = new StringBuilder(512);
if (!StatSummarizer.isDisabled()) if (!StatSummarizer.isDisabled(_context)) {
buf.append("<div id=\"sb_graphcontainer\"><a href=\"/graphs\"><table id=\"sb_bandwidthgraph\">" + buf.append("<div id=\"sb_graphcontainer\"><a href=\"/graphs\"><table id=\"sb_bandwidthgraph\">" +
"<tr title=\"") "<tr title=\"")
.append(_t("Our inbound &amp; outbound traffic for the last 20 minutes")) .append(_t("Our inbound &amp; outbound traffic for the last 20 minutes"))
.append("\"><td><span id=\"sb_graphstats\">") .append("\"><td><span id=\"sb_graphstats\">")
.append(_helper.getSecondKBps()) .append(_helper.getSecondKBps())
.append("Bps</span></td></tr></table></a></div>\n"); .append("Bps</span></td></tr></table></a></div>\n");
}
buf.append("<script src=\"/js/refreshGraph.js\" type=\"text/javascript\" id=\"refreshGraph\" async></script>"); buf.append("<script src=\"/js/refreshGraph.js\" type=\"text/javascript\" id=\"refreshGraph\" async></script>");
return buf.toString(); return buf.toString();
} }

View File

@ -6,14 +6,19 @@
* *
* Do not tag this file for translation. * Do not tag this file for translation.
*/ */
net.i2p.I2PAppContext ctx = net.i2p.I2PAppContext.getGlobalContext();
net.i2p.router.web.StatSummarizer ss = net.i2p.router.web.StatSummarizer.instance(ctx);
if (ss == null) {
response.sendError(403, "Stats disabled");
return;
}
boolean rendered = false; boolean rendered = false;
/**** unused /**** unused
String templateFile = request.getParameter("template"); String templateFile = request.getParameter("template");
if (templateFile != null) { if (templateFile != null) {
java.io.OutputStream cout = response.getOutputStream(); java.io.OutputStream cout = response.getOutputStream();
response.setContentType("image/png"); response.setContentType("image/png");
rendered = net.i2p.router.web.StatSummarizer.instance().renderPng(cout, templateFile); rendered = ss.renderPng(cout, templateFile);
} }
****/ ****/
net.i2p.stat.Rate rate = null; net.i2p.stat.Rate rate = null;
@ -22,7 +27,7 @@ String period = request.getParameter("period");
boolean fakeBw = (stat != null && ("bw.combined".equals(stat))); boolean fakeBw = (stat != null && ("bw.combined".equals(stat)));
net.i2p.stat.RateStat rs = null; net.i2p.stat.RateStat rs = null;
if (stat != null) if (stat != null)
rs = net.i2p.I2PAppContext.getGlobalContext().statManager().getRate(stat); rs = ctx.statManager().getRate(stat);
if ( !rendered && ((rs != null) || fakeBw) ) { if ( !rendered && ((rs != null) || fakeBw) ) {
long per = -1; long per = -1;
try { try {
@ -39,12 +44,12 @@ if ( !rendered && ((rs != null) || fakeBw) ) {
if ("xml".equals(format)) { if ("xml".equals(format)) {
if (!fakeBw) { if (!fakeBw) {
response.setContentType("text/xml"); response.setContentType("text/xml");
rendered = net.i2p.router.web.StatSummarizer.instance().getXML(rate, cout); rendered = ss.getXML(rate, cout);
} }
} else { } else {
response.setContentType("image/png"); response.setContentType("image/png");
// very brief 45 sec expire // very brief 45 sec expire
response.setDateHeader("Expires", net.i2p.I2PAppContext.getGlobalContext().clock().now() + (45*1000)); response.setDateHeader("Expires", ctx.clock().now() + (45*1000));
response.setHeader("Accept-Ranges", "none"); response.setHeader("Accept-Ranges", "none");
// http://jira.codehaus.org/browse/JETTY-1346 // http://jira.codehaus.org/browse/JETTY-1346
// This doesn't actually appear in the response, but it fixes the problem, // This doesn't actually appear in the response, but it fixes the problem,
@ -70,9 +75,9 @@ if ( !rendered && ((rs != null) || fakeBw) ) {
if (request.getParameter("showCredit") != null) if (request.getParameter("showCredit") != null)
showCredit = Boolean.parseBoolean(request.getParameter("showCredit")); showCredit = Boolean.parseBoolean(request.getParameter("showCredit"));
if (fakeBw) if (fakeBw)
rendered = net.i2p.router.web.StatSummarizer.instance().renderRatePng(cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit); rendered = ss.renderRatePng(cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit);
else else
rendered = net.i2p.router.web.StatSummarizer.instance().renderPng(rate, cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit); rendered = ss.renderPng(rate, cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit);
} }
if (rendered) if (rendered)
cout.close(); cout.close();