diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NetDbHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/NetDbHelper.java index 1e68254c32a58e04f44d88fc5d200879146fde36..1cb635ad06825b8642cabc4de739ec8131a12f51 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbHelper.java @@ -2,11 +2,14 @@ package net.i2p.router.web; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; import net.i2p.router.RouterContext; public class NetDbHelper { private RouterContext _context; + private Writer _out; /** * Configure this bean to query a particular router context * @@ -23,13 +26,21 @@ public class NetDbHelper { public NetDbHelper() {} + public void setWriter(Writer writer) { _out = writer; } + public String getNetDbSummary() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(32*1024); try { - _context.netDb().renderStatusHTML(baos); + if (_out != null) { + _context.netDb().renderStatusHTML(_out); + return ""; + } else { + ByteArrayOutputStream baos = new ByteArrayOutputStream(32*1024); + _context.netDb().renderStatusHTML(new OutputStreamWriter(baos)); + return new String(baos.toByteArray()); + } } catch (IOException ioe) { ioe.printStackTrace(); + return ""; } - return new String(baos.toByteArray()); } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/OldConsoleHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/OldConsoleHelper.java index 88f4c86c6e572deec795786c9b71fb1325a02a0d..c6d9a743090c1e1a7d44138b32cf420113425589 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/OldConsoleHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/OldConsoleHelper.java @@ -2,6 +2,8 @@ package net.i2p.router.web; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; import java.util.List; import net.i2p.router.RouterContext; @@ -9,6 +11,7 @@ import net.i2p.router.admin.StatsGenerator; public class OldConsoleHelper { private RouterContext _context; + private Writer _out; /** * Configure this bean to query a particular router context * @@ -25,11 +28,20 @@ public class OldConsoleHelper { public OldConsoleHelper() {} + public void setWriter(Writer writer) { + _out = writer; + } + public String getConsole() { try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(128*1024); - _context.router().renderStatusHTML(baos); - return baos.toString(); + if (_out != null) { + _context.router().renderStatusHTML(_out); + return ""; + } else { + ByteArrayOutputStream baos = new ByteArrayOutputStream(128*1024); + _context.router().renderStatusHTML(new OutputStreamWriter(baos)); + return baos.toString(); + } } catch (IOException ioe) { return "<b>Error rending the console</b>"; } @@ -38,9 +50,14 @@ public class OldConsoleHelper { public String getStats() { StatsGenerator gen = new StatsGenerator(_context); try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(32*1024); - gen.generateStatsPage(baos); - return baos.toString(); + if (_out != null) { + gen.generateStatsPage(_out); + return ""; + } else { + ByteArrayOutputStream baos = new ByteArrayOutputStream(32*1024); + gen.generateStatsPage(new OutputStreamWriter(baos)); + return baos.toString(); + } } catch (IOException ioe) { return "<b>Error rending the console</b>"; } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ProfilesHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ProfilesHelper.java index d8b0b5b96c36a41162314b902ef7a8dd029e3cea..4db1010a570d160d296da60c1cf02d907d10a195 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ProfilesHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ProfilesHelper.java @@ -2,6 +2,7 @@ package net.i2p.router.web; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; import net.i2p.router.RouterContext; @@ -26,7 +27,7 @@ public class ProfilesHelper { public String getProfileSummary() { ByteArrayOutputStream baos = new ByteArrayOutputStream(16*1024); try { - _context.profileOrganizer().renderStatusHTML(baos); + _context.profileOrganizer().renderStatusHTML(new OutputStreamWriter(baos)); } catch (IOException ioe) { ioe.printStackTrace(); } @@ -36,7 +37,7 @@ public class ProfilesHelper { public String getShitlistSummary() { ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024); try { - _context.shitlist().renderStatusHTML(baos); + _context.shitlist().renderStatusHTML(new OutputStreamWriter(baos)); } catch (IOException ioe) { ioe.printStackTrace(); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java index e55ff9683485eb6155287bdd367b56e53327fd31..5d920fa07047e420655040c58b3f9969f36b2b00 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -2,6 +2,7 @@ package net.i2p.router.web; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; import java.text.DecimalFormat; import net.i2p.data.DataHelper; @@ -334,7 +335,7 @@ public class SummaryHelper { public String getDestinations() { ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); try { - _context.clientManager().renderStatusHTML(baos); + _context.clientManager().renderStatusHTML(new OutputStreamWriter(baos)); return new String(baos.toByteArray()); } catch (IOException ioe) { _context.logManager().getLog(SummaryHelper.class).error("Error rendering client info", ioe); @@ -397,8 +398,7 @@ public class SummaryHelper { if (_context == null) return "0ms"; - Rate delayRate = _context.statManager().getRate("transport.sendProcessingTime").getRate(60*1000); - return ((int)delayRate.getAverageValue()) + "ms"; + return _context.throttle().getMessageDelay() + "ms"; } /** @@ -410,7 +410,6 @@ public class SummaryHelper { if (_context == null) return "0ms"; - Rate lagRate = _context.statManager().getRate("tunnel.testSuccessTime").getRate(10*60*1000); - return ((int)lagRate.getAverageValue()) + "ms"; + return _context.throttle().getTunnelLag() + "ms"; } } \ No newline at end of file diff --git a/apps/routerconsole/jsp/netdb.jsp b/apps/routerconsole/jsp/netdb.jsp index aac78a4d15d6ca3e18f7a4e11609c302caf1ea8c..0933c7b22cde553b29b6f59bf6bdb20832c7df0c 100644 --- a/apps/routerconsole/jsp/netdb.jsp +++ b/apps/routerconsole/jsp/netdb.jsp @@ -13,6 +13,7 @@ <div class="main" id="main"> <jsp:useBean class="net.i2p.router.web.NetDbHelper" id="netdbHelper" scope="request" /> <jsp:setProperty name="netdbHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" /> + <jsp:setProperty name="netdbHelper" property="writer" value="<%=out%>" /> <jsp:getProperty name="netdbHelper" property="netDbSummary" /> </div> diff --git a/apps/routerconsole/jsp/oldconsole.jsp b/apps/routerconsole/jsp/oldconsole.jsp index bd501a471a103c01358aa5ce78fb7c419607fb50..3d1ec31cd0762b43fccc3b4b512c2980060f15e5 100644 --- a/apps/routerconsole/jsp/oldconsole.jsp +++ b/apps/routerconsole/jsp/oldconsole.jsp @@ -12,6 +12,7 @@ <jsp:useBean class="net.i2p.router.web.OldConsoleHelper" id="conhelper" scope="request" /> <jsp:setProperty name="conhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" /> +<jsp:setProperty name="conhelper" property="writer" value="<%=out%>" /> <div class="main" id="main"> <jsp:getProperty name="conhelper" property="console" /> diff --git a/apps/routerconsole/jsp/oldstats.jsp b/apps/routerconsole/jsp/oldstats.jsp index bf19e4cc4d1c56ea5c9ad2cc0eacdeb9be349c34..15a39fc53a340203a99487ca862e920a66b21a44 100644 --- a/apps/routerconsole/jsp/oldstats.jsp +++ b/apps/routerconsole/jsp/oldstats.jsp @@ -12,6 +12,7 @@ <jsp:useBean class="net.i2p.router.web.OldConsoleHelper" id="oldhelper" scope="request" /> <jsp:setProperty name="oldhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" /> +<jsp:setProperty name="oldhelper" property="writer" value="<%=out%>" /> <div class="main" id="main"> <jsp:getProperty name="oldhelper" property="stats" /> diff --git a/router/java/src/net/i2p/router/ClientManagerFacade.java b/router/java/src/net/i2p/router/ClientManagerFacade.java index 980e6aeea322d79943b186e9f11bc61118b755ff..de3b8e51c5658143eb4932344726e5dbb175c4d0 100644 --- a/router/java/src/net/i2p/router/ClientManagerFacade.java +++ b/router/java/src/net/i2p/router/ClientManagerFacade.java @@ -9,7 +9,7 @@ package net.i2p.router; */ import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import net.i2p.data.Destination; import net.i2p.data.Hash; @@ -70,7 +70,7 @@ public abstract class ClientManagerFacade implements Service { * */ public abstract SessionConfig getClientSessionConfig(Destination dest); - public void renderStatusHTML(OutputStream out) throws IOException { } + public void renderStatusHTML(Writer out) throws IOException { } } class DummyClientManagerFacade extends ClientManagerFacade { diff --git a/router/java/src/net/i2p/router/CommSystemFacade.java b/router/java/src/net/i2p/router/CommSystemFacade.java index 5c6f42878afeac76f66934729f4646f7d9ee89ad..9a03ebcb914f9b6813051df0bc7cf9786bd53f01 100644 --- a/router/java/src/net/i2p/router/CommSystemFacade.java +++ b/router/java/src/net/i2p/router/CommSystemFacade.java @@ -9,7 +9,7 @@ package net.i2p.router; */ import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -23,7 +23,7 @@ import java.util.Set; public abstract class CommSystemFacade implements Service { public abstract void processMessage(OutNetMessage msg); - public void renderStatusHTML(OutputStream out) throws IOException { } + public void renderStatusHTML(Writer out) throws IOException { } /** Create the set of RouterAddress structures based on the router's config */ public Set createAddresses() { return new HashSet(); } diff --git a/router/java/src/net/i2p/router/JobQueue.java b/router/java/src/net/i2p/router/JobQueue.java index c714d12858479c634e0fc541c808809fd52d5d1b..beee90f381f63c279b1eb7863de8e3b1d3713ead 100644 --- a/router/java/src/net/i2p/router/JobQueue.java +++ b/router/java/src/net/i2p/router/JobQueue.java @@ -9,7 +9,7 @@ package net.i2p.router; */ import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -558,18 +558,18 @@ public class JobQueue { // the remainder are utility methods for dumping status info //// - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { ArrayList readyJobs = null; ArrayList timedJobs = null; ArrayList activeJobs = new ArrayList(1); ArrayList justFinishedJobs = new ArrayList(4); - out.write("<!-- jobQueue rendering -->\n".getBytes()); + out.write("<!-- jobQueue rendering -->\n"); out.flush(); synchronized (_readyJobs) { readyJobs = new ArrayList(_readyJobs); } - out.write("<!-- jobQueue rendering: after readyJobs sync -->\n".getBytes()); + out.write("<!-- jobQueue rendering: after readyJobs sync -->\n"); out.flush(); synchronized (_timedJobs) { timedJobs = new ArrayList(_timedJobs); } - out.write("<!-- jobQueue rendering: after timedJobs sync -->\n".getBytes()); + out.write("<!-- jobQueue rendering: after timedJobs sync -->\n"); out.flush(); int numRunners = 0; synchronized (_queueRunners) { @@ -586,7 +586,7 @@ public class JobQueue { numRunners = _queueRunners.size(); } - out.write("<!-- jobQueue rendering: after queueRunners sync -->\n".getBytes()); + out.write("<!-- jobQueue rendering: after queueRunners sync -->\n"); out.flush(); StringBuffer buf = new StringBuffer(32*1024); @@ -631,15 +631,15 @@ public class JobQueue { } buf.append("</ol>\n"); - out.write("<!-- jobQueue rendering: after main buffer, before stats -->\n".getBytes()); + out.write("<!-- jobQueue rendering: after main buffer, before stats -->\n"); out.flush(); getJobStats(buf); - out.write("<!-- jobQueue rendering: after stats -->\n".getBytes()); + out.write("<!-- jobQueue rendering: after stats -->\n"); out.flush(); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); } /** render the HTML for the job stats */ diff --git a/router/java/src/net/i2p/router/NetworkDatabaseFacade.java b/router/java/src/net/i2p/router/NetworkDatabaseFacade.java index 371cf26775e4c8e0846c12937fa698708a4b5261..9c6ef0a8b57ce8a60ec922591707d0798f4aad8b 100644 --- a/router/java/src/net/i2p/router/NetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/NetworkDatabaseFacade.java @@ -9,7 +9,7 @@ package net.i2p.router; */ import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -95,5 +95,5 @@ class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade { public Set findNearestRouters(Hash key, int maxNumRouters, Set peersToIgnore) { return new HashSet(_routers.values()); } - public void renderStatusHTML(OutputStream out) throws IOException {} + public void renderStatusHTML(Writer out) throws IOException {} } diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index d835aa1766bd45b02657741dff0d3b8cc49ccf19..7b6c009c3b4c46d153d50c1c2393675319ca8453 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -12,7 +12,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.text.DecimalFormat; import java.util.Calendar; import java.util.Date; @@ -315,8 +315,8 @@ public class Router { _context.inNetMessagePool().registerHandlerJobBuilder(TunnelMessage.MESSAGE_TYPE, new TunnelMessageHandler(_context)); } - public void renderStatusHTML(OutputStream out) throws IOException { - out.write(("<h1>Router console</h1>\n" + + public void renderStatusHTML(Writer out) throws IOException { + out.write("<h1>Router console</h1>\n" + "<i><a href=\"/oldconsole.jsp\">console</a> | <a href=\"/oldstats.jsp\">stats</a></i><br>\n" + "<form action=\"/oldconsole.jsp\">" + "<select name=\"go\" onChange='location.href=this.value'>" + @@ -331,7 +331,7 @@ public class Router { "<option value=\"/oldconsole.jsp#netdb\">Network Database</option>\n" + "<option value=\"/oldconsole.jsp#logs\">Log messages</option>\n" + "</select> <input type=\"submit\" value=\"GO\" /> </form>" + - "<hr />\n").getBytes()); + "<hr />\n"); StringBuffer buf = new StringBuffer(32*1024); @@ -453,39 +453,39 @@ public class Router { buf.append("trying to transfer data. Lifetime averages count how many elephants there are on the moon [like anyone reads this text]</i>"); buf.append("\n"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); _context.bandwidthLimiter().renderStatusHTML(out); - out.write("<hr /><a name=\"clients\"> </a>\n".getBytes()); + out.write("<hr /><a name=\"clients\"> </a>\n"); _context.clientManager().renderStatusHTML(out); - out.write("\n<hr /><a name=\"transports\"> </a>\n".getBytes()); + out.write("\n<hr /><a name=\"transports\"> </a>\n"); _context.commSystem().renderStatusHTML(out); - out.write("\n<hr /><a name=\"profiles\"> </a>\n".getBytes()); + out.write("\n<hr /><a name=\"profiles\"> </a>\n"); _context.peerManager().renderStatusHTML(out); - out.write("\n<hr /><a name=\"tunnels\"> </a>\n".getBytes()); + out.write("\n<hr /><a name=\"tunnels\"> </a>\n"); _context.tunnelManager().renderStatusHTML(out); - out.write("\n<hr /><a name=\"jobs\"> </a>\n".getBytes()); + out.write("\n<hr /><a name=\"jobs\"> </a>\n"); _context.jobQueue().renderStatusHTML(out); - out.write("\n<hr /><a name=\"shitlist\"> </a>\n".getBytes()); + out.write("\n<hr /><a name=\"shitlist\"> </a>\n"); _context.shitlist().renderStatusHTML(out); - out.write("\n<hr /><a name=\"pending\"> </a>\n".getBytes()); + out.write("\n<hr /><a name=\"pending\"> </a>\n"); _context.messageRegistry().renderStatusHTML(out); - out.write("\n<hr /><a name=\"netdb\"> </a>\n".getBytes()); + out.write("\n<hr /><a name=\"netdb\"> </a>\n"); _context.netDb().renderStatusHTML(out); @@ -500,7 +500,7 @@ public class Router { buf.append("</pre></td></tr>\n"); } buf.append("</table>\n"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); } private static int MAX_MSG_LENGTH = 120; diff --git a/router/java/src/net/i2p/router/RouterThrottle.java b/router/java/src/net/i2p/router/RouterThrottle.java index 45d8bf9f545a8a7ccc9b30e5eb425d4d2be58a80..4b22394a0dbc56f32a161c26589531d0ecfeb975 100644 --- a/router/java/src/net/i2p/router/RouterThrottle.java +++ b/router/java/src/net/i2p/router/RouterThrottle.java @@ -31,4 +31,15 @@ public interface RouterThrottle { * */ public boolean acceptNetDbLookupRequest(Hash key); + + /** How backed up we are at the moment processing messages (in milliseconds) */ + public long getMessageDelay(); + /** How backed up our tunnels are at the moment (in milliseconds) */ + public long getTunnelLag(); + /** + * How much faster (or if negative, slower) we are receiving data as + * opposed to our longer term averages? + * + */ + public double getInboundRateDelta(); } diff --git a/router/java/src/net/i2p/router/RouterThrottleImpl.java b/router/java/src/net/i2p/router/RouterThrottleImpl.java index 05fafe99329b1767e0e286eaaa5edaf9849aa477..5e8a6f556e7dbc52aff6b75a1cc7c374930ec923 100644 --- a/router/java/src/net/i2p/router/RouterThrottleImpl.java +++ b/router/java/src/net/i2p/router/RouterThrottleImpl.java @@ -154,5 +154,35 @@ class RouterThrottleImpl implements RouterThrottle { return true; } + + public long getMessageDelay() { + Rate delayRate = _context.statManager().getRate("transport.sendProcessingTime").getRate(60*1000); + return (long)delayRate.getAverageValue(); + } + + public long getTunnelLag() { + Rate lagRate = _context.statManager().getRate("tunnel.testSuccessTime").getRate(10*60*1000); + return (long)lagRate.getAverageValue(); + } + + public double getInboundRateDelta() { + RateStat receiveRate = _context.statManager().getRate("transport.sendMessageSize"); + double nowBps = getBps(receiveRate.getRate(60*1000)); + double fiveMinBps = getBps(receiveRate.getRate(5*60*1000)); + double hourBps = getBps(receiveRate.getRate(60*60*1000)); + double dailyBps = getBps(receiveRate.getRate(24*60*60*1000)); + + if (nowBps < 0) return 0; + if (dailyBps > 0) return nowBps - dailyBps; + if (hourBps > 0) return nowBps - hourBps; + if (fiveMinBps > 0) return nowBps - fiveMinBps; + return 0; + } + private double getBps(Rate rate) { + if (rate == null) return -1; + double bytes = rate.getLastTotalValue(); + return (bytes*1000.0d)/rate.getPeriod(); + } + protected RouterContext getContext() { return _context; } } diff --git a/router/java/src/net/i2p/router/Service.java b/router/java/src/net/i2p/router/Service.java index 0fe2f4639dcc20782e6af41b6c2606f800f4aaef..31340ebee2516e3a4e7eb9681a546e7fdff99148 100644 --- a/router/java/src/net/i2p/router/Service.java +++ b/router/java/src/net/i2p/router/Service.java @@ -9,7 +9,7 @@ package net.i2p.router; */ import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; /** * Define the manageable service interface for the subsystems in the I2P router @@ -37,5 +37,5 @@ public interface Service { */ public void restart(); - public void renderStatusHTML(OutputStream out) throws IOException; + public void renderStatusHTML(Writer out) throws IOException; } diff --git a/router/java/src/net/i2p/router/SessionKeyPersistenceHelper.java b/router/java/src/net/i2p/router/SessionKeyPersistenceHelper.java index 03de1bfd9039e56c78185e0f7ff60c997b0d5cf3..93a35aba5f9288a458c42734f85fd6f44a9837c0 100644 --- a/router/java/src/net/i2p/router/SessionKeyPersistenceHelper.java +++ b/router/java/src/net/i2p/router/SessionKeyPersistenceHelper.java @@ -4,7 +4,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import net.i2p.crypto.PersistentSessionKeyManager; import net.i2p.crypto.SessionKeyManager; @@ -97,7 +97,7 @@ public class SessionKeyPersistenceHelper implements Service { } } - public void renderStatusHTML(OutputStream out) { } + public void renderStatusHTML(Writer out) { } private class SessionKeyWriterJob extends JobImpl { public SessionKeyWriterJob() { diff --git a/router/java/src/net/i2p/router/Shitlist.java b/router/java/src/net/i2p/router/Shitlist.java index cda6b21eaf4eec143995ada208e4d2d13a77b4b0..adca46ec78669f4a52b9f48d06d8527ad6126684 100644 --- a/router/java/src/net/i2p/router/Shitlist.java +++ b/router/java/src/net/i2p/router/Shitlist.java @@ -9,7 +9,7 @@ package net.i2p.router; */ import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.Date; import java.util.HashMap; import java.util.Iterator; @@ -123,7 +123,7 @@ public class Shitlist { } - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { StringBuffer buf = new StringBuffer(1024); buf.append("<h2>Shitlist</h2>"); Map shitlist = null; @@ -152,6 +152,6 @@ public class Shitlist { buf.append("</li>\n"); } buf.append("</ul>\n"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); } } diff --git a/router/java/src/net/i2p/router/StatisticsManager.java b/router/java/src/net/i2p/router/StatisticsManager.java index bf4ed721885dd61113fb652f02013da324429f70..e1ae639305503d6cbef6f042b9c6efce911ed68a 100644 --- a/router/java/src/net/i2p/router/StatisticsManager.java +++ b/router/java/src/net/i2p/router/StatisticsManager.java @@ -8,7 +8,7 @@ package net.i2p.router; * */ -import java.io.OutputStream; +import java.io.Writer; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; @@ -107,32 +107,33 @@ public class StatisticsManager implements Service { includeRate("jobQueue.jobLag", stats, new long[] { 60*1000, 60*60*1000 }); includeRate("jobQueue.jobRun", stats, new long[] { 60*1000, 60*60*1000 }); includeRate("crypto.elGamal.encrypt", stats, new long[] { 60*1000, 60*60*1000 }); - includeRate("crypto.garlic.decryptFail", stats, new long[] { 60*60*1000, 24*60*60*1000 }); + //includeRate("crypto.garlic.decryptFail", stats, new long[] { 60*60*1000, 24*60*60*1000 }); includeRate("tunnel.unknownTunnelTimeLeft", stats, new long[] { 60*60*1000, 24*60*60*1000 }); includeRate("jobQueue.readyJobs", stats, new long[] { 60*1000, 60*60*1000 }); //includeRate("jobQueue.droppedJobs", stats, new long[] { 60*60*1000, 24*60*60*1000 }); includeRate("inNetPool.dropped", stats, new long[] { 60*60*1000, 24*60*60*1000 }); includeRate("tunnel.participatingTunnels", stats, new long[] { 5*60*1000, 60*60*1000 }); includeRate("tunnel.testSuccessTime", stats, new long[] { 60*60*1000l, 24*60*60*1000l }); - includeRate("tunnel.outboundMessagesProcessed", stats, new long[] { 10*60*1000, 60*60*1000 }); - includeRate("tunnel.inboundMessagesProcessed", stats, new long[] { 10*60*1000, 60*60*1000 }); + //includeRate("tunnel.outboundMessagesProcessed", stats, new long[] { 10*60*1000, 60*60*1000 }); + //includeRate("tunnel.inboundMessagesProcessed", stats, new long[] { 10*60*1000, 60*60*1000 }); includeRate("tunnel.participatingMessagesProcessed", stats, new long[] { 10*60*1000, 60*60*1000 }); - includeRate("tunnel.expiredAfterAcceptTime", stats, new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000l }); + includeRate("tunnel.participatingMessagesProcessedActive", stats, new long[] { 10*60*1000, 60*60*1000 }); + //includeRate("tunnel.expiredAfterAcceptTime", stats, new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000l }); includeRate("tunnel.bytesAllocatedAtAccept", stats, new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000l }); includeRate("netDb.lookupsReceived", stats, new long[] { 5*60*1000, 60*60*1000 }); includeRate("netDb.lookupsHandled", stats, new long[] { 5*60*1000, 60*60*1000 }); includeRate("netDb.lookupsMatched", stats, new long[] { 5*60*1000, 60*60*1000 }); - includeRate("netDb.storeSent", stats, new long[] { 5*60*1000, 60*60*1000 }); + //includeRate("netDb.storeSent", stats, new long[] { 5*60*1000, 60*60*1000 }); includeRate("netDb.successPeers", stats, new long[] { 60*60*1000 }); includeRate("netDb.failedPeers", stats, new long[] { 60*60*1000 }); - includeRate("router.throttleNetDbDoSSend", stats, new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 }); - includeRate("router.throttleNetDbDoS", stats, new long[] { 10*60*1000, 60*60*1000 }); + //includeRate("router.throttleNetDbDoSSend", stats, new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 }); + //includeRate("router.throttleNetDbDoS", stats, new long[] { 10*60*1000, 60*60*1000 }); //includeRate("netDb.searchCount", stats, new long[] { 3*60*60*1000}); //includeRate("netDb.searchMessageCount", stats, new long[] { 5*60*1000, 10*60*1000, 60*60*1000 }); //includeRate("inNetMessage.timeToDiscard", stats, new long[] { 5*60*1000, 10*60*1000, 60*60*1000 }); //includeRate("outNetMessage.timeToDiscard", stats, new long[] { 5*60*1000, 10*60*1000, 60*60*1000 }); - includeRate("router.throttleNetworkCause", stats, new long[] { 10*60*1000, 60*60*1000 }); - includeRate("transport.receiveMessageSize", stats, new long[] { 5*60*1000, 60*60*1000 }); + //includeRate("router.throttleNetworkCause", stats, new long[] { 10*60*1000, 60*60*1000 }); + //includeRate("transport.receiveMessageSize", stats, new long[] { 5*60*1000, 60*60*1000 }); //includeRate("transport.sendMessageSize", stats, new long[] { 5*60*1000, 60*60*1000 }); //includeRate("transport.sendMessageSmall", stats, new long[] { 5*60*1000, 60*60*1000 }); //includeRate("transport.sendMessageMedium", stats, new long[] { 5*60*1000, 60*60*1000 }); @@ -141,6 +142,10 @@ public class StatisticsManager implements Service { //includeRate("transport.receiveMessageMedium", stats, new long[] { 5*60*1000, 60*60*1000 }); //includeRate("transport.receiveMessageLarge", stats, new long[] { 5*60*1000, 60*60*1000 }); includeRate("client.sendAckTime", stats, new long[] { 60*60*1000, 24*60*60*1000l }, true); + includeRate("client.sendsPerFailure", stats, new long[] { 60*60*1000, 24*60*60*1000l }, true); + includeRate("client.timeoutCongestionTunnel", stats, new long[] { 60*60*1000, 24*60*60*1000l }, true); + includeRate("client.timeoutCongestionMessage", stats, new long[] { 60*60*1000, 24*60*60*1000l }, true); + includeRate("client.timeoutCongestionInbound", stats, new long[] { 60*60*1000, 24*60*60*1000l }, true); stats.setProperty("stat_uptime", DataHelper.formatDuration(_context.router().getUptime())); stats.setProperty("stat__rateKey", "avg;maxAvg;pctLifetime;[sat;satLim;maxSat;maxSatLim;][num;lifetimeFreq;maxFreq]"); _log.debug("Publishing peer rankings"); @@ -266,5 +271,5 @@ public class StatisticsManager implements Service { private final String num(double num) { synchronized (_fmt) { return _fmt.format(num); } } private final String pct(double num) { synchronized (_pct) { return _pct.format(num); } } - public void renderStatusHTML(OutputStream out) { } + public void renderStatusHTML(Writer out) { } } diff --git a/router/java/src/net/i2p/router/admin/AdminManager.java b/router/java/src/net/i2p/router/admin/AdminManager.java index 06d8de5941961a28d3bb017ae62fd4b891695cb3..531b5efce63a82a84a3b18cda997fa15bd8856bc 100644 --- a/router/java/src/net/i2p/router/admin/AdminManager.java +++ b/router/java/src/net/i2p/router/admin/AdminManager.java @@ -1,6 +1,6 @@ package net.i2p.router.admin; -import java.io.OutputStream; +import java.io.Writer; import net.i2p.router.RouterContext; import net.i2p.router.Service; @@ -20,7 +20,7 @@ public class AdminManager implements Service { _log = context.logManager().getLog(AdminManager.class); } - public void renderStatusHTML(OutputStream out) { } + public void renderStatusHTML(Writer out) { } public void shutdown() { if (_listener != null) { diff --git a/router/java/src/net/i2p/router/admin/AdminRunner.java b/router/java/src/net/i2p/router/admin/AdminRunner.java index d8424e70b49ea49a3e9f1798d48bb9a0182c0a55..0ded465eb314526bd5045f854440be462c38641c 100644 --- a/router/java/src/net/i2p/router/admin/AdminRunner.java +++ b/router/java/src/net/i2p/router/admin/AdminRunner.java @@ -5,6 +5,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.net.Socket; import java.util.Iterator; import java.util.Set; @@ -47,7 +48,7 @@ class AdminRunner implements Runnable { } else if ( (command.indexOf("routerStats.html") >= 0) || (command.indexOf("oldstats.jsp") >= 0) ) { try { out.write("HTTP/1.1 200 OK\nConnection: close\nCache-control: no-cache\nContent-type: text/html\n\n".getBytes()); - _generator.generateStatsPage(out); + _generator.generateStatsPage(new OutputStreamWriter(out)); out.close(); } catch (IOException ioe) { if (_log.shouldLog(Log.WARN)) @@ -61,7 +62,7 @@ class AdminRunner implements Runnable { } else if (true || command.indexOf("routerConsole.html") > 0) { try { out.write("HTTP/1.1 200 OK\nConnection: close\nCache-control: no-cache\nContent-type: text/html\n\n".getBytes()); - _context.router().renderStatusHTML(out); + _context.router().renderStatusHTML(new OutputStreamWriter(out)); out.close(); } catch (IOException ioe) { if (_log.shouldLog(Log.WARN)) diff --git a/router/java/src/net/i2p/router/admin/StatsGenerator.java b/router/java/src/net/i2p/router/admin/StatsGenerator.java index 3a84bad95714ac9c5a2aa35de693512ec03cd9bf..e7bdfd71990dd48073c05503fd32697c45f752a0 100644 --- a/router/java/src/net/i2p/router/admin/StatsGenerator.java +++ b/router/java/src/net/i2p/router/admin/StatsGenerator.java @@ -2,6 +2,7 @@ package net.i2p.router.admin; import java.io.IOException; import java.io.OutputStream; +import java.io.Writer; import java.text.DecimalFormat; import java.util.Arrays; import java.util.Iterator; @@ -27,13 +28,13 @@ public class StatsGenerator { _log = context.logManager().getLog(StatsGenerator.class); } - public void generateStatsPage(OutputStream out) throws IOException { + public void generateStatsPage(Writer out) throws IOException { StringBuffer buf = new StringBuffer(16*1024); buf.append("<h1>Router statistics</h1>"); buf.append("<i><a href=\"/oldconsole.jsp\">console</a> | <a href=\"/oldstats.jsp\">stats</a></i><hr />"); buf.append("<form action=\"/oldstats.jsp\">"); buf.append("<select name=\"go\" onChange='location.href=this.value'>"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); buf.setLength(0); Map groups = _context.statManager().getStatsByGroup(); @@ -50,7 +51,7 @@ public class StatsGenerator { buf.append(stat); buf.append("</option>\n"); } - out.write(buf.toString().getBytes()); + out.write(buf.toString()); buf.setLength(0); } buf.append("</select> <input type=\"submit\" value=\"GO\" />"); @@ -61,7 +62,7 @@ public class StatsGenerator { buf.append(DataHelper.formatDuration(uptime)); buf.append("). The data gathered is quantized over a 1 minute period, so should just be used as an estimate<p />"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); buf.setLength(0); for (Iterator iter = groups.keySet().iterator(); iter.hasNext(); ) { @@ -73,7 +74,7 @@ public class StatsGenerator { buf.append(group); buf.append("</a></h2>"); buf.append("<ul>"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); buf.setLength(0); for (Iterator statIter = stats.iterator(); statIter.hasNext(); ) { String stat = (String)statIter.next(); @@ -86,10 +87,10 @@ public class StatsGenerator { renderFrequency(stat, buf); else renderRate(stat, buf); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); buf.setLength(0); } - out.write("</ul><hr />".getBytes()); + out.write("</ul><hr />"); } } diff --git a/router/java/src/net/i2p/router/client/ClientManager.java b/router/java/src/net/i2p/router/client/ClientManager.java index d5ab9c98c315a220cdb5bca3ab91e2423c7e5b1b..abe32939d0d01db588d19acfdebdf894fb9aa075 100644 --- a/router/java/src/net/i2p/router/client/ClientManager.java +++ b/router/java/src/net/i2p/router/client/ClientManager.java @@ -9,7 +9,7 @@ package net.i2p.router.client; */ import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -332,7 +332,7 @@ public class ClientManager { } } - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { StringBuffer buf = new StringBuffer(8*1024); buf.append("<u><b>Local destinations</b></u><br />"); @@ -376,7 +376,7 @@ public class ClientManager { } buf.append("\n<hr />\n"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); } public void messageReceived(ClientMessage msg) { diff --git a/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java b/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java index 43b870aaa99370c899d1c8fef4582c2152024a6a..ac2ee7f74dcb97b4b364b2c5692a3dc5e9ce2ac6 100644 --- a/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java +++ b/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java @@ -9,7 +9,7 @@ package net.i2p.router.client; */ import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import net.i2p.data.Destination; import net.i2p.data.Hash; @@ -158,7 +158,7 @@ public class ClientManagerFacadeImpl extends ClientManagerFacade { } } - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { if (_manager != null) _manager.renderStatusHTML(out); } diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageJob.java b/router/java/src/net/i2p/router/message/OutboundClientMessageJob.java index 0bd1d459e304642b6019984d518aea831c739bba..b63b5443d677704220d11e6af3499520087adf6f 100644 --- a/router/java/src/net/i2p/router/message/OutboundClientMessageJob.java +++ b/router/java/src/net/i2p/router/message/OutboundClientMessageJob.java @@ -104,7 +104,11 @@ public class OutboundClientMessageJob extends JobImpl { ctx.statManager().createRateStat("client.sendMessageSize", "How large are messages sent by the client?", "Client Messages", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); ctx.statManager().createRateStat("client.sendAttemptAverage", "How many different tunnels do we have to try when sending a client message?", "Client Messages", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); ctx.statManager().createRateStat("client.sendAckTime", "How long does it take to get an ACK back from a message?", "Client Messages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l }); - + ctx.statManager().createRateStat("client.sendsPerFailure", "How many send attempts do we make when they all fail?", "Client Messages", new long[] { 60*60*1000l, 24*60*60*1000l }); + ctx.statManager().createRateStat("client.timeoutCongestionTunnel", "How lagged our tunnels are when a send times out?", "Client Messages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l }); + ctx.statManager().createRateStat("client.timeoutCongestionMessage", "How fast we process messages locally when a send times out?", "Client Messages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l }); + ctx.statManager().createRateStat("client.timeoutCongestionInbound", "How much faster we are receiving data than our average bps when a send times out?", "Client Messages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l }); + long timeoutMs = OVERALL_TIMEOUT_MS_DEFAULT; String param = msg.getSenderConfig().getOptions().getProperty(OVERALL_TIMEOUT_MS_PARAM); @@ -122,7 +126,7 @@ public class OutboundClientMessageJob extends JobImpl { } _overallExpiration = timeoutMs + getContext().clock().now(); - _status = new OutboundClientMessageStatus(msg); + _status = new OutboundClientMessageStatus(ctx, msg); _nextStep = new NextStepJob(); _lookupLeaseSetFailed = new LookupLeaseSetFailedJob(); _shouldBundle = getShouldBundle(); @@ -423,6 +427,7 @@ public class OutboundClientMessageJob extends JobImpl { getContext().clientManager().messageDeliveryStatusUpdate(msg.getFromDestination(), msg.getMessageId(), false); getContext().statManager().updateFrequency("client.sendMessageFailFrequency"); getContext().statManager().addRateData("client.sendAttemptAverage", _status.getNumSent(), sendTime); + getContext().statManager().addRateData("client.sendsPerFailure", _status.getNumSent(), sendTime); } /** build the payload clove that will be used for all of the messages, placing the clove in the status structure */ @@ -455,126 +460,6 @@ public class OutboundClientMessageJob extends JobImpl { _log.debug(getJobId() + ": Built payload clove with id " + clove.getId()); } - /** - * Good ol' fashioned struct with the send status - * - */ - private class OutboundClientMessageStatus { - private ClientMessage _msg; - private PayloadGarlicConfig _clove; - private LeaseSet _leaseSet; - private Set _sent; - private int _numLookups; - private boolean _success; - private boolean _failure; - private long _start; - private int _previousSent; - - public OutboundClientMessageStatus(ClientMessage msg) { - _msg = msg; - _clove = null; - _leaseSet = null; - _sent = new HashSet(4); - _success = false; - _failure = false; - _numLookups = 0; - _previousSent = 0; - _start = getContext().clock().now(); - } - - /** raw payload */ - public Payload getPayload() { return _msg.getPayload(); } - /** clove, if we've built it */ - public PayloadGarlicConfig getClove() { return _clove; } - public void setClove(PayloadGarlicConfig clove) { _clove = clove; } - public ClientMessage getMessage() { return _msg; } - /** date we started the process on */ - public long getStart() { return _start; } - - public int getNumLookups() { return _numLookups; } - public void incrementLookups() { _numLookups++; } - public void clearAlreadySent() { - synchronized (_sent) { - _previousSent += _sent.size(); - _sent.clear(); - } - } - - /** who sent the message? */ - public Destination getFrom() { return _msg.getFromDestination(); } - /** who is the message going to? */ - public Destination getTo() { return _msg.getDestination(); } - /** what is the target's current leaseSet (or null if we don't know yet) */ - public LeaseSet getLeaseSet() { return _leaseSet; } - public void setLeaseSet(LeaseSet ls) { _leaseSet = ls; } - /** have we already sent the message down this tunnel? */ - public boolean alreadySent(Hash gateway, TunnelId tunnelId) { - Tunnel t = new Tunnel(gateway, tunnelId); - synchronized (_sent) { - return _sent.contains(t); - } - } - public void sent(Hash gateway, TunnelId tunnelId) { - Tunnel t = new Tunnel(gateway, tunnelId); - synchronized (_sent) { - _sent.add(t); - } - } - /** how many messages have we sent through various leases? */ - public int getNumSent() { - synchronized (_sent) { - return _sent.size() + _previousSent; - } - } - /** did we totally fail? */ - public boolean getFailure() { return _failure; } - /** we failed. returns true if we had already failed before */ - public boolean failed() { - boolean already = _failure; - _failure = true; - return already; - } - /** have we totally succeeded? */ - public boolean getSuccess() { return _success; } - /** we succeeded. returns true if we had already succeeded before */ - public boolean success() { - boolean already = _success; - _success = true; - return already; - } - - /** represent a unique tunnel at any given time */ - private class Tunnel { - private Hash _gateway; - private TunnelId _tunnel; - - public Tunnel(Hash tunnelGateway, TunnelId tunnel) { - _gateway = tunnelGateway; - _tunnel = tunnel; - } - - public Hash getGateway() { return _gateway; } - public TunnelId getTunnel() { return _tunnel; } - - public int hashCode() { - int rv = 0; - if (_gateway != null) - rv += _gateway.hashCode(); - if (_tunnel != null) - rv += 7*_tunnel.getTunnelId(); - return rv; - } - - public boolean equals(Object o) { - if (o == null) return false; - if (o.getClass() != Tunnel.class) return false; - Tunnel t = (Tunnel)o; - return (getTunnel() == t.getTunnel()) && - getGateway().equals(t.getGateway()); - } - } - } - /** * Keep an eye out for any of the delivery status message tokens that have been * sent down the various tunnels to deliver this message @@ -712,6 +597,14 @@ public class OutboundClientMessageJob extends JobImpl { if (_log.shouldLog(Log.DEBUG)) _log.debug(OutboundClientMessageJob.this.getJobId() + ": Soft timeout through the lease " + _lease); + + long messageDelay = getContext().throttle().getMessageDelay(); + long tunnelLag = getContext().throttle().getTunnelLag(); + long inboundDelta = (long)getContext().throttle().getInboundRateDelta(); + getContext().statManager().addRateData("client.timeoutCongestionTunnel", tunnelLag, 1); + getContext().statManager().addRateData("client.timeoutCongestionMessage", messageDelay, 1); + getContext().statManager().addRateData("client.timeoutCongestionInbound", inboundDelta, 1); + _lease.setNumFailure(_lease.getNumFailure()+1); sendNext(); } diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageStatus.java b/router/java/src/net/i2p/router/message/OutboundClientMessageStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..f309dca7d5e89e6b76ee4f97d885a7ede9ae8423 --- /dev/null +++ b/router/java/src/net/i2p/router/message/OutboundClientMessageStatus.java @@ -0,0 +1,133 @@ +package net.i2p.router.message; + +import java.util.HashSet; +import java.util.Set; +import net.i2p.data.Destination; +import net.i2p.data.Hash; +import net.i2p.data.LeaseSet; +import net.i2p.data.Payload; +import net.i2p.data.TunnelId; +import net.i2p.router.ClientMessage; +import net.i2p.router.RouterContext; + +/** + * Good ol' fashioned struct with the send status + * + */ +class OutboundClientMessageStatus { + private RouterContext _context; + private ClientMessage _msg; + private PayloadGarlicConfig _clove; + private LeaseSet _leaseSet; + private Set _sent; + private int _numLookups; + private boolean _success; + private boolean _failure; + private long _start; + private int _previousSent; + + public OutboundClientMessageStatus(RouterContext ctx, ClientMessage msg) { + _context = ctx; + _msg = msg; + _clove = null; + _leaseSet = null; + _sent = new HashSet(4); + _success = false; + _failure = false; + _numLookups = 0; + _previousSent = 0; + _start = ctx.clock().now(); + } + + /** raw payload */ + public Payload getPayload() { return _msg.getPayload(); } + /** clove, if we've built it */ + public PayloadGarlicConfig getClove() { return _clove; } + public void setClove(PayloadGarlicConfig clove) { _clove = clove; } + public ClientMessage getMessage() { return _msg; } + /** date we started the process on */ + public long getStart() { return _start; } + + public int getNumLookups() { return _numLookups; } + public void incrementLookups() { _numLookups++; } + public void clearAlreadySent() { + synchronized (_sent) { + _previousSent += _sent.size(); + _sent.clear(); + } + } + + /** who sent the message? */ + public Destination getFrom() { return _msg.getFromDestination(); } + /** who is the message going to? */ + public Destination getTo() { return _msg.getDestination(); } + /** what is the target's current leaseSet (or null if we don't know yet) */ + public LeaseSet getLeaseSet() { return _leaseSet; } + public void setLeaseSet(LeaseSet ls) { _leaseSet = ls; } + /** have we already sent the message down this tunnel? */ + public boolean alreadySent(Hash gateway, TunnelId tunnelId) { + Tunnel t = new Tunnel(gateway, tunnelId); + synchronized (_sent) { + return _sent.contains(t); + } + } + public void sent(Hash gateway, TunnelId tunnelId) { + Tunnel t = new Tunnel(gateway, tunnelId); + synchronized (_sent) { + _sent.add(t); + } + } + /** how many messages have we sent through various leases? */ + public int getNumSent() { + synchronized (_sent) { + return _sent.size() + _previousSent; + } + } + /** did we totally fail? */ + public boolean getFailure() { return _failure; } + /** we failed. returns true if we had already failed before */ + public boolean failed() { + boolean already = _failure; + _failure = true; + return already; + } + /** have we totally succeeded? */ + public boolean getSuccess() { return _success; } + /** we succeeded. returns true if we had already succeeded before */ + public boolean success() { + boolean already = _success; + _success = true; + return already; + } + + /** represent a unique tunnel at any given time */ + private class Tunnel { + private Hash _gateway; + private TunnelId _tunnel; + + public Tunnel(Hash tunnelGateway, TunnelId tunnel) { + _gateway = tunnelGateway; + _tunnel = tunnel; + } + + public Hash getGateway() { return _gateway; } + public TunnelId getTunnel() { return _tunnel; } + + public int hashCode() { + int rv = 0; + if (_gateway != null) + rv += _gateway.hashCode(); + if (_tunnel != null) + rv += 7*_tunnel.getTunnelId(); + return rv; + } + + public boolean equals(Object o) { + if (o == null) return false; + if (o.getClass() != Tunnel.class) return false; + Tunnel t = (Tunnel)o; + return (getTunnel() == t.getTunnel()) && + getGateway().equals(t.getGateway()); + } + } +} diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java index 589cd1a2e6c0955ac0c91df56468ccae94fa7dab..52357e2ea49548e369376b5113cd6232acb3b2ed 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java @@ -11,7 +11,7 @@ package net.i2p.router.networkdb.kademlia; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -810,17 +810,17 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { return routers; } - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { StringBuffer buf = new StringBuffer(10*1024); buf.append("<h2>Kademlia Network DB Contents</h2>\n"); if (!_initialized) { buf.append("<i>Not initialized</i>\n"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); return; } Set leases = getLeases(); buf.append("<h3>Leases</h3>\n"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); buf.setLength(0); long now = _context.clock().now(); for (Iterator iter = leases.iterator(); iter.hasNext(); ) { @@ -838,17 +838,17 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { buf.append("</i> tunnelId <i>").append(ls.getLease(i).getTunnelId().getTunnelId()).append("</i><br />\n"); } buf.append("<hr />\n"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); buf.setLength(0); } Hash us = _context.routerHash(); Set routers = getRouters(); - out.write("<h3>Routers</h3>\n".getBytes()); + out.write("<h3>Routers</h3>\n"); RouterInfo ourInfo = _context.router().getRouterInfo(); renderRouterInfo(buf, ourInfo, true); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); buf.setLength(0); /* coreVersion to Map of routerVersion to Integer */ @@ -860,7 +860,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { boolean isUs = key.equals(us); if (!isUs) { renderRouterInfo(buf, ri, false); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); buf.setLength(0); String coreVersion = ri.getOptions().getProperty("coreVersion"); String routerVersion = ri.getOptions().getProperty("router.version"); @@ -895,7 +895,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade { } buf.append("</table>\n"); } - out.write(buf.toString().getBytes()); + out.write(buf.toString()); } private void renderRouterInfo(StringBuffer buf, RouterInfo info, boolean isUs) { diff --git a/router/java/src/net/i2p/router/peermanager/PeerManager.java b/router/java/src/net/i2p/router/peermanager/PeerManager.java index 9dd2a4ac5f4a9fb30270662418601acc3bf029e9..2506abe720b6ef4588241af85df86751b3356d32 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerManager.java +++ b/router/java/src/net/i2p/router/peermanager/PeerManager.java @@ -9,7 +9,7 @@ package net.i2p.router.peermanager; */ import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; @@ -116,7 +116,7 @@ class PeerManager { return new ArrayList(peers); } - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { _organizer.renderStatusHTML(out); } } diff --git a/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java b/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java index a8bbee49193f1c85bb7c3f3bfd4d83007630a8f2..13b0adf1ea9017ba7e301d3e1a91bf6c06b2cb7c 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java +++ b/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java @@ -9,7 +9,7 @@ package net.i2p.router.peermanager; */ import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.ArrayList; import java.util.List; @@ -59,7 +59,7 @@ public class PeerManagerFacadeImpl implements PeerManagerFacade { return _manager.selectPeers(criteria); } - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { _manager.renderStatusHTML(out); } } diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java index 05eecda1c24bb6b5350a222f0223ea9e50fd7964..30ba0dfacdd486c62155305416474eb3355c1f45 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java +++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java @@ -2,6 +2,7 @@ package net.i2p.router.peermanager; import java.io.IOException; import java.io.OutputStream; +import java.io.Writer; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.ArrayList; @@ -203,7 +204,7 @@ public class ProfileOrganizer { _persistenceHelper.writeProfile(prof, out); } - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { ProfileOrganizerRenderer rend = new ProfileOrganizerRenderer(this, _context); rend.renderStatusHTML(out); } diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizerRenderer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizerRenderer.java index 3d929afd8e274c1c2f02c476d3dd6734081fd80c..909d183d419277824c31a433c2c6c071fe2faa0b 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizerRenderer.java +++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizerRenderer.java @@ -1,7 +1,7 @@ package net.i2p.router.peermanager; import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; @@ -27,7 +27,7 @@ class ProfileOrganizerRenderer { _context = context; _organizer = organizer; } - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { Set peers = _organizer.selectAllPeers(); long hideBefore = _context.clock().now() - 3*60*60*1000; @@ -126,7 +126,7 @@ class ProfileOrganizerRenderer { buf.append("<b>Speed:</b> ").append(num(_organizer.getSpeedThreshold())).append(" (").append(fast).append(" fast peers)<br />"); buf.append("<b>Capacity:</b> ").append(num(_organizer.getCapacityThreshold())).append(" (").append(reliable).append(" high capacity peers)<br />"); buf.append("<b>Integration:</b> ").append(num(_organizer.getIntegrationThreshold())).append(" (").append(integrated).append(" well integrated peers)<br />"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); } private final static DecimalFormat _fmt = new DecimalFormat("###,##0.00", new DecimalFormatSymbols(Locale.UK)); diff --git a/router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java b/router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java index dc0f33406f1ecbc8a5d0e33674b83af421936f16..17d0942ecc4edc7c02a428b40edc432eeaeb84d0 100644 --- a/router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java +++ b/router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java @@ -1,7 +1,7 @@ package net.i2p.router.transport; import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.ArrayList; import java.util.List; @@ -407,7 +407,7 @@ public class FIFOBandwidthLimiter { return satisfied; } - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { long now = _context.clock().now(); StringBuffer buf = new StringBuffer(4096); buf.append("<br /><b>Pending bandwidth requests (with "); @@ -436,7 +436,7 @@ public class FIFOBandwidthLimiter { } } buf.append("</ol></li></ul>\n"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); } private static long __requestId = 0; diff --git a/router/java/src/net/i2p/router/transport/OutboundMessageRegistry.java b/router/java/src/net/i2p/router/transport/OutboundMessageRegistry.java index 7fe5462d6f0ef2d9d0a019e5e644bbb9da8a2f96..ccada8769132f737cb81040b177bec9cf50ead52 100644 --- a/router/java/src/net/i2p/router/transport/OutboundMessageRegistry.java +++ b/router/java/src/net/i2p/router/transport/OutboundMessageRegistry.java @@ -9,7 +9,7 @@ package net.i2p.router.transport; */ import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; @@ -275,7 +275,7 @@ public class OutboundMessageRegistry { } } - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { StringBuffer buf = new StringBuffer(8192); buf.append("<h2>Pending messages</h2>\n"); Map msgs = null; @@ -295,7 +295,7 @@ public class OutboundMessageRegistry { buf.append("</li>\n"); } buf.append("</ul>"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); } /** diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java index 35beef902a4388472ced944c58c93300ca6b862e..be97c2eef5463d7802d16ef355108e4e7a50a806 100644 --- a/router/java/src/net/i2p/router/transport/TransportManager.java +++ b/router/java/src/net/i2p/router/transport/TransportManager.java @@ -9,7 +9,7 @@ package net.i2p.router.transport; */ import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -265,7 +265,7 @@ public class TransportManager implements TransportEventListener { return rv; } - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { StringBuffer buf = new StringBuffer(8*1024); buf.append("<h2>Transport Manager</h2>\n"); buf.append("Listening on: <br /><pre>\n"); @@ -283,6 +283,6 @@ public class TransportManager implements TransportEventListener { if (str != null) buf.append(str); } - out.write(buf.toString().getBytes()); + out.write(buf.toString()); } } diff --git a/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelManagerFacade.java b/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelManagerFacade.java index b7cfbc15107ae03cff776265b16c73d25961c37b..fae3e83d83f00f832c17fc015fc3fe30b063506c 100644 --- a/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelManagerFacade.java +++ b/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelManagerFacade.java @@ -1,7 +1,7 @@ package net.i2p.router.tunnelmanager; import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.Date; import java.util.Iterator; import java.util.List; @@ -229,7 +229,7 @@ public class PoolingTunnelManagerFacade implements TunnelManagerFacade { * Aint she pretty? * */ - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { if (_pool != null) _pool.renderStatusHTML(out); } diff --git a/router/java/src/net/i2p/router/tunnelmanager/TunnelPool.java b/router/java/src/net/i2p/router/tunnelmanager/TunnelPool.java index d7f7da1063e79b37035a61fbe19ac94fdaf9fd30..e087f641730cb44611812c74cc1e68bbb181685d 100644 --- a/router/java/src/net/i2p/router/tunnelmanager/TunnelPool.java +++ b/router/java/src/net/i2p/router/tunnelmanager/TunnelPool.java @@ -1,7 +1,7 @@ package net.i2p.router.tunnelmanager; import java.io.IOException; -import java.io.OutputStream; +import java.io.Writer; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -66,7 +66,8 @@ class TunnelPool { _context.statManager().createRateStat("tunnel.inboundMessagesProcessed", "How many messages does an inbound tunnel process in its lifetime?", "Tunnels", new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000l }); _context.statManager().createRateStat("tunnel.outboundMessagesProcessed", "How many messages does an inbound tunnel process in its lifetime?", "Tunnels", new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000l }); _context.statManager().createRateStat("tunnel.participatingMessagesProcessed", "How many messages does an inbound tunnel process in its lifetime?", "Tunnels", new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000l }); - + _context.statManager().createRateStat("tunnel.participatingMessagesProcessedActive", "How many messages beyond the average were processed in a more-than-average tunnel's lifetime?", "Tunnels", new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000l }); + _isLive = true; _persistenceHelper = new TunnelPoolPersistenceHelper(_context); _tunnelBuilder = new TunnelBuilder(_context); @@ -603,8 +604,8 @@ class TunnelPool { public void shutdown() { if (_log.shouldLog(Log.INFO)) _log.info("Shutting down tunnel pool"); - if (_persistenceHelper != null) - _persistenceHelper.writePool(this); + //if (_persistenceHelper != null) + // _persistenceHelper.writePool(this); _isLive = false; // the subjobs [should] check getIsLive() on each run _outboundTunnels = null; _freeInboundTunnels = null; @@ -633,10 +634,17 @@ class TunnelPool { info.getSettings().getCreated()); break; case TunnelId.TYPE_PARTICIPANT: + long numMsgs = info.getMessagesProcessed(); + long lastAvg = (long)_context.statManager().getRate("tunnel.participatingMessagesProcessed").getRate(10*60*1000l).getAverageValue(); _context.statManager().addRateData("tunnel.participatingMessagesProcessed", - info.getMessagesProcessed(), + numMsgs, info.getSettings().getExpiration() - info.getSettings().getCreated()); + if (numMsgs > lastAvg) + _context.statManager().addRateData("tunnel.participatingMessagesProcessedActive", + numMsgs-lastAvg, + info.getSettings().getExpiration() - + info.getSettings().getCreated()); break; case TunnelId.TYPE_UNSPECIFIED: default: @@ -651,9 +659,9 @@ class TunnelPool { return settings; } - public void renderStatusHTML(OutputStream out) throws IOException { + public void renderStatusHTML(Writer out) throws IOException { if (!_isLive) return; - out.write("<h2>Tunnel Pool</h2>\n".getBytes()); + out.write("<h2>Tunnel Pool</h2>\n"); StringBuffer buf = new StringBuffer(4096); renderTunnels(out, buf, "Free inbound tunnels", getFreeTunnels()); renderTunnels(out, buf, "Outbound tunnels", getOutboundTunnels()); @@ -665,19 +673,19 @@ class TunnelPool { } } - private void renderTunnels(OutputStream out, StringBuffer buf, String msg, Set tunnelIds) throws IOException { + private void renderTunnels(Writer out, StringBuffer buf, String msg, Set tunnelIds) throws IOException { buf.append("<b>").append(msg).append(":</b> <i>(").append(tunnelIds.size()).append(" tunnels)</i><ul>\n"); - out.write(buf.toString().getBytes()); + out.write(buf.toString()); buf.setLength(0); for (Iterator iter = tunnelIds.iterator(); iter.hasNext(); ) { TunnelId id = (TunnelId)iter.next(); TunnelInfo tunnel = getTunnelInfo(id); renderTunnel(out, buf, id, tunnel); } - out.write("</ul>\n".getBytes()); + out.write("</ul>\n"); } - private final void renderTunnel(OutputStream out, StringBuffer buf, TunnelId id, TunnelInfo tunnel) throws IOException { + private final void renderTunnel(Writer out, StringBuffer buf, TunnelId id, TunnelInfo tunnel) throws IOException { buf.setLength(0); if (tunnel == null) { buf.append("<li>Tunnel: ").append(id.getTunnelId()).append(" is not known</li>\n"); @@ -713,7 +721,7 @@ class TunnelPool { buf.append("\n</pre>"); } - out.write(buf.toString().getBytes()); + out.write(buf.toString()); buf.setLength(0); }