diff --git a/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java index a761a5ac24..68dfa0df60 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java @@ -81,12 +81,13 @@ public class TunnelRenderer { int displayed = 0; for (int i = 0; i < participating.size(); i++) { HopConfig cfg = participating.get(i); - long count = cfg.getProcessedMessagesCount(); + int count = cfg.getProcessedMessagesCount(); if (count <= 0) { inactive++; continue; } - processed += count; + // everything that isn't 'recent' is already in the tunnel.participatingMessageCount stat + processed += cfg.getRecentMessagesCount(); if (++displayed > DISPLAY_LIMIT) continue; out.write(""); @@ -111,13 +112,13 @@ public class TunnelRenderer { out.write("" + DataHelper.formatDuration2(timeLeft) + ""); else out.write("(" + _t("grace period") + ")"); - out.write("" + cfg.getProcessedMessagesCount() + " KB"); + out.write("" + count + " KB"); int lifetime = (int) ((_context.clock().now() - cfg.getCreation()) / 1000); if (lifetime <= 0) lifetime = 1; if (lifetime > 10*60) lifetime = 10*60; - int bps = 1024 * cfg.getProcessedMessagesCount() / lifetime; + int bps = 1024 * count / lifetime; out.write("" + bps + " Bps"); if (cfg.getSendTo() == null) out.write("" + _t("Outbound Endpoint") + ""); @@ -188,7 +189,8 @@ public class TunnelRenderer { else out.write(" \"Outbound\""); out.write(" " + DataHelper.formatDuration2(timeLeft) + "\n"); - out.write(" " + info.getProcessedMessagesCount() + " KB\n"); + int count = info.getProcessedMessagesCount(); + out.write(" " + count + " KB\n"); for (int j = 0; j < info.getLength(); j++) { Hash peer = info.getPeer(j); TunnelId id = (info.isInbound() ? info.getReceiveTunnelId(j) : info.getSendTunnelId(j)); @@ -206,9 +208,9 @@ public class TunnelRenderer { out.write("\n"); if (info.isInbound()) - processedIn += info.getProcessedMessagesCount(); + processedIn += count; else - processedOut += info.getProcessedMessagesCount(); + processedOut += count; } out.write("\n"); if (in != null) { diff --git a/history.txt b/history.txt index 3debcdab40..3d35346344 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,6 @@ +2015-11-13 zzz + * Console: Fix lifetime participating bandwidth display (ticket #1706) + 2015-11-12 zzz * Console /configclients: = Fix filtering and escaping diff --git a/router/java/src/net/i2p/router/RouterThrottleImpl.java b/router/java/src/net/i2p/router/RouterThrottleImpl.java index aafdea9fd6..9d0d0ddceb 100644 --- a/router/java/src/net/i2p/router/RouterThrottleImpl.java +++ b/router/java/src/net/i2p/router/RouterThrottleImpl.java @@ -276,7 +276,7 @@ class RouterThrottleImpl implements RouterThrottle { // ok, we're not hosed, but can we handle the bandwidth requirements // of another tunnel? - rs = _context.statManager().getRate("tunnel.participatingMessageCount"); + rs = _context.statManager().getRate("tunnel.participatingMessageCountAvgPerTunnel"); r = null; double messagesPerTunnel = DEFAULT_MESSAGES_PER_TUNNEL_ESTIMATE; if (rs != null) { diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 0e04b1445c..33006bcb1f 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 26; + public final static long BUILD = 27; /** for example "-test" */ public final static String EXTRA = "-rc"; diff --git a/router/java/src/net/i2p/router/tunnel/HopConfig.java b/router/java/src/net/i2p/router/tunnel/HopConfig.java index 447f6a0834..0e317cd79e 100644 --- a/router/java/src/net/i2p/router/tunnel/HopConfig.java +++ b/router/java/src/net/i2p/router/tunnel/HopConfig.java @@ -26,6 +26,7 @@ public class HopConfig { // these 4 were longs, let's save some space // 2 billion * 1KB / 10 minutes = 3 GBps in a single tunnel + // we use synchronization instead of an AtomicInteger here to save space private int _messagesProcessed; private int _oldMessagesProcessed; //private int _messagesSent; @@ -125,12 +126,29 @@ public class HopConfig { /** * Take note of a message being pumped through this tunnel. * "processed" is for incoming and "sent" is for outgoing (could be dropped in between) + * We use synchronization instead of an AtomicInteger here to save space. */ - public void incrementProcessedMessages() { _messagesProcessed++; } + public synchronized void incrementProcessedMessages() { _messagesProcessed++; } - public int getProcessedMessagesCount() { return _messagesProcessed; } + public synchronized int getProcessedMessagesCount() { return _messagesProcessed; } - public int getRecentMessagesCount() { + /** + * This returns the number of processed messages since + * the last time getAndResetRecentMessagesCount() was called. + * As of 0.9.23, does NOT reset the count, see getAndResetRecentMessagesCount(). + */ + public synchronized int getRecentMessagesCount() { + return _messagesProcessed - _oldMessagesProcessed; + } + + /** + * This returns the number of processed messages since the last time this was called, + * and resets the count. It should only be called by code that updates the router stats. + * See TunnelDispatcher.updateParticipatingStats(). + * + * @since 0.9.23 + */ + synchronized int getAndResetRecentMessagesCount() { int rv = _messagesProcessed - _oldMessagesProcessed; _oldMessagesProcessed = _messagesProcessed; return rv; @@ -169,8 +187,9 @@ public class HopConfig { } buf.append(" exp. ").append(TunnelCreatorConfig.format(_expiration)); - if (_messagesProcessed > 0) - buf.append(" used ").append(_messagesProcessed).append("KB"); + int messagesProcessed = getProcessedMessagesCount(); + if (messagesProcessed > 0) + buf.append(" used ").append(messagesProcessed).append("KB"); return buf.toString(); } } diff --git a/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java b/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java index 4e945b9db1..8e4d433353 100644 --- a/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java +++ b/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java @@ -163,9 +163,14 @@ public class TunnelDispatcher implements Service { ctx.statManager().createRateStat("tunnel.participatingMessageDropped", "Dropped for exceeding share limit", "Tunnels", new long[] { 60*1000l, 60*10*1000l }); + // count for console ctx.statManager().createRequiredRateStat("tunnel.participatingMessageCount", "Number of 1KB participating messages", "Tunnels", new long[] { 60*1000l, 60*10*1000l, 60*60*1000l }); + // estimate for RouterThrottleImpl + ctx.statManager().createRequiredRateStat("tunnel.participatingMessageCountAvgPerTunnel", + "Estimate of participating messages per tunnel lifetime", "Tunnels", + new long[] { 60*1000l }); ctx.statManager().createRateStat("tunnel.ownedMessageCount", "How many messages are sent through a tunnel we created (period == failures)?", "Tunnels", new long[] { 60*1000l, 10*60*1000l, 60*60*1000l }); @@ -711,7 +716,7 @@ public class TunnelDispatcher implements Service { long tooYoung = _context.clock().now() - 60*1000; long tooOld = tooYoung - 9*60*1000; for (HopConfig cfg : _participatingConfig.values()) { - long c = cfg.getRecentMessagesCount(); + long c = cfg.getAndResetRecentMessagesCount(); bw += c; //bwOut += cfg.getRecentSentMessagesCount(); long created = cfg.getCreation(); @@ -720,9 +725,15 @@ public class TunnelDispatcher implements Service { tcount++; count += c; } + // This is an estimate of the average number of participating messages per tunnel + // in a tunnel lifetime, used only by RouterThrottleImpl + // 10 minutes / 50 seconds = 12 if (tcount > 0) - count = count * 30 / tcount; - _context.statManager().addRateData("tunnel.participatingMessageCount", count, ms); + count = count * (10*60*1000 / ms) / tcount; + _context.statManager().addRateData("tunnel.participatingMessageCountAvgPerTunnel", count, ms); + // This is a straight count of the total participating messages, used in the router console + _context.statManager().addRateData("tunnel.participatingMessageCount", bw, ms); + // Bandwidth in bits per second _context.statManager().addRateData("tunnel.participatingBandwidth", bw*1024/(ms/1000), ms); // moved to FIFOBandwidthRefiller //_context.statManager().addRateData("tunnel.participatingBandwidthOut", bwOut*1024/(ms/1000), ms);