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
This commit is contained in:
zzz
2019-11-23 16:51:14 +00:00
parent 27fa991783
commit 6fa13313f0
6 changed files with 43 additions and 30 deletions

View File

@ -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 2019-11-20 zzz
* I2CP: * I2CP:
- Prevent an uncaught OCMOSJ exception from killing the session - Prevent an uncaught OCMOSJ exception from killing the session

View File

@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */ /** deprecated */
public final static String ID = "Monotone"; public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION; public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 5; public final static long BUILD = 6;
/** for example "-test" */ /** for example "-test" */
public final static String EXTRA = ""; public final static String EXTRA = "";

View File

@ -111,10 +111,7 @@ public class TunnelPoolSettings {
_lengthVariance = _isExploratory ? DEFAULT_OB_EXPL_LENGTH_VARIANCE : DEFAULT_LENGTH_VARIANCE; _lengthVariance = _isExploratory ? DEFAULT_OB_EXPL_LENGTH_VARIANCE : DEFAULT_LENGTH_VARIANCE;
} }
_lengthOverride = -1; _lengthOverride = -1;
if (_isExploratory) _allowZeroHop = DEFAULT_ALLOW_ZERO_HOP;
_allowZeroHop = true;
else
_allowZeroHop = DEFAULT_ALLOW_ZERO_HOP;
_IPRestriction = DEFAULT_IP_RESTRICTION; _IPRestriction = DEFAULT_IP_RESTRICTION;
_unknownOptions = new Properties(); _unknownOptions = new Properties();
_randomKey = generateRandomKey(); _randomKey = generateRandomKey();
@ -162,7 +159,7 @@ public class TunnelPoolSettings {
/** /**
* If there are no tunnels to build with, will this pool allow 0 hop tunnels? * 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. * Prior to 0.9.35, generally true for client.
* As of 0.9.35, generally false for client, but true if * As of 0.9.35, generally false for client, but true if
* getLength() + Math.min(getLengthVariance(), 0) <= 0, * getLength() + Math.min(getLengthVariance(), 0) <= 0,

View File

@ -338,8 +338,9 @@ class BuildExecutor implements Runnable {
if (!pool.isAlive()) if (!pool.isAlive())
continue; continue;
int howMany = pool.countHowManyToBuild(); int howMany = pool.countHowManyToBuild();
for (int j = 0; j < howMany; j++) for (int j = 0; j < howMany; j++) {
wanted.add(pool); wanted.add(pool);
}
} }
// allowed() also expires timed out requests (for new style requests) // 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) * @return number of tunnels allowed after processing these zero hop tunnels (almost always the same as before)
*/ */
private int buildZeroHopTunnels(List<TunnelPool> wanted, int allowed) { private int buildZeroHopTunnels(List<TunnelPool> wanted, int allowed) {
for (int i = 0; i < wanted.size(); i++) { for (Iterator<TunnelPool> iter = wanted.iterator(); iter.hasNext(); ) {
TunnelPool pool = wanted.get(0); TunnelPool pool = iter.next();
if (pool.getSettings().getLength() == 0) { if (pool.getSettings().getLength() == 0) {
PooledTunnelCreatorConfig cfg = pool.configureNewTunnel(); PooledTunnelCreatorConfig cfg = pool.configureNewTunnel();
if (cfg != null) { if (cfg != null) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Configuring short tunnel " + i + " for " + pool + ": " + cfg); _log.debug("Configuring short tunnel for " + pool + ": " + cfg);
buildTunnel(cfg); buildTunnel(cfg);
if (cfg.getLength() > 1) { if (cfg.getLength() > 1) {
allowed--; // oops... shouldn't have done that, but hey, its not that bad... allowed--; // oops... shouldn't have done that, but hey, its not that bad...
} }
wanted.remove(i); iter.remove();
i--;
} else { } else {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Configured a null tunnel"); _log.debug("Configured a null tunnel");
@ -571,7 +571,7 @@ class BuildExecutor implements Runnable {
_currentlyBuilding.notifyAll(); _currentlyBuilding.notifyAll();
} }
} else { } 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); _log.info("Build complete really fast (" + buildTime + " ms) for tunnel: " + cfg);
} }

View File

@ -47,13 +47,14 @@ public class TunnelPool {
private long _lastRateUpdate; private long _lastRateUpdate;
private long _lastLifetimeProcessed; private long _lastLifetimeProcessed;
private final String _rateName; private final String _rateName;
private final long _firstInstalled;
private static final int TUNNEL_LIFETIME = 10*60*1000; private static final int TUNNEL_LIFETIME = 10*60*1000;
/** if less than one success in this many, reduce quantity (exploratory only) */ /** if less than one success in this many, reduce quantity (exploratory only) */
private static final int BUILD_TRIES_QUANTITY_OVERRIDE = 12; private static final int BUILD_TRIES_QUANTITY_OVERRIDE = 12;
/** if less than one success in this many, reduce length (exploratory only) */ /** 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_1 = 8;
private static final int BUILD_TRIES_LENGTH_OVERRIDE_2 = 18; private static final int BUILD_TRIES_LENGTH_OVERRIDE_2 = 12;
private static final long STARTUP_TIME = 30*60*1000; private static final long STARTUP_TIME = 30*60*1000;
TunnelPool(RouterContext ctx, TunnelPoolManager mgr, TunnelPoolSettings settings, TunnelPeerSelector sel) { TunnelPool(RouterContext ctx, TunnelPoolManager mgr, TunnelPoolSettings settings, TunnelPeerSelector sel) {
@ -66,6 +67,7 @@ public class TunnelPool {
_expireSkew = _context.random().nextInt(90*1000); _expireSkew = _context.random().nextInt(90*1000);
_started = System.currentTimeMillis(); _started = System.currentTimeMillis();
_lastRateUpdate = _started; _lastRateUpdate = _started;
_firstInstalled = ctx.getProperty("router.firstInstalled", 0L) + 60*60*1000;
String name; String name;
if (_settings.isExploratory()) { if (_settings.isExploratory()) {
name = "exploratory"; name = "exploratory";
@ -315,15 +317,15 @@ public class TunnelPool {
/** /**
* Do we really need more fallbacks? * 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() { boolean needFallback() {
int needed = getAdjustedTotalQuantity(); long exp = _context.clock().now() + 120*1000;
int fallbacks = 0;
synchronized (_tunnels) { synchronized (_tunnels) {
for (int i = 0; i < _tunnels.size(); i++) { for (int i = 0; i < _tunnels.size(); i++) {
TunnelInfo info = _tunnels.get(i); TunnelInfo info = _tunnels.get(i);
if (info.getLength() <= 1 && ++fallbacks >= needed) if (info.getLength() <= 1 && info.getExpiration() > exp)
return false; return false;
} }
} }
@ -343,16 +345,22 @@ public class TunnelPool {
* generate a lot of exploratory traffic. * generate a lot of exploratory traffic.
* TODO high-bandwidth non-floodfills do also... * TODO high-bandwidth non-floodfills do also...
* *
* Also returns 1 if set for zero hop, client or exploratory.
*
* @since 0.8.11 * @since 0.8.11
*/ */
private int getAdjustedTotalQuantity() { private int getAdjustedTotalQuantity() {
if (_settings.getLength() == 0 && _settings.getLengthVariance() == 0)
return 1;
int rv = _settings.getTotalQuantity(); int rv = _settings.getTotalQuantity();
if (!_settings.isExploratory())
return rv;
// TODO high-bw non-ff also // TODO high-bw non-ff also
if (_settings.isExploratory() && _context.netDb().floodfillEnabled() && if (_context.netDb().floodfillEnabled() &&
_context.router().getUptime() > 5*60*1000) { _context.router().getUptime() > 5*60*1000) {
rv += 2; rv += 2;
} }
if (_settings.isExploratory() && rv > 1) { if (rv > 1) {
RateStat e = _context.statManager().getRate("tunnel.buildExploratoryExpire"); RateStat e = _context.statManager().getRate("tunnel.buildExploratoryExpire");
RateStat r = _context.statManager().getRate("tunnel.buildExploratoryReject"); RateStat r = _context.statManager().getRate("tunnel.buildExploratoryReject");
RateStat s = _context.statManager().getRate("tunnel.buildExploratorySuccess"); 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 // more exploratory during startup, when we are refreshing the netdb RIs
rv++; rv++;
} }
@ -406,8 +414,9 @@ public class TunnelPool {
long rc = rr.computeAverages(ra, false).getTotalEventCount(); long rc = rr.computeAverages(ra, false).getTotalEventCount();
long sc = sr.computeAverages(ra, false).getTotalEventCount(); long sc = sr.computeAverages(ra, false).getTotalEventCount();
long tot = ec + rc + sc; long tot = ec + rc + sc;
if (tot >= BUILD_TRIES_LENGTH_OVERRIDE_1) { if (tot >= BUILD_TRIES_LENGTH_OVERRIDE_1 ||
long succ = 1000 * sc / tot; _firstInstalled > _context.clock().now()) {
long succ = tot > 0 ? 1000 * sc / tot : 0;
if (succ <= 1000 / BUILD_TRIES_LENGTH_OVERRIDE_1) { if (succ <= 1000 / BUILD_TRIES_LENGTH_OVERRIDE_1) {
if (len > 2 && succ <= 1000 / BUILD_TRIES_LENGTH_OVERRIDE_2) if (len > 2 && succ <= 1000 / BUILD_TRIES_LENGTH_OVERRIDE_2)
_settings.setLengthOverride(len - 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() { boolean buildFallback() {
int quantity = getAdjustedTotalQuantity(); int quantity = getAdjustedTotalQuantity();
@ -656,7 +667,7 @@ public class TunnelPool {
if (usable > 0) if (usable > 0)
return false; return false;
if (_settings.getAllowZeroHop()) { if (_settings.isExploratory() || _settings.getAllowZeroHop()) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info(toString() + ": building a fallback tunnel (usable: " + usable + " needed: " + quantity + ")"); _log.info(toString() + ": building a fallback tunnel (usable: " + usable + " needed: " + quantity + ")");
@ -910,8 +921,6 @@ public class TunnelPool {
inProgress = _inProgress.size(); inProgress = _inProgress.size();
} }
int remainingWanted = (wanted - expireLater) - inProgress; int remainingWanted = (wanted - expireLater) - inProgress;
if (allowZeroHop)
remainingWanted -= fallback;
int rv = 0; int rv = 0;
int latesttime = 0; int latesttime = 0;

View File

@ -586,11 +586,11 @@ public class TunnelPoolManager implements TunnelManagerFacade {
} }
private static class BootstrapPool extends JobImpl { private static class BootstrapPool extends JobImpl {
private TunnelPool _pool; private final TunnelPool _pool;
public BootstrapPool(RouterContext ctx, TunnelPool pool) { public BootstrapPool(RouterContext ctx, TunnelPool pool) {
super(ctx); super(ctx);
_pool = pool; _pool = pool;
getTiming().setStartAfter(ctx.clock().now() + 30*1000); getTiming().setStartAfter(ctx.clock().now() + 5*1000);
} }
public String getName() { return "Bootstrap tunnel pool"; } public String getName() { return "Bootstrap tunnel pool"; }
public void runJob() { public void runJob() {