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 ffe67b9e9a313921883e4c459aeea10a44602547..b939b833eabca04b463ea75ca4aa63643f947a81 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java @@ -40,7 +40,7 @@ class BuildExecutor implements Runnable { private final ConcurrentHashMap<Long, PooledTunnelCreatorConfig> _currentlyBuildingMap; /** indexed by ptcc.getReplyMessageId() */ private final ConcurrentHashMap<Long, PooledTunnelCreatorConfig> _recentlyBuildingMap; - private boolean _isRunning; + private volatile boolean _isRunning; private boolean _repoll; private static final int MAX_CONCURRENT_BUILDS = 10; /** accept replies up to a minute after we gave up on them */ @@ -84,6 +84,26 @@ class BuildExecutor implements Runnable { statMgr.createRateStat("tunnel.tierExpireUnknown", "Expired joins from unknown", "Tunnels", new long[] { 60*1000, 10*60*1000 }); } + /** + * @since 0.9 + */ + public void restart() { + synchronized (_recentBuildIds) { + _recentBuildIds.clear(); + } + _currentlyBuildingMap.clear(); + _recentlyBuildingMap.clear(); + } + + /** + * Cannot be restarted. + * @since 0.9 + */ + public void shutdown() { + _isRunning = false; + restart(); + } + private int allowed() { int maxKBps = _context.bandwidthLimiter().getOutboundKBytesPerSecond(); int allowed = maxKBps / 6; // Max. 1 concurrent build per 6 KB/s outbound @@ -270,7 +290,7 @@ class BuildExecutor implements Runnable { long afterBuildReal = 0; long afterHandleInbound = 0; - while (!_manager.isShutdown()){ + while (_isRunning && !_manager.isShutdown()){ //loopBegin = System.currentTimeMillis(); try { _repoll = false; // resets repoll to false unless there are inbound requeusts pending diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java index 28a9233d321a46541980a4c2a0f447ea427c99b4..4e3043acfa2be8f803c4a0a7df1a62271bd87010 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java @@ -54,7 +54,7 @@ class BuildHandler implements Runnable { private final LinkedBlockingQueue<BuildMessageState> _inboundBuildMessages; private final BuildMessageProcessor _processor; private final ParticipatingThrottler _throttler; - private boolean _isRunning; + private volatile boolean _isRunning; /** TODO these may be too high, review and adjust */ private static final int MIN_QUEUE = 18; @@ -121,13 +121,34 @@ class BuildHandler implements Runnable { ctx.inNetMessagePool().registerHandlerJobBuilder(VariableTunnelBuildReplyMessage.MESSAGE_TYPE, tbrmhjb); } + /** + * @since 0.9 + */ + public void restart() { + _inboundBuildMessages.clear(); + } + + /** + * Cannot be restarted. + * @param numThreads the number of threads to be shut down + * @since 0.9 + */ + public void shutdown(int numThreads) { + _isRunning = false; + _inboundBuildMessages.clear(); + BuildMessageState poison = new BuildMessageState(null, null, null); + for (int i = 0; i < numThreads; i++) { + _inboundBuildMessages.offer(poison); + } + } + /** * Thread to handle inbound requests * @since 0.8.11 */ public void run() { _isRunning = true; - while (!_manager.isShutdown()) { + while (_isRunning && !_manager.isShutdown()) { try { handleInboundRequest(); } catch (Exception e) { @@ -150,6 +171,13 @@ class BuildHandler implements Runnable { } catch (InterruptedException ie) { return; } + + // check for poison + if (state.msg == null) { + _isRunning = false; + return; + } + long dropBefore = System.currentTimeMillis() - (BuildRequestor.REQUEST_TIMEOUT/4); if (state.recvTime <= dropBefore) { if (_log.shouldLog(Log.WARN)) 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 753f931bcb1bfa3640d508353aaf24a7c2cb485b..9af3fc453f8caca4b4508de041725ac4c965d004 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java @@ -105,7 +105,7 @@ public class TunnelPool { void shutdown() { if (_log.shouldLog(Log.WARN)) - _log.warn(toString() + ": Shutdown called", new Exception()); + _log.warn(toString() + ": Shutdown called"); _alive = false; _lastSelectionPeriod = 0; _lastSelected = null; 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 56f8a587bd4fbc276330c102c341fd75a9132b73..626566d5cb42febe887431283ffe139245beacf0 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java @@ -50,6 +50,7 @@ public class TunnelPoolManager implements TunnelManagerFacade { private final BuildExecutor _executor; private final BuildHandler _handler; private boolean _isShutdown; + private final int _numHandlerThreads; private static final long[] RATES = { 60*1000, 10*60*1000l, 60*60*1000l }; private static final int MIN_KBPS_TWO_HANDLERS = 512; @@ -80,8 +81,8 @@ public class TunnelPoolManager implements TunnelManagerFacade { numHandlerThreads = 2; else numHandlerThreads = 1; - numHandlerThreads = ctx.getProperty("router.buildHandlerThreads", numHandlerThreads); - for (int i = 1; i <= numHandlerThreads; i++) { + _numHandlerThreads = ctx.getProperty("router.buildHandlerThreads", numHandlerThreads); + for (int i = 1; i <= _numHandlerThreads; i++) { I2PThread hThread = new I2PThread(_handler, "BuildHandler " + i + '/' + numHandlerThreads, true); hThread.start(); } @@ -396,7 +397,9 @@ public class TunnelPoolManager implements TunnelManagerFacade { } public void restart() { - shutdown(); + _handler.restart(); + _executor.restart(); + shutdownExploratory(); startup(); } @@ -548,12 +551,21 @@ public class TunnelPoolManager implements TunnelManagerFacade { } } + /** + * Cannot be restarted + */ public void shutdown() { + _handler.shutdown(_numHandlerThreads); + _executor.shutdown(); + shutdownExploratory(); + _isShutdown = true; + } + + private void shutdownExploratory() { if (_inboundExploratory != null) _inboundExploratory.shutdown(); if (_outboundExploratory != null) _outboundExploratory.shutdown(); - _isShutdown = true; } /** list of TunnelPool instances currently in play */