* Shutdown:

- Kill the global app context
    - Recognize multi-router case
    - Fix RandomIterator, YKGenerator, DHBuilder, NTCPConnection
      hanging on to old context -
      probably other offenders not yet found
    - Fix DHBuilder thread not stopping
This commit is contained in:
zzz
2011-06-17 18:37:02 +00:00
parent df793193aa
commit 9ad8f35bca
10 changed files with 101 additions and 39 deletions

View File

@ -22,8 +22,8 @@ import net.i2p.util.Log;
*
*/
public class I2NPMessageHandler {
private Log _log;
private I2PAppContext _context;
private final Log _log;
private final I2PAppContext _context;
private long _lastReadBegin;
private long _lastReadEnd;
private int _lastSize;

View File

@ -28,8 +28,8 @@ import net.i2p.util.SimpleByteCache;
* @author jrandom
*/
public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPMessage {
private Log _log;
protected I2PAppContext _context;
private final Log _log;
protected final I2PAppContext _context;
private long _expiration;
private long _uniqueId;

View File

@ -980,19 +980,23 @@ public class Router {
try { _context.inNetMessagePool().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the inbound net pool", t); }
//try { _sessionKeyPersistenceHelper.shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); }
_context.deleteTempDir();
RouterContext.listContexts().remove(_context);
List<RouterContext> contexts = RouterContext.getContexts();
contexts.remove(_context);
// shut down I2PAppContext tasks here
// TODO if there are multiple routers in the JVM, we don't want to do this
// 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); }
if (contexts.isEmpty()) {
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); }
} else {
_log.logAlways(Log.WARN, "Warning - " + contexts.size() + " routers remaining in this JVM, not releasing all resources");
}
try {
((FortunaRandomSource)_context.random()).shutdown();
} catch (Throwable t) { _log.log(Log.CRIT, "Error shutting random()", t); }
@ -1020,6 +1024,8 @@ public class Router {
File f = getPingFile();
f.delete();
if (RouterContext.getContexts().isEmpty())
RouterContext.killGlobalContext();
if (_killVMOnEnd) {
try { Thread.sleep(1000); } catch (InterruptedException ie) {}
Runtime.getRuntime().halt(exitCode);

View File

@ -1,6 +1,7 @@
package net.i2p.router;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
@ -67,6 +68,8 @@ public class RouterContext extends I2PAppContext {
// to init everything. Caller MUST call initAll() afterwards.
// Sorry, this breaks some main() unit tests out there.
//initAll();
if (!_contexts.isEmpty())
System.out.println("Warning - More than one router in this JVM");
_contexts.add(this);
}
@ -165,11 +168,37 @@ public class RouterContext extends I2PAppContext {
/**
* Retrieve the list of router contexts currently instantiated in this JVM.
* This will always contain only one item (except when a simulation per the
* MultiRouter is going on), and the list should only be modified when a new
* MultiRouter is going on).
*
* @return an unmodifiable list (as of 0.8.8). May be null or empty.
*/
public static List<RouterContext> listContexts() {
return Collections.unmodifiableList(_contexts);
}
/**
* Same as listContexts() but package private and modifiable.
* The list should only be modified when a new
* context is created or a router is shut down.
*
* @since 0.8.8
*/
public static List<RouterContext> listContexts() { return _contexts; }
static List<RouterContext> getContexts() {
return _contexts;
}
/**
* Kill the global I2PAppContext, so it isn't still around
* when we restart in the same JVM (Android).
* Only do this if there are no other routers in the JVM.
*
* @since 0.8.8
*/
static void killGlobalContext() {
synchronized (I2PAppContext.class) {
_globalAppContext = null;
}
}
/** what router is this context working for? */
public Router router() { return _router; }

View File

@ -1089,6 +1089,10 @@ class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener {
}
private static final int MAX_HANDLERS = 4;
/**
* FIXME static queue mixes handlers from different contexts in multirouter JVM
*/
private final static LinkedBlockingQueue<I2NPMessageHandler> _i2npHandlers = new LinkedBlockingQueue(MAX_HANDLERS);
private final static I2NPMessageHandler acquireHandler(RouterContext ctx) {
@ -1129,6 +1133,15 @@ class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener {
_dataReadBufs.offer(buf);
}
/** @since 0.8.8 */
static void releaseResources() {
_i2npHandlers.clear();
_dataReadBufs.clear();
synchronized(_bufs) {
_bufs.clear();
}
}
/**
* sizeof(data)+data+pad+crc.
*

View File

@ -702,6 +702,7 @@ public class NTCPTransport extends TransportImpl {
NTCPConnection con = (NTCPConnection)iter.next();
con.close();
}
NTCPConnection.releaseResources();
// will this work?
replaceAddress(null);
}

View File

@ -84,7 +84,7 @@ public class RandomIterator<E> implements Iterator<E> {
* <a href="http://www.qbrundage.com/michaelb/pubs/essays/random_number_generation" title="http://www.qbrundage.com/michaelb/pubs/essays/random_number_generation" target="_blank">http://www.qbrundage.com/michaelb/pubs/e&#8230;</a>
* for some implementations, which are faster than java.util.Random.
*/
private static final Random rand = RandomSource.getInstance();
private final Random rand = RandomSource.getInstance();
/** Used to narrow the range to take random indexes from */
private int lower, upper;