* Tunnel TestJob:

- Don't continue testing after the pool is dead
    - Tweak test intervals
  * TunnelPool: Make more methods package private
This commit is contained in:
zzz
2011-07-19 20:54:22 +00:00
parent c78719bfe4
commit 56d8b72b07
3 changed files with 61 additions and 25 deletions

View File

@@ -23,6 +23,10 @@ import net.i2p.stat.Rate;
import net.i2p.stat.RateStat; import net.i2p.stat.RateStat;
import net.i2p.util.Log; import net.i2p.util.Log;
/**
* Repeatedly test a single tunnel for its entire lifetime,
* or until the pool is shut down or removed from the client manager.
*/
class TestJob extends JobImpl { class TestJob extends JobImpl {
private final Log _log; private final Log _log;
private final TunnelPool _pool; private final TunnelPool _pool;
@@ -35,7 +39,7 @@ class TestJob extends JobImpl {
private SessionTag _encryptTag; private SessionTag _encryptTag;
/** base to randomize the test delay on */ /** base to randomize the test delay on */
private static final int TEST_DELAY = 30*1000; private static final int TEST_DELAY = 40*1000;
public TestJob(RouterContext ctx, PooledTunnelCreatorConfig cfg, TunnelPool pool) { public TestJob(RouterContext ctx, PooledTunnelCreatorConfig cfg, TunnelPool pool) {
super(ctx); super(ctx);
@@ -54,7 +58,7 @@ class TestJob extends JobImpl {
public String getName() { return "Test tunnel"; } public String getName() { return "Test tunnel"; }
public void runJob() { public void runJob() {
if (_pool == null) if (_pool == null || !_pool.isAlive())
return; return;
long lag = getContext().jobQueue().getMaxLag(); long lag = getContext().jobQueue().getMaxLag();
if (lag > 3000) { if (lag > 3000) {
@@ -155,6 +159,8 @@ class TestJob extends JobImpl {
} }
public void testSuccessful(int ms) { public void testSuccessful(int ms) {
if (_pool == null || !_pool.isAlive())
return;
getContext().statManager().addRateData("tunnel.testSuccessLength", _cfg.getLength(), 0); getContext().statManager().addRateData("tunnel.testSuccessLength", _cfg.getLength(), 0);
getContext().statManager().addRateData("tunnel.testSuccessTime", ms, 0); getContext().statManager().addRateData("tunnel.testSuccessTime", ms, 0);
@@ -182,6 +188,8 @@ class TestJob extends JobImpl {
} }
private void testFailed(long timeToFail) { private void testFailed(long timeToFail) {
if (_pool == null || !_pool.isAlive())
return;
if (_found) { if (_found) {
// ok, not really a /success/, but we did find it, even though slowly // ok, not really a /success/, but we did find it, even though slowly
noteSuccess(timeToFail, _outTunnel); noteSuccess(timeToFail, _outTunnel);
@@ -208,7 +216,7 @@ class TestJob extends JobImpl {
} }
/** randomized time we should wait before testing */ /** randomized time we should wait before testing */
private int getDelay() { return TEST_DELAY + getContext().random().nextInt(TEST_DELAY); } private int getDelay() { return TEST_DELAY + getContext().random().nextInt(TEST_DELAY / 3); }
/** how long we allow tests to run for before failing them */ /** how long we allow tests to run for before failing them */
private int getTestPeriod() { private int getTestPeriod() {
@@ -234,8 +242,11 @@ class TestJob extends JobImpl {
private void scheduleRetest() { scheduleRetest(false); } private void scheduleRetest() { scheduleRetest(false); }
private void scheduleRetest(boolean asap) { private void scheduleRetest(boolean asap) {
if (_pool == null || !_pool.isAlive())
return;
if (asap) { if (asap) {
requeue(getContext().random().nextInt(TEST_DELAY)); if (_cfg.getExpiration() > getContext().clock().now() + (60 * 1000))
requeue((TEST_DELAY / 4) + getContext().random().nextInt(TEST_DELAY / 4));
} else { } else {
int delay = getDelay(); int delay = getDelay();
if (_cfg.getExpiration() > getContext().clock().now() + delay + (3 * getTestPeriod())) if (_cfg.getExpiration() > getContext().clock().now() + delay + (3 * getTestPeriod()))

View File

@@ -23,6 +23,7 @@ import net.i2p.util.Log;
/** /**
* A group of tunnels for the router or a particular client, in a single direction. * A group of tunnels for the router or a particular client, in a single direction.
* Public only for TunnelRenderer in router console.
*/ */
public class TunnelPool { public class TunnelPool {
private final List<PooledTunnelCreatorConfig> _inProgress = new ArrayList(); private final List<PooledTunnelCreatorConfig> _inProgress = new ArrayList();
@@ -43,7 +44,7 @@ public class TunnelPool {
private final String _rateName; private final String _rateName;
private static final int TUNNEL_LIFETIME = 10*60*1000; private static final int TUNNEL_LIFETIME = 10*60*1000;
public TunnelPool(RouterContext ctx, TunnelPoolManager mgr, TunnelPoolSettings settings, TunnelPeerSelector sel) { TunnelPool(RouterContext ctx, TunnelPoolManager mgr, TunnelPoolSettings settings, TunnelPeerSelector sel) {
_context = ctx; _context = ctx;
_log = ctx.logManager().getLog(TunnelPool.class); _log = ctx.logManager().getLog(TunnelPool.class);
_manager = mgr; _manager = mgr;
@@ -59,10 +60,18 @@ public class TunnelPool {
refreshSettings(); refreshSettings();
} }
public void startup() { /**
* Warning, this may be called more than once
* (without an intervening shutdown()) if the
* tunnel is stopped and then restarted by the client manager with the same
* Destination (i.e. for servers or clients w/ persistent key)
*/
void startup() {
synchronized (_inProgress) { synchronized (_inProgress) {
_inProgress.clear(); _inProgress.clear();
} }
if (_log.shouldLog(Log.WARN))
_log.warn(toString() + ": Startup() called, was already alive? " + _alive, new Exception());
_alive = true; _alive = true;
_started = System.currentTimeMillis(); _started = System.currentTimeMillis();
_lastRateUpdate = _started; _lastRateUpdate = _started;
@@ -84,7 +93,9 @@ public class TunnelPool {
new long[] { 5*60*1000l }); new long[] { 5*60*1000l });
} }
public void shutdown() { void shutdown() {
if (_log.shouldLog(Log.WARN))
_log.warn(toString() + ": Shutdown called", new Exception());
_alive = false; _alive = false;
_lastSelectionPeriod = 0; _lastSelectionPeriod = 0;
_lastSelected = null; _lastSelected = null;
@@ -132,7 +143,8 @@ public class TunnelPool {
* and returns it. * and returns it.
* *
*/ */
public TunnelInfo selectTunnel() { return selectTunnel(true); } TunnelInfo selectTunnel() { return selectTunnel(true); }
private TunnelInfo selectTunnel(boolean allowRecurseOnFail) { private TunnelInfo selectTunnel(boolean allowRecurseOnFail) {
boolean avoidZeroHop = ((getSettings().getLength() + getSettings().getLengthVariance()) > 0); boolean avoidZeroHop = ((getSettings().getLength() + getSettings().getLengthVariance()) > 0);
@@ -239,7 +251,7 @@ 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
*/ */
public boolean needFallback() { boolean needFallback() {
int needed = _settings.getBackupQuantity() + _settings.getQuantity(); int needed = _settings.getBackupQuantity() + _settings.getQuantity();
int fallbacks = 0; int fallbacks = 0;
synchronized (_tunnels) { synchronized (_tunnels) {
@@ -259,7 +271,8 @@ public class TunnelPool {
int getTunnelCount() { synchronized (_tunnels) { return _tunnels.size(); } } int getTunnelCount() { synchronized (_tunnels) { return _tunnels.size(); } }
public TunnelPoolSettings getSettings() { return _settings; } public TunnelPoolSettings getSettings() { return _settings; }
public void setSettings(TunnelPoolSettings settings) {
void setSettings(TunnelPoolSettings settings) {
_settings = settings; _settings = settings;
if (_settings != null) { if (_settings != null) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
@@ -267,8 +280,19 @@ public class TunnelPool {
_manager.getExecutor().repoll(); // in case we need more _manager.getExecutor().repoll(); // in case we need more
} }
} }
public TunnelPeerSelector getSelector() { return _peerSelector; }
public boolean isAlive() { return _alive; } /**
* Is this pool running AND either exploratory, or tracked by the client manager?
* A pool will be alive but not tracked after the client manager removes it
* but before all the tunnels have expired.
*/
public boolean isAlive() {
return _alive &&
(_settings.isExploratory() ||
(_settings.getDestination() != null &&
_context.clientManager().isLocal(_settings.getDestination())));
}
/** duplicate of getTunnelCount(), let's pick one */ /** duplicate of getTunnelCount(), let's pick one */
public int size() { public int size() {
synchronized (_tunnels) { synchronized (_tunnels) {
@@ -336,17 +360,14 @@ public class TunnelPool {
} }
} }
boolean connected = true; if (getTunnelCount() <= 0 && !isAlive()) {
if ( (_settings.getDestination() != null) && (!_context.clientManager().isLocal(_settings.getDestination())) ) // this calls both our shutdown() and the other one (inbound/outbound)
connected = false;
if ( (getTunnelCount() <= 0) && (!connected) ) {
_manager.removeTunnels(_settings.getDestination()); _manager.removeTunnels(_settings.getDestination());
return;
} }
} }
/** This may be called multiple times from TestJob */ /** This may be called multiple times from TestJob */
public void tunnelFailed(PooledTunnelCreatorConfig cfg) { void tunnelFailed(PooledTunnelCreatorConfig cfg) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn(toString() + ": Tunnel failed: " + cfg); _log.warn(toString() + ": Tunnel failed: " + cfg);
LeaseSet ls = null; LeaseSet ls = null;
@@ -574,9 +595,8 @@ public class TunnelPool {
* the countHowManyToBuild function below) * the countHowManyToBuild function below)
* *
*/ */
public int countHowManyToBuild() { int countHowManyToBuild() {
if (_settings.getDestination() != null) { if (!isAlive()) {
if (!_context.clientManager().isLocal(_settings.getDestination()))
return 0; return 0;
} }
int wanted = getSettings().getBackupQuantity() + getSettings().getQuantity(); int wanted = getSettings().getBackupQuantity() + getSettings().getQuantity();

View File

@@ -276,9 +276,9 @@ public class TunnelPoolManager implements TunnelManagerFacade {
* Do not use to change settings. * Do not use to change settings.
*/ */
public void buildTunnels(Destination client, ClientTunnelSettings settings) { public void buildTunnels(Destination client, ClientTunnelSettings settings) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Building tunnels for the client " + client.calculateHash().toBase64() + ": " + settings);
Hash dest = client.calculateHash(); Hash dest = client.calculateHash();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Building tunnels for the client " + dest + ": " + settings);
settings.getInboundSettings().setDestination(dest); settings.getInboundSettings().setDestination(dest);
settings.getOutboundSettings().setDestination(dest); settings.getOutboundSettings().setDestination(dest);
TunnelPool inbound = null; TunnelPool inbound = null;
@@ -311,7 +311,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
private static class DelayedStartup implements SimpleTimer.TimedEvent { private static class DelayedStartup implements SimpleTimer.TimedEvent {
private TunnelPool pool; private final TunnelPool pool;
public DelayedStartup(TunnelPool p) { public DelayedStartup(TunnelPool p) {
this.pool = p; this.pool = p;
@@ -322,9 +322,14 @@ public class TunnelPoolManager implements TunnelManagerFacade {
} }
} }
/** synch with buildTunnels() above */ /**
* This will be called twice, once by the inbound and once by the outbound pool.
* Synched with buildTunnels() above.
*/
public synchronized void removeTunnels(Hash destination) { public synchronized void removeTunnels(Hash destination) {
if (destination == null) return; if (destination == null) return;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Removing tunnels for the client " + destination);
if (_context.clientManager().isLocal(destination)) { if (_context.clientManager().isLocal(destination)) {
if (_log.shouldLog(Log.CRIT)) if (_log.shouldLog(Log.CRIT))
_log.log(Log.CRIT, "wtf, why are you removing the pool for " + destination.toBase64(), new Exception("i did it")); _log.log(Log.CRIT, "wtf, why are you removing the pool for " + destination.toBase64(), new Exception("i did it"));