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

@ -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 = "";

View File

@ -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,

View File

@ -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<TunnelPool> wanted, int allowed) {
for (int i = 0; i < wanted.size(); i++) {
TunnelPool pool = wanted.get(0);
for (Iterator<TunnelPool> 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);
}

View File

@ -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;

View File

@ -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() {