* Shutdown:

- Implement and call shutdown for RouterWatchdog
    - Fix i2psnark DirMonitor not stopping
    - Fix UPnP-Disposer not stopping quickly
    - Implement and call YKGenerator and DHSessionKeyBuilder shutdown
This commit is contained in:
zzz
2011-06-16 21:02:56 +00:00
parent 4cff55daca
commit 83ee57adc7
7 changed files with 128 additions and 23 deletions

View File

@ -48,14 +48,14 @@ public class SnarkManager implements Snark.CompleteListener {
private final Object _addSnarkLock; private final Object _addSnarkLock;
private /* FIXME final FIXME */ File _configFile; private /* FIXME final FIXME */ File _configFile;
private Properties _config; private Properties _config;
private I2PAppContext _context; private final I2PAppContext _context;
private Log _log; private final Log _log;
private final List _messages; private final List _messages;
private I2PSnarkUtil _util; private final I2PSnarkUtil _util;
private PeerCoordinatorSet _peerCoordinatorSet; private PeerCoordinatorSet _peerCoordinatorSet;
private ConnectionAcceptor _connectionAcceptor; private ConnectionAcceptor _connectionAcceptor;
private Thread _monitor; private Thread _monitor;
private boolean _running; private volatile boolean _running;
public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost"; public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost";
public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort"; public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort";
@ -1089,7 +1089,7 @@ public class SnarkManager implements Snark.CompleteListener {
// although the user will see the default until then // although the user will see the default until then
getBWLimit(); getBWLimit();
boolean doMagnets = true; boolean doMagnets = true;
while (true) { while (_running) {
File dir = getDataDir(); File dir = getDataDir();
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Directory Monitor loop over " + dir.getAbsolutePath()); _log.debug("Directory Monitor loop over " + dir.getAbsolutePath());

View File

@ -53,7 +53,8 @@ public class DHSessionKeyBuilder {
private static final int MAX_NUM_BUILDERS; private static final int MAX_NUM_BUILDERS;
private static final int CALC_DELAY; private static final int CALC_DELAY;
private static final LinkedBlockingQueue<DHSessionKeyBuilder> _builders; private static final LinkedBlockingQueue<DHSessionKeyBuilder> _builders;
private static final Thread _precalcThread; private static Thread _precalcThread;
private static volatile boolean _isRunning;
// the data of importance // the data of importance
private BigInteger _myPrivateValue; private BigInteger _myPrivateValue;
@ -96,12 +97,41 @@ public class DHSessionKeyBuilder {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("DH Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: " _log.debug("DH Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
+ CALC_DELAY + ")"); + CALC_DELAY + ")");
startPrecalc();
}
_precalcThread = new I2PThread(new DHSessionKeyBuilderPrecalcRunner(MIN_NUM_BUILDERS, MAX_NUM_BUILDERS)); /** @since 0.8.8 */
_precalcThread.setName("DH Precalc"); private static void startPrecalc() {
_precalcThread.setDaemon(true); synchronized(DHSessionKeyBuilder.class) {
_precalcThread.setPriority(Thread.MIN_PRIORITY); _precalcThread = new I2PThread(new DHSessionKeyBuilderPrecalcRunner(MIN_NUM_BUILDERS, MAX_NUM_BUILDERS),
_precalcThread.start(); "DH Precalc", true);
_precalcThread.setPriority(Thread.MIN_PRIORITY);
_isRunning = true;
_precalcThread.start();
}
}
/**
* Note that this stops the singleton precalc thread.
* You don't want to do this if there are multiple routers in the JVM.
* Fix this if you care. See Router.shutdown().
* @since 0.8.8
*/
public static void shutdown() {
_isRunning = false;
_precalcThread.interrupt();
_builders.clear();
}
/**
* Only required if shutdown() previously called.
* @since 0.8.8
*/
public static void restart() {
synchronized(DHSessionKeyBuilder.class) {
if (!_isRunning)
startPrecalc();
}
} }
/** /**

View File

@ -78,6 +78,24 @@ public class ElGamalEngine {
} }
/**
* Note that this stops the singleton precalc thread.
* You don't want to do this if there are multiple routers in the JVM.
* Fix this if you care. See Router.shutdown().
* @since 0.8.8
*/
public void shutdown() {
YKGenerator.shutdown();
}
/**
* Only required if shutdown() previously called.
* @since 0.8.8
*/
public static void restart() {
YKGenerator.restart();
}
private final static BigInteger _two = new NativeBigInteger(1, new byte[] { 0x02}); private final static BigInteger _two = new NativeBigInteger(1, new byte[] { 0x02});
private BigInteger[] getNextYK() { private BigInteger[] getNextYK() {

View File

@ -42,8 +42,9 @@ class YKGenerator {
private static final int MAX_NUM_BUILDERS; private static final int MAX_NUM_BUILDERS;
private static final int CALC_DELAY; private static final int CALC_DELAY;
private static final LinkedBlockingQueue<BigInteger[]> _values; private static final LinkedBlockingQueue<BigInteger[]> _values;
private static final Thread _precalcThread; private static Thread _precalcThread;
private static final I2PAppContext ctx; private static final I2PAppContext ctx;
private static volatile boolean _isRunning;
public final static String PROP_YK_PRECALC_MIN = "crypto.yk.precalc.min"; public final static String PROP_YK_PRECALC_MIN = "crypto.yk.precalc.min";
public final static String PROP_YK_PRECALC_MAX = "crypto.yk.precalc.max"; public final static String PROP_YK_PRECALC_MAX = "crypto.yk.precalc.max";
@ -77,12 +78,41 @@ class YKGenerator {
ctx.statManager().createRateStat("crypto.YKUsed", "Need a YK from the queue", "Encryption", new long[] { 60*60*1000 }); ctx.statManager().createRateStat("crypto.YKUsed", "Need a YK from the queue", "Encryption", new long[] { 60*60*1000 });
ctx.statManager().createRateStat("crypto.YKEmpty", "YK queue empty", "Encryption", new long[] { 60*60*1000 }); ctx.statManager().createRateStat("crypto.YKEmpty", "YK queue empty", "Encryption", new long[] { 60*60*1000 });
startPrecalc();
}
_precalcThread = new I2PThread(new YKPrecalcRunner(MIN_NUM_BUILDERS, MAX_NUM_BUILDERS)); /** @since 0.8.8 */
_precalcThread.setName("YK Precalc"); private static void startPrecalc() {
_precalcThread.setDaemon(true); synchronized(YKGenerator.class) {
_precalcThread.setPriority(Thread.MIN_PRIORITY); _precalcThread = new I2PThread(new YKPrecalcRunner(MIN_NUM_BUILDERS, MAX_NUM_BUILDERS),
_precalcThread.start(); "YK Precalc", true);
_precalcThread.setPriority(Thread.MIN_PRIORITY);
_isRunning = true;
_precalcThread.start();
}
}
/**
* Note that this stops the singleton precalc thread.
* You don't want to do this if there are multiple routers in the JVM.
* Fix this if you care. See Router.shutdown().
* @since 0.8.8
*/
public static void shutdown() {
_isRunning = false;
_precalcThread.interrupt();
_values.clear();
}
/**
* Only required if shutdown() previously called.
* @since 0.8.8
*/
public static void restart() {
synchronized(YKGenerator.class) {
if (!_isRunning)
startPrecalc();
}
} }
private static final int getSize() { private static final int getSize() {
@ -161,7 +191,7 @@ class YKGenerator {
} }
public void run() { public void run() {
while (true) { while (_isRunning) {
int curSize = 0; int curSize = 0;
//long start = Clock.getInstance().now(); //long start = Clock.getInstance().now();
int startSize = getSize(); int startSize = getSize();
@ -172,7 +202,7 @@ class YKGenerator {
_checkDelay += 1000; _checkDelay += 1000;
curSize = startSize; curSize = startSize;
if (curSize < _minSize) { if (curSize < _minSize) {
for (int i = curSize; i < _maxSize; i++) { for (int i = curSize; i < _maxSize && _isRunning; i++) {
//long begin = Clock.getInstance().now(); //long begin = Clock.getInstance().now();
if (!addValues(generateYK())) if (!addValues(generateYK()))
break; break;

View File

@ -75,6 +75,8 @@ public class Router {
private I2PThread.OOMEventListener _oomListener; private I2PThread.OOMEventListener _oomListener;
private ShutdownHook _shutdownHook; private ShutdownHook _shutdownHook;
private final I2PThread _gracefulShutdownDetector; private final I2PThread _gracefulShutdownDetector;
private final RouterWatchdog _watchdog;
private final Thread _watchdogThread;
public final static String PROP_CONFIG_FILE = "router.configLocation"; public final static String PROP_CONFIG_FILE = "router.configLocation";
@ -277,8 +279,9 @@ public class Router {
_gracefulShutdownDetector = new I2PAppThread(new GracefulShutdown(), "Graceful shutdown hook", true); _gracefulShutdownDetector = new I2PAppThread(new GracefulShutdown(), "Graceful shutdown hook", true);
_gracefulShutdownDetector.start(); _gracefulShutdownDetector.start();
Thread watchdog = new I2PAppThread(new RouterWatchdog(_context), "RouterWatchdog", true); _watchdog = new RouterWatchdog(_context);
watchdog.start(); _watchdogThread = new I2PAppThread(_watchdog, "RouterWatchdog", true);
_watchdogThread.start();
} }
@ -643,7 +646,10 @@ public class Router {
private void warmupCrypto() { private void warmupCrypto() {
_context.random().nextBoolean(); _context.random().nextBoolean();
new DHSessionKeyBuilder(); // load the class so it starts the precalc process // Use restart() to refire the static refiller threads, in case
// we are restarting the router in the same JVM (Android)
DHSessionKeyBuilder.restart();
_context.elGamalEngine().restart();
} }
private void startupQueue() { private void startupQueue() {
@ -977,11 +983,23 @@ public class Router {
RouterContext.listContexts().remove(_context); RouterContext.listContexts().remove(_context);
// shut down I2PAppContext tasks here // shut down I2PAppContext tasks here
// TODO if there are multiple routers in the JVM, we don't want to do this
// to the DH or YK tasks, as they are singletons.
// Have MultiRouter set a property or something.
try {
DHSessionKeyBuilder.shutdown();
} catch (Throwable t) { _log.log(Log.CRIT, "Error shutting DH", t); }
try {
_context.elGamalEngine().shutdown();
} catch (Throwable t) { _log.log(Log.CRIT, "Error shutting elGamal", t); }
try { try {
((FortunaRandomSource)_context.random()).shutdown(); ((FortunaRandomSource)_context.random()).shutdown();
} catch (Throwable t) { _log.log(Log.CRIT, "Error shutting random()", t); } } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting random()", t); }
// logManager shut down in finalShutdown() // logManager shut down in finalShutdown()
_watchdog.shutdown();
_watchdogThread.interrupt();
finalShutdown(exitCode); finalShutdown(exitCode);
} }

View File

@ -15,14 +15,21 @@ class RouterWatchdog implements Runnable {
private final Log _log; private final Log _log;
private final RouterContext _context; private final RouterContext _context;
private int _consecutiveErrors; private int _consecutiveErrors;
private volatile boolean _isRunning;
private static final long MAX_JOB_RUN_LAG = 60*1000; private static final long MAX_JOB_RUN_LAG = 60*1000;
public RouterWatchdog(RouterContext ctx) { public RouterWatchdog(RouterContext ctx) {
_context = ctx; _context = ctx;
_log = ctx.logManager().getLog(RouterWatchdog.class); _log = ctx.logManager().getLog(RouterWatchdog.class);
_isRunning = true;
} }
/** @since 0.8.8 */
public void shutdown() {
_isRunning = false;
}
public boolean verifyJobQueueLiveliness() { public boolean verifyJobQueueLiveliness() {
long when = _context.jobQueue().getLastJobBegin(); long when = _context.jobQueue().getLastJobBegin();
if (when < 0) if (when < 0)
@ -109,7 +116,7 @@ class RouterWatchdog implements Runnable {
} }
public void run() { public void run() {
while (true) { while (_isRunning) {
try { Thread.sleep(60*1000); } catch (InterruptedException ie) {} try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
monitorRouter(); monitorRouter();
} }

View File

@ -65,6 +65,8 @@ public class ThreadCore implements Runnable
//threadObject.destroy(); //threadObject.destroy();
//threadObject.stop(); //threadObject.stop();
setThreadObject(null); setThreadObject(null);
// I2P break Disposer out of sleep()
threadObject.interrupt();
} }
} }