diff --git a/history.txt b/history.txt index 7a8bfb2e3..5e72be984 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,9 @@ -$Id: history.txt,v 1.473 2006/05/11 22:31:44 jrandom Exp $ +$Id: history.txt,v 1.474 2006/05/13 23:52:44 complication Exp $ + +2006-05-15 jrandom + * Add a load dependent throttle on the pending inbound tunnel request + backlog + * Increased the tunnel test failure slack before killing a tunnel 2006-05-13 Complication * Separate growth factors for tunnel count and tunnel test time diff --git a/router/java/src/net/i2p/router/RouterThrottleImpl.java b/router/java/src/net/i2p/router/RouterThrottleImpl.java index 12f28c26b..4e10e351f 100644 --- a/router/java/src/net/i2p/router/RouterThrottleImpl.java +++ b/router/java/src/net/i2p/router/RouterThrottleImpl.java @@ -52,6 +52,7 @@ class RouterThrottleImpl implements RouterThrottle { _context.statManager().createRateStat("router.throttleTunnelBytesAllowed", "How many bytes are allowed to be sent when we get a tunnel request (period is how many are currently allocated)?", "Throttle", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 }); _context.statManager().createRateStat("router.throttleTunnelBytesUsed", "Used Bps at request (period = max KBps)?", "Throttle", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 }); _context.statManager().createRateStat("router.throttleTunnelFailCount1m", "How many messages failed to be sent in the last 2 minutes when we throttle based on a spike in failures (period = 10 minute average failure count)?", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000}); + _context.statManager().createRateStat("router.throttleTunnelQueueOverload", "How many pending tunnel request messages have we received when we reject them due to overload (period = time to process each)?", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000}); } public boolean acceptNetworkMessage() { @@ -139,41 +140,41 @@ class RouterThrottleImpl implements RouterThrottle { } } - double tunnelTestTimeGrowthFactor = getTunnelTestTimeGrowthFactor(); - Rate tunnelTestTime1m = _context.statManager().getRate("tunnel.testSuccessTime").getRate(1*60*1000); - Rate tunnelTestTime60m = _context.statManager().getRate("tunnel.testSuccessTime").getRate(60*60*1000); - if ( (tunnelTestTime1m != null) && (tunnelTestTime60m != null) && (tunnelTestTime1m.getLastEventCount() > 0) ) { - double avg1m = tunnelTestTime1m.getAverageValue(); - double avg60m = 0; - if (tunnelTestTime60m.getLastEventCount() > 0) - avg60m = tunnelTestTime60m.getAverageValue(); - else - avg60m = tunnelTestTime60m.getLifetimeAverageValue(); - - if (avg60m < 2000) - avg60m = 2000; // minimum before complaining - - if ( (avg60m > 0) && (avg1m > avg60m * tunnelTestTimeGrowthFactor) ) { - double probAccept = (avg60m*tunnelTestTimeGrowthFactor)/avg1m; - probAccept = probAccept * probAccept; // square the decelerator for test times - int v = _context.random().nextInt(100); - if (v < probAccept*100) { - // ok - if (_log.shouldLog(Log.INFO)) - _log.info("Probabalistically accept tunnel request (p=" + probAccept - + " v=" + v + " test time avg 1m=" + avg1m + " 60m=" + avg60m + ")"); - } else { - if (_log.shouldLog(Log.WARN)) - _log.warn("Probabalistically refusing tunnel request (test time avg 1m=" + avg1m - + " 60m=" + avg60m + ")"); - _context.statManager().addRateData("router.throttleTunnelProbTestSlow", (long)(avg1m-avg60m), 0); - return TunnelHistory.TUNNEL_REJECT_PROBABALISTIC_REJECT; - } - } else { + double tunnelTestTimeGrowthFactor = getTunnelTestTimeGrowthFactor(); + Rate tunnelTestTime1m = _context.statManager().getRate("tunnel.testSuccessTime").getRate(1*60*1000); + Rate tunnelTestTime60m = _context.statManager().getRate("tunnel.testSuccessTime").getRate(60*60*1000); + if ( (tunnelTestTime1m != null) && (tunnelTestTime60m != null) && (tunnelTestTime1m.getLastEventCount() > 0) ) { + double avg1m = tunnelTestTime1m.getAverageValue(); + double avg60m = 0; + if (tunnelTestTime60m.getLastEventCount() > 0) + avg60m = tunnelTestTime60m.getAverageValue(); + else + avg60m = tunnelTestTime60m.getLifetimeAverageValue(); + + if (avg60m < 2000) + avg60m = 2000; // minimum before complaining + + if ( (avg60m > 0) && (avg1m > avg60m * tunnelTestTimeGrowthFactor) ) { + double probAccept = (avg60m*tunnelTestTimeGrowthFactor)/avg1m; + probAccept = probAccept * probAccept; // square the decelerator for test times + int v = _context.random().nextInt(100); + if (v < probAccept*100) { + // ok if (_log.shouldLog(Log.INFO)) - _log.info("Accepting tunnel request, since 60m test time average is " + avg60m - + " and past 1m only has " + avg1m + ")"); + _log.info("Probabalistically accept tunnel request (p=" + probAccept + + " v=" + v + " test time avg 1m=" + avg1m + " 60m=" + avg60m + ")"); + } else { + if (_log.shouldLog(Log.WARN)) + _log.warn("Probabalistically refusing tunnel request (test time avg 1m=" + avg1m + + " 60m=" + avg60m + ")"); + _context.statManager().addRateData("router.throttleTunnelProbTestSlow", (long)(avg1m-avg60m), 0); + return TunnelHistory.TUNNEL_REJECT_PROBABALISTIC_REJECT; } + } else { + if (_log.shouldLog(Log.INFO)) + _log.info("Accepting tunnel request, since 60m test time average is " + avg60m + + " and past 1m only has " + avg1m + ")"); + } } String maxTunnels = _context.getProperty(PROP_MAX_TUNNELS); @@ -215,9 +216,30 @@ class RouterThrottleImpl implements RouterThrottle { _context.statManager().addRateData("router.throttleTunnelBandwidthExceeded", (long)bytesAllocated, 0); return TunnelHistory.TUNNEL_REJECT_BANDWIDTH; } + + int queuedRequests = _context.tunnelManager().getInboundBuildQueueSize(); + int timePerRequest = 1000; + rs = _context.statManager().getRate("tunnel.decryptRequestTime"); + if (rs != null) { + r = rs.getRate(60*1000); + if (r.getLastEventCount() > 0) + timePerRequest = (int)r.getAverageValue(); + else + timePerRequest = (int)rs.getLifetimeAverageValue(); + } + float pctFull = (queuedRequests * timePerRequest) / (10*1000f); + float pReject = 1 - ((1-pctFull) * (1-pctFull)); + if ( (pctFull >= 1) || (pReject >= _context.random().nextFloat()) ) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Rejecting a new tunnel request because we have too many pending requests (" + queuedRequests + + " at " + timePerRequest + "ms each, %full = " + pctFull); + _context.statManager().addRateData("router.throttleTunnelQueueOverload", queuedRequests, timePerRequest); + return TunnelHistory.TUNNEL_REJECT_TRANSIENT_OVERLOAD; + } + + // ok, all is well, let 'er in _context.statManager().addRateData("tunnel.bytesAllocatedAtAccept", (long)bytesAllocated, 60*10*1000); - if (_log.shouldLog(Log.DEBUG)) _log.debug("Accepting a new tunnel request (now allocating " + bytesAllocated + " bytes across " + numTunnels + " tunnels with lag of " + lag + ")"); diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 8901e1ac9..6c1692c67 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.413 $ $Date: 2006/05/11 22:31:47 $"; + public final static String ID = "$Revision: 1.414 $ $Date: 2006/05/14 00:11:36 $"; public final static String VERSION = "0.6.1.18"; - public final static long BUILD = 2; + public final static long BUILD = 3; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java b/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java index 730c3c39d..d79891983 100644 --- a/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java +++ b/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java @@ -137,7 +137,7 @@ public class TunnelCreatorConfig implements TunnelInfo { } - private static final int MAX_CONSECUTIVE_TEST_FAILURES = 2; + private static final int MAX_CONSECUTIVE_TEST_FAILURES = 3; /** * The tunnel failed, so stop using it