From 3c88c854bf6d7f51b4ceeccb7150dbe782059d9b Mon Sep 17 00:00:00 2001 From: zzz Date: Tue, 14 Jun 2011 19:27:46 +0000 Subject: [PATCH] more cleanup at shutdown --- core/java/src/net/i2p/I2PAppContext.java | 19 ++++++++++++++++--- router/java/src/net/i2p/router/Router.java | 16 ++++++++++++++-- .../src/net/i2p/router/RouterContext.java | 7 +++++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java index fa352ada6..be35d32f1 100644 --- a/core/java/src/net/i2p/I2PAppContext.java +++ b/core/java/src/net/i2p/I2PAppContext.java @@ -1,6 +1,7 @@ package net.i2p; import java.io.File; +import java.util.Collections; import java.util.HashSet; import java.util.Properties; import java.util.Random; @@ -100,7 +101,7 @@ public class I2PAppContext { private volatile boolean _randomInitialized; private volatile boolean _keyGeneratorInitialized; protected volatile boolean _keyRingInitialized; // used in RouterContext - private Set _shutdownTasks; + protected final Set _shutdownTasks; private File _baseDir; private File _configDir; private File _routerDir; @@ -185,7 +186,7 @@ public class I2PAppContext { _elGamalAESEngineInitialized = false; _logManagerInitialized = false; _keyRingInitialized = false; - _shutdownTasks = new ConcurrentHashSet(0); + _shutdownTasks = new ConcurrentHashSet(16); initializeDirs(); } @@ -843,12 +844,24 @@ public class I2PAppContext { } } + /** + * WARNING - Shutdown tasks are not executed in an I2PAppContext. + * You must be in a RouterContext for the tasks to be executed + * at shutdown. + * This method moved from Router in 0.7.1 so that clients + * may use it without depending on router.jar. + * @since 0.7.1 + */ public void addShutdownTask(Runnable task) { _shutdownTasks.add(task); } + /** + * @return an unmodifiable Set + * @since 0.7.1 + */ public Set getShutdownTasks() { - return new HashSet(_shutdownTasks); + return Collections.unmodifiableSet(_shutdownTasks); } /** diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index 6e7ce010c..cb4c0df6f 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -49,6 +49,7 @@ import net.i2p.util.I2PAppThread; import net.i2p.util.I2PThread; import net.i2p.util.Log; import net.i2p.util.SecureFileOutputStream; +import net.i2p.util.SimpleByteCache; import net.i2p.util.SimpleScheduler; import net.i2p.util.SimpleTimer; @@ -257,7 +258,7 @@ public class Router { _killVMOnEnd = true; _oomListener = new I2PThread.OOMEventListener() { public void outOfMemory(OutOfMemoryError oom) { - ByteCache.clearAll(); + clearCaches(); _log.log(Log.CRIT, "Thread ran out of memory", oom); for (int i = 0; i < 5; i++) { // try this 5 times, in case it OOMs try { @@ -280,6 +281,12 @@ public class Router { } + /** @since 0.8.8 */ + private static final void clearCaches() { + ByteCache.clearAll(); + SimpleByteCache.clearAll(); + } + /** * Configure the router to kill the JVM when the router shuts down, as well * as whether to explicitly halt the JVM during the hard fail process. @@ -624,6 +631,7 @@ public class Router { _log.log(Log.CRIT, "Error running shutdown task", t); } } + _context.removeShutdownTasks(); // hard and ugly if (System.getProperty("wrapper.version") != null) _log.log(Log.CRIT, "Restarting with new router identity"); @@ -940,12 +948,15 @@ public class Router { // Run the shutdown hooks first in case they want to send some goodbye messages // Maybe we need a delay after this too? for (Runnable task : _context.getShutdownTasks()) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Running shutdown task " + task.getClass()); try { task.run(); } catch (Throwable t) { _log.log(Log.CRIT, "Error running shutdown task", t); } } + _context.removeShutdownTasks(); try { _context.clientManager().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the client manager", t); } try { _context.namingService().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the naming service", t); } try { _context.jobQueue().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the job queue", t); } @@ -972,6 +983,7 @@ public class Router { private static final boolean ALLOW_DYNAMIC_KEYS = false; private void finalShutdown(int exitCode) { + clearCaches(); _log.log(Log.CRIT, "Shutdown(" + exitCode + ") complete" /* , new Exception("Shutdown") */ ); try { _context.logManager().shutdown(); } catch (Throwable t) { } if (ALLOW_DYNAMIC_KEYS) { @@ -1486,7 +1498,7 @@ private static class CoalesceStatsEvent implements SimpleTimer.TimedEvent { long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); getContext().statManager().addRateData("router.memoryUsed", used, 0); if (_maxMemory - used < LOW_MEMORY_THRESHOLD) - ByteCache.clearAll(); + clearCaches(); getContext().tunnelDispatcher().updateParticipatingStats(COALESCE_TIME); diff --git a/router/java/src/net/i2p/router/RouterContext.java b/router/java/src/net/i2p/router/RouterContext.java index c7d54f88d..26e54ff4d 100644 --- a/router/java/src/net/i2p/router/RouterContext.java +++ b/router/java/src/net/i2p/router/RouterContext.java @@ -402,6 +402,13 @@ public class RouterContext extends I2PAppContext { } } + /** + * @since 0.8.8 + */ + void removeShutdownTasks() { + _shutdownTasks.clear(); + } + /** * Use this instead of context instanceof RouterContext * @return true