diff --git a/history.txt b/history.txt index 60dcfd9b78..98cd552e40 100644 --- a/history.txt +++ b/history.txt @@ -5,7 +5,11 @@ - Don't exceed high cap limit between reorgs - Reduce max reorg cycle time - Reduce new bonus values + - Fix rare NSEE thx sponge * SSU: Increase threshold for incremented cost + * Tunnels: + - Restore and implement lengthOverride() + - Adjust quantity override 2011-10-29 zzz * BuildHandler: Add router.buildHandlerThreads config setting diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index f6e6df3a5c..4e28a2c8d2 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 = 4; + public final static long BUILD = 5; /** for example "-test" */ public final static String EXTRA = ""; diff --git a/router/java/src/net/i2p/router/TunnelPoolSettings.java b/router/java/src/net/i2p/router/TunnelPoolSettings.java index 80c103c197..ee364e938a 100644 --- a/router/java/src/net/i2p/router/TunnelPoolSettings.java +++ b/router/java/src/net/i2p/router/TunnelPoolSettings.java @@ -19,7 +19,7 @@ public class TunnelPoolSettings { //private int _duration; private int _length; private int _lengthVariance; - //private int _lengthOverride; + private int _lengthOverride; private boolean _isInbound; private boolean _isExploratory; private boolean _allowZeroHop; @@ -60,6 +60,7 @@ public class TunnelPoolSettings { //_duration = DEFAULT_DURATION; _length = DEFAULT_LENGTH; _lengthVariance = DEFAULT_LENGTH_VARIANCE; + _lengthOverride = -1; _allowZeroHop = DEFAULT_ALLOW_ZERO_HOP; _IPRestriction = DEFAULT_IP_RESTRICTION; _unknownOptions = new Properties(); @@ -87,8 +88,16 @@ public class TunnelPoolSettings { // public int getRebuildPeriod() { return _rebuildPeriod; } // public void setRebuildPeriod(int periodMs) { _rebuildPeriod = periodMs; } - /** how many remote hops should be in the tunnel */ + /** + * How many remote hops should be in the tunnel NOT including us + * @return 0 to 7 + */ public int getLength() { return _length; } + + /** + * How many remote hops should be in the tunnel NOT including us + * @param length 0 to 7 (not enforced here) + */ public void setLength(int length) { _length = length; } /** if there are no tunnels to build with, will this pool allow 0 hop tunnels? */ @@ -104,10 +113,20 @@ public class TunnelPoolSettings { public int getLengthVariance() { return _lengthVariance; } public void setLengthVariance(int variance) { _lengthVariance = variance; } - /* UNUSED Set to a nonzero value to override the length setting */ - //public int getLengthOverride() { return _lengthOverride; } - //public void setLengthOverride(int variance) { _lengthOverride = variance; } - + /** + * A temporary length to be used due to network conditions. + * If less than zero, the standard length should be used. + * Unused until 0.8.11 + */ + public int getLengthOverride() { return _lengthOverride; } + + /** + * A temporary length to be used due to network conditions. + * If less than zero, the standard length will be used. + * Unused until 0.8.11 + */ + public void setLengthOverride(int length) { _lengthOverride = length; } + /** is this an inbound tunnel? */ public boolean isInbound() { return _isInbound; } public void setIsInbound(boolean isInbound) { _isInbound = isInbound; } diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java index 4b1171848c..2a7ae09f1c 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java @@ -47,11 +47,10 @@ public abstract class TunnelPeerSelector { */ protected int getLength(RouterContext ctx, TunnelPoolSettings settings) { int length = settings.getLength(); - //int override = settings.getLengthOverride(); - //if (override != 0) - // length = override; - //else if (settings.getLengthVariance() != 0) { - if (settings.getLengthVariance() != 0) { + int override = settings.getLengthOverride(); + if (override >= 0) { + length = override; + } else if (settings.getLengthVariance() != 0) { int skew = settings.getLengthVariance(); if (skew > 0) length += ctx.random().nextInt(skew+1); diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java index 55d62d5859..ebcded466f 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java @@ -43,7 +43,12 @@ public class TunnelPool { private long _lastRateUpdate; private long _lastLifetimeProcessed; private final String _rateName; + private static final int TUNNEL_LIFETIME = 10*60*1000; + /** if less than one success in this many, reduce quantity (exploratory only) */ + private static final int BUILD_TRIES_QUANTITY_OVERRIDE = 12; + /** if less than one success in this many, reduce length (exploratory only) */ + private static final int BUILD_TRIES_LENGTH_OVERRIDE = 18; TunnelPool(RouterContext ctx, TunnelPoolManager mgr, TunnelPoolSettings settings, TunnelPeerSelector sel) { _context = ctx; @@ -322,19 +327,16 @@ public class TunnelPool { RateStat r = _context.statManager().getRate("tunnel.buildExploratoryReject"); RateStat s = _context.statManager().getRate("tunnel.buildExploratorySuccess"); if (e != null && r != null && s != null) { - // 60 min was too long - is 10 min too short? - // By not adding in previous period, this gives us a burst every - // 10 min - is that good or bad? Rate er = e.getRate(10*60*1000); Rate rr = r.getRate(10*60*1000); Rate sr = s.getRate(10*60*1000); if (er != null && rr != null && sr != null) { - long ec = er.getCurrentEventCount(); - long rc = rr.getCurrentEventCount(); - long sc = sr.getCurrentEventCount(); + long ec = er.getCurrentEventCount() + er.getLastEventCount(); + long rc = rr.getCurrentEventCount() + rr.getLastEventCount(); + long sc = sr.getCurrentEventCount() + sr.getLastEventCount(); long tot = ec + rc + sc; - if (tot >= 10) { - if (1000 * sc / tot <= 1000 / 10) + if (tot >= BUILD_TRIES_QUANTITY_OVERRIDE) { + if (1000 * sc / tot <= 1000 / BUILD_TRIES_QUANTITY_OVERRIDE) rv--; } } @@ -343,6 +345,43 @@ public class TunnelPool { return rv; } + + /** + * Shorten the length when under extreme stress, else clear the override. + * We only do this for exploratory tunnels, since we have to build a fallback + * if we run out. It's much better to have a shorter tunnel than a fallback. + * + * @since 0.8.11 + */ + private void setLengthOverride() { + if (!_settings.isExploratory()) + return; + int len = _settings.getLength(); + if (len > 1) { + RateStat e = _context.statManager().getRate("tunnel.buildExploratoryExpire"); + RateStat r = _context.statManager().getRate("tunnel.buildExploratoryReject"); + RateStat s = _context.statManager().getRate("tunnel.buildExploratorySuccess"); + if (e != null && r != null && s != null) { + Rate er = e.getRate(10*60*1000); + Rate rr = r.getRate(10*60*1000); + Rate sr = s.getRate(10*60*1000); + if (er != null && rr != null && sr != null) { + long ec = er.getCurrentEventCount() + er.getLastEventCount(); + long rc = rr.getCurrentEventCount() + rr.getLastEventCount(); + long sc = sr.getCurrentEventCount() + sr.getLastEventCount(); + long tot = ec + rc + sc; + if (tot >= BUILD_TRIES_LENGTH_OVERRIDE) { + if (1000 * sc / tot <= 1000 / BUILD_TRIES_LENGTH_OVERRIDE) + _settings.setLengthOverride(len - 1); + return; + } + } + } + } + // disable + _settings.setLengthOverride(-1); + } + /** list of tunnelInfo instances of tunnels currently being built */ public List listPending() { synchronized (_inProgress) { return new ArrayList(_inProgress); } } @@ -1008,15 +1047,18 @@ public class TunnelPool { long expiration = now + TunnelPoolSettings.DEFAULT_DURATION; if (!forceZeroHop) { - int len = settings.getLength(); + int len = settings.getLengthOverride(); + if (len < 0) + len = settings.getLength(); if (len > 0 && _context.random().nextBoolean()) { // look for a tunnel to reuse, if the right length and expiring soon // ignore variance for now. len++; // us synchronized (_tunnels) { for (TunnelInfo ti : _tunnels) { - if (ti.getLength() == len && ti.getExpiration() < now + 3*60*1000 && !ti.wasReused()) { + if (ti.getLength() >= len && ti.getExpiration() < now + 3*60*1000 && !ti.wasReused()) { ti.setReused(); + len = ti.getLength(); peers = new ArrayList(len); // peers list is ordered endpoint first, but cfg.getPeer() is ordered gateway first for (int i = len - 1; i >= 0; i--) { @@ -1026,8 +1068,10 @@ public class TunnelPool { } } } - if (peers == null) + if (peers == null) { + setLengthOverride(); peers = _peerSelector.selectPeers(_context, settings); + } if ( (peers == null) || (peers.isEmpty()) ) { // no peers to build the tunnel with, and