From 6fa13313f05bf62d21e0c91991be18fbccb271bd Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 23 Nov 2019 16:51:14 +0000 Subject: [PATCH] Tunnel building: - Don't count zero-hop tunnels as part of the pool when building - Don't build more than one zero-hop tunnel in a pool - Assume high build failure rate for new installs - Reduce threshold for tunnel length override --- history.txt | 7 ++++ .../src/net/i2p/router/RouterVersion.java | 2 +- .../net/i2p/router/TunnelPoolSettings.java | 7 +--- .../i2p/router/tunnel/pool/BuildExecutor.java | 14 +++---- .../i2p/router/tunnel/pool/TunnelPool.java | 39 ++++++++++++------- .../router/tunnel/pool/TunnelPoolManager.java | 4 +- 6 files changed, 43 insertions(+), 30 deletions(-) diff --git a/history.txt b/history.txt index 46de1302d..bddab445e 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,10 @@ +2019-11-23 zzz + * Router: + - Don't count zero-hop tunnels as part of the pool when building + - Don't build more than one zero-hop tunnel in a pool + - Assume high build failure rate for new installs + - Reduce threshold for tunnel length override + 2019-11-20 zzz * I2CP: - Prevent an uncaught OCMOSJ exception from killing the session diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 4e28a2c8d..c10128fe6 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 = 5; + public final static long BUILD = 6; /** 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 2c8a197b6..96349af66 100644 --- a/router/java/src/net/i2p/router/TunnelPoolSettings.java +++ b/router/java/src/net/i2p/router/TunnelPoolSettings.java @@ -111,10 +111,7 @@ public class TunnelPoolSettings { _lengthVariance = _isExploratory ? DEFAULT_OB_EXPL_LENGTH_VARIANCE : DEFAULT_LENGTH_VARIANCE; } _lengthOverride = -1; - if (_isExploratory) - _allowZeroHop = true; - else - _allowZeroHop = DEFAULT_ALLOW_ZERO_HOP; + _allowZeroHop = DEFAULT_ALLOW_ZERO_HOP; _IPRestriction = DEFAULT_IP_RESTRICTION; _unknownOptions = new Properties(); _randomKey = generateRandomKey(); @@ -162,7 +159,7 @@ public class TunnelPoolSettings { /** * If there are no tunnels to build with, will this pool allow 0 hop tunnels? * - * Always true for exploratory. + * As of 0.9.44, same goes for exploratory: * Prior to 0.9.35, generally true for client. * As of 0.9.35, generally false for client, but true if * getLength() + Math.min(getLengthVariance(), 0) <= 0, diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java index ca3014f82..d5f43c6b5 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java @@ -338,8 +338,9 @@ class BuildExecutor implements Runnable { if (!pool.isAlive()) continue; int howMany = pool.countHowManyToBuild(); - for (int j = 0; j < howMany; j++) + for (int j = 0; j < howMany; j++) { wanted.add(pool); + } } // allowed() also expires timed out requests (for new style requests) @@ -500,19 +501,18 @@ class BuildExecutor implements Runnable { * @return number of tunnels allowed after processing these zero hop tunnels (almost always the same as before) */ private int buildZeroHopTunnels(List wanted, int allowed) { - for (int i = 0; i < wanted.size(); i++) { - TunnelPool pool = wanted.get(0); + for (Iterator iter = wanted.iterator(); iter.hasNext(); ) { + TunnelPool pool = iter.next(); if (pool.getSettings().getLength() == 0) { PooledTunnelCreatorConfig cfg = pool.configureNewTunnel(); if (cfg != null) { if (_log.shouldLog(Log.DEBUG)) - _log.debug("Configuring short tunnel " + i + " for " + pool + ": " + cfg); + _log.debug("Configuring short tunnel for " + pool + ": " + cfg); buildTunnel(cfg); if (cfg.getLength() > 1) { allowed--; // oops... shouldn't have done that, but hey, its not that bad... } - wanted.remove(i); - i--; + iter.remove(); } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Configured a null tunnel"); @@ -571,7 +571,7 @@ class BuildExecutor implements Runnable { _currentlyBuilding.notifyAll(); } } else { - if (_log.shouldLog(Log.INFO)) + if (cfg.getLength() > 1 && _log.shouldLog(Log.INFO)) _log.info("Build complete really fast (" + buildTime + " ms) for tunnel: " + cfg); } 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 0415261e3..82befb362 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java @@ -47,13 +47,14 @@ public class TunnelPool { private long _lastRateUpdate; private long _lastLifetimeProcessed; private final String _rateName; + private final long _firstInstalled; 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_1 = 10; - private static final int BUILD_TRIES_LENGTH_OVERRIDE_2 = 18; + private static final int BUILD_TRIES_LENGTH_OVERRIDE_1 = 8; + private static final int BUILD_TRIES_LENGTH_OVERRIDE_2 = 12; private static final long STARTUP_TIME = 30*60*1000; TunnelPool(RouterContext ctx, TunnelPoolManager mgr, TunnelPoolSettings settings, TunnelPeerSelector sel) { @@ -66,6 +67,7 @@ public class TunnelPool { _expireSkew = _context.random().nextInt(90*1000); _started = System.currentTimeMillis(); _lastRateUpdate = _started; + _firstInstalled = ctx.getProperty("router.firstInstalled", 0L) + 60*60*1000; String name; if (_settings.isExploratory()) { name = "exploratory"; @@ -315,15 +317,15 @@ public class TunnelPool { /** * Do we really need more fallbacks? - * Used to prevent a zillion of them + * Used to prevent a zillion of them. + * Does not check config, only call if config allows zero hop. */ boolean needFallback() { - int needed = getAdjustedTotalQuantity(); - int fallbacks = 0; + long exp = _context.clock().now() + 120*1000; synchronized (_tunnels) { for (int i = 0; i < _tunnels.size(); i++) { TunnelInfo info = _tunnels.get(i); - if (info.getLength() <= 1 && ++fallbacks >= needed) + if (info.getLength() <= 1 && info.getExpiration() > exp) return false; } } @@ -343,16 +345,22 @@ public class TunnelPool { * generate a lot of exploratory traffic. * TODO high-bandwidth non-floodfills do also... * + * Also returns 1 if set for zero hop, client or exploratory. + * * @since 0.8.11 */ private int getAdjustedTotalQuantity() { + if (_settings.getLength() == 0 && _settings.getLengthVariance() == 0) + return 1; int rv = _settings.getTotalQuantity(); + if (!_settings.isExploratory()) + return rv; // TODO high-bw non-ff also - if (_settings.isExploratory() && _context.netDb().floodfillEnabled() && + if (_context.netDb().floodfillEnabled() && _context.router().getUptime() > 5*60*1000) { rv += 2; } - if (_settings.isExploratory() && rv > 1) { + if (rv > 1) { RateStat e = _context.statManager().getRate("tunnel.buildExploratoryExpire"); RateStat r = _context.statManager().getRate("tunnel.buildExploratoryReject"); RateStat s = _context.statManager().getRate("tunnel.buildExploratorySuccess"); @@ -373,7 +381,7 @@ public class TunnelPool { } } } - if (_settings.isExploratory() && _context.router().getUptime() < STARTUP_TIME) { + if (_context.router().getUptime() < STARTUP_TIME) { // more exploratory during startup, when we are refreshing the netdb RIs rv++; } @@ -406,8 +414,9 @@ public class TunnelPool { long rc = rr.computeAverages(ra, false).getTotalEventCount(); long sc = sr.computeAverages(ra, false).getTotalEventCount(); long tot = ec + rc + sc; - if (tot >= BUILD_TRIES_LENGTH_OVERRIDE_1) { - long succ = 1000 * sc / tot; + if (tot >= BUILD_TRIES_LENGTH_OVERRIDE_1 || + _firstInstalled > _context.clock().now()) { + long succ = tot > 0 ? 1000 * sc / tot : 0; if (succ <= 1000 / BUILD_TRIES_LENGTH_OVERRIDE_1) { if (len > 2 && succ <= 1000 / BUILD_TRIES_LENGTH_OVERRIDE_2) _settings.setLengthOverride(len - 2); @@ -644,8 +653,10 @@ public class TunnelPool { } /** - * @return true if a fallback tunnel is built + * This will build a fallback (zero-hop) tunnel ONLY if + * this pool is exploratory, or the settings allow it. * + * @return true if a fallback tunnel is built */ boolean buildFallback() { int quantity = getAdjustedTotalQuantity(); @@ -656,7 +667,7 @@ public class TunnelPool { if (usable > 0) return false; - if (_settings.getAllowZeroHop()) { + if (_settings.isExploratory() || _settings.getAllowZeroHop()) { if (_log.shouldLog(Log.INFO)) _log.info(toString() + ": building a fallback tunnel (usable: " + usable + " needed: " + quantity + ")"); @@ -910,8 +921,6 @@ public class TunnelPool { inProgress = _inProgress.size(); } int remainingWanted = (wanted - expireLater) - inProgress; - if (allowZeroHop) - remainingWanted -= fallback; int rv = 0; int latesttime = 0; diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java index 91efb1630..792305deb 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java @@ -586,11 +586,11 @@ public class TunnelPoolManager implements TunnelManagerFacade { } private static class BootstrapPool extends JobImpl { - private TunnelPool _pool; + private final TunnelPool _pool; public BootstrapPool(RouterContext ctx, TunnelPool pool) { super(ctx); _pool = pool; - getTiming().setStartAfter(ctx.clock().now() + 30*1000); + getTiming().setStartAfter(ctx.clock().now() + 5*1000); } public String getName() { return "Bootstrap tunnel pool"; } public void runJob() {