From 43044586d13f2e95ee22b338ea670781ad976d35 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Sun, 3 Jul 2011 13:46:29 +0000
Subject: [PATCH]   * AppContext: Add hasWrapper() method   * Shutdown:     -
 Clear more resources in peer manager, netdb, stat manager,       session key
 manager, naming service, tunnel dispatcher,       OCMOSJ (result of testing
 with jvisualvm)     - Don't call wrapper on shutdown (starting two threads)
 if we       were started with runplain

---
 .../src/net/i2p/router/web/ConfigNetHandler.java |  6 ++++--
 .../net/i2p/router/web/ConfigRestartBean.java    | 14 +++++++++-----
 .../net/i2p/router/web/ConfigServiceHandler.java | 16 ++++++++++++----
 .../net/i2p/router/web/ConfigUpdateHelper.java   |  2 +-
 .../i2p/router/web/UnsignedUpdateHandler.java    |  2 +-
 .../src/net/i2p/router/web/UpdateHandler.java    |  5 +++--
 core/java/src/net/i2p/I2PAppContext.java         |  8 ++++++++
 .../client/naming/BlockfileNamingService.java    |  3 ++-
 core/java/src/net/i2p/stat/StatManager.java      |  6 ++++++
 core/java/src/net/i2p/util/LogConsoleBuffer.java |  8 ++++++++
 core/java/src/net/i2p/util/LogManager.java       |  4 ++++
 history.txt                                      |  9 +++++++++
 .../src/net/i2p/router/ClientMessagePool.java    |  7 +++++++
 router/java/src/net/i2p/router/Router.java       | 14 +++++++++-----
 .../java/src/net/i2p/router/RouterVersion.java   |  2 +-
 .../message/OutboundClientMessageOneShotJob.java | 16 ++++++++++++++++
 .../router/networkdb/kademlia/KBucketSet.java    |  9 +++++++++
 .../kademlia/KademliaNetworkDatabaseFacade.java  |  2 ++
 .../i2p/router/networkdb/kademlia/LocalHash.java |  5 +++--
 .../i2p/router/peermanager/ProfileOrganizer.java |  6 ++++--
 .../net/i2p/router/tunnel/TunnelDispatcher.java  |  6 ++++++
 21 files changed, 124 insertions(+), 26 deletions(-)

diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
index 541f6d73cc..82c175e922 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
@@ -271,7 +271,7 @@ public class ConfigNetHandler extends FormHandler {
         if (switchRequired) {
             hiddenSwitch();
         } else if (restartRequired) {
-            if (System.getProperty("wrapper.version") == null) {
+            if (_context.hasWrapper()) {
                 // Wow this dumps all conns immediately and really isn't nice
                 addFormNotice("Performing a soft restart");
                 _context.router().restart();
@@ -289,7 +289,8 @@ public class ConfigNetHandler extends FormHandler {
                 // There's a few changes that don't really require restart (e.g. enabling inbound TCP)
                 // But it would be hard to get right, so just do a restart.
                 addFormError(_("Gracefully restarting I2P to change published router address"));
-                _context.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
+                if (_context.hasWrapper())
+                    _context.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
                 _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
             }
         }
@@ -297,6 +298,7 @@ public class ConfigNetHandler extends FormHandler {
 
     private void hiddenSwitch() {
         // Full restart required to generate new keys
+        // FIXME don't call wrapper if not present, only rekey
         _context.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL_RESTART));
         _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
     }
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java
index d36cfbaf90..e98dadcac3 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java
@@ -30,21 +30,25 @@ public class ConfigRestartBean {
         if ( (nonce != null) && (systemNonce.equals(nonce)) && (action != null) ) {
             // Normal browsers send value, IE sends button label
             if ("shutdownImmediate".equals(action) || _("Shutdown immediately", ctx).equals(action)) {
-                ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD));
+                if (ctx.hasWrapper())
+                    ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD));
                 //ctx.router().shutdown(Router.EXIT_HARD); // never returns
                 ctx.router().shutdownGracefully(Router.EXIT_HARD); // give the UI time to respond
             } else if ("cancelShutdown".equals(action) || _("Cancel shutdown", ctx).equals(action) ||
                        _("Cancel restart", ctx).equals(action)) {
                 ctx.router().cancelGracefulShutdown();
             } else if ("restartImmediate".equals(action) || _("Restart immediately", ctx).equals(action)) {
-                ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
+                if (ctx.hasWrapper())
+                    ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
                 //ctx.router().shutdown(Router.EXIT_HARD_RESTART); // never returns
                 ctx.router().shutdownGracefully(Router.EXIT_HARD_RESTART); // give the UI time to respond
             } else if ("restart".equals(action) || _("Restart", ctx).equals(action)) {
-                ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
+                if (ctx.hasWrapper())
+                    ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
                 ctx.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
             } else if ("shutdown".equals(action) || _("Shutdown", ctx).equals(action)) {
-                ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL));
+                if (ctx.hasWrapper())
+                    ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL));
                 ctx.router().shutdownGracefully();
             }
         }
@@ -71,7 +75,7 @@ public class ConfigRestartBean {
             buf.append("</b></center><br>");
             buttons(ctx, buf, urlBase, systemNonce, SET2);
         } else {
-            if (System.getProperty("wrapper.version") != null)
+            if (ctx.hasWrapper())
                 buttons(ctx, buf, urlBase, systemNonce, SET3);
             else
                 buttons(ctx, buf, urlBase, systemNonce, SET4);
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java
index 7b1d7bc629..304b624a03 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java
@@ -51,30 +51,38 @@ public class ConfigServiceHandler extends FormHandler {
         if (_action == null) return;
         
         if (_("Shutdown gracefully").equals(_action)) {
-            _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_GRACEFUL));
+            if (_context.hasWrapper())
+                _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_GRACEFUL));
             _context.router().shutdownGracefully();
             addFormNotice(_("Graceful shutdown initiated"));
         } else if (_("Shutdown immediately").equals(_action)) {
-            _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_HARD));
+            if (_context.hasWrapper())
+                _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_HARD));
             _context.router().shutdown(Router.EXIT_HARD);
             addFormNotice(_("Shutdown immediately!  boom bye bye bad bwoy"));
         } else if (_("Cancel graceful shutdown").equals(_action)) {
             _context.router().cancelGracefulShutdown();
             addFormNotice(_("Graceful shutdown cancelled"));
         } else if (_("Graceful restart").equals(_action)) {
-            _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
+            // should have wrapper if restart button is visible
+            if (_context.hasWrapper())
+                _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
             _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
             addFormNotice(_("Graceful restart requested"));
         } else if (_("Hard restart").equals(_action)) {
-            _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
+            // should have wrapper if restart button is visible
+            if (_context.hasWrapper())
+                _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
             _context.router().shutdown(Router.EXIT_HARD_RESTART);
             addFormNotice(_("Hard restart requested"));
         } else if (_("Rekey and Restart").equals(_action)) {
             addFormNotice(_("Rekeying after graceful restart"));
+            // FIXME don't call wrapper if not present, only rekey
             _context.addShutdownTask(new UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL_RESTART));
             _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
         } else if (_("Rekey and Shutdown").equals(_action)) {
             addFormNotice(_("Rekeying after graceful shutdown"));
+            // FIXME don't call wrapper if not present, only rekey
             _context.addShutdownTask(new UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL));
             _context.router().shutdownGracefully(Router.EXIT_GRACEFUL);
         } else if (_("Run I2P on startup").equals(_action)) {
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java
index f74a295bbe..2ffa495755 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java
@@ -117,7 +117,7 @@ public class ConfigUpdateHelper extends HelperBase {
             buf.append(" selected=\"true\"");
         buf.append('>').append(_("Download and verify only")).append("</option>");
         
-        if (System.getProperty("wrapper.version") != null) {
+        if (_context.hasWrapper()) {
             buf.append("<option value=\"install\"");
             if (_dontInstall)
                 buf.append(" disabled=\"true\"");
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java
index 5a52ee883a..2eb132b30b 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java
@@ -115,7 +115,7 @@ public class UnsignedUpdateHandler extends UpdateHandler {
                     _log.log(Log.CRIT, "Update was downloaded, will be installed at next restart");
                     StringBuilder buf = new StringBuilder(64);
                     buf.append("<b>").append(_("Update downloaded")).append("</b><br>");
-                    if (System.getProperty("wrapper.version") != null)
+                    if (_context.hasWrapper())
                         buf.append(_("Click Restart to install"));
                     else
                         buf.append(_("Click Shutdown and restart to install"));
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java
index 423b9e52ad..4581a346a7 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java
@@ -285,7 +285,7 @@ public class UpdateHandler {
                     _log.log(Log.CRIT, "Update was VERIFIED, will be installed at next restart");
                     StringBuilder buf = new StringBuilder(64);
                     buf.append("<b>").append(_("Update downloaded")).append("<br>");
-                    if (System.getProperty("wrapper.version") != null)
+                    if (_context.hasWrapper())
                         buf.append(_("Click Restart to install"));
                     else
                         buf.append(_("Click Shutdown and restart to install"));
@@ -312,7 +312,8 @@ public class UpdateHandler {
     }
     
     protected void restart() {
-        _context.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
+        if (_context.hasWrapper())
+            _context.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
         _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
     }
 
diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java
index 146d4e0e41..b7ab613720 100644
--- a/core/java/src/net/i2p/I2PAppContext.java
+++ b/core/java/src/net/i2p/I2PAppContext.java
@@ -888,4 +888,12 @@ public class I2PAppContext {
     public InternalClientManager internalClientManager() {
         return null;
     }
+
+    /**
+     *  Is the wrapper present?
+     *  @since 0.8.8
+     */
+    public boolean hasWrapper() {
+        return System.getProperty("wrapper.version") != null;
+    }
 }
diff --git a/core/java/src/net/i2p/client/naming/BlockfileNamingService.java b/core/java/src/net/i2p/client/naming/BlockfileNamingService.java
index fdd035c2e9..b0efc768fe 100644
--- a/core/java/src/net/i2p/client/naming/BlockfileNamingService.java
+++ b/core/java/src/net/i2p/client/naming/BlockfileNamingService.java
@@ -108,7 +108,7 @@ public class BlockfileNamingService extends DummyNamingService {
      *
      *  If not in router context, the database will be opened read-only
      *  unless the property i2p.naming.blockfile.writeInAppContext is true.
-     *  Not designed for simultaneous access by multiple processes.
+     *  Not designed for multiple instantiations or simultaneous use by multple JVMs.
      *
      *  @throws RuntimeException on fatal error
      */
@@ -780,6 +780,7 @@ public class BlockfileNamingService extends DummyNamingService {
             }
             _isClosed = true;
         }
+        clearCache();
     }
 
     /** for logging errors in the static serializers below */
diff --git a/core/java/src/net/i2p/stat/StatManager.java b/core/java/src/net/i2p/stat/StatManager.java
index 870f8fc054..8846a026e6 100644
--- a/core/java/src/net/i2p/stat/StatManager.java
+++ b/core/java/src/net/i2p/stat/StatManager.java
@@ -57,6 +57,12 @@ public class StatManager {
             _statLog = new BufferedStatLog(context);
     }
     
+    /** @since 0.8.8 */
+    public void shutdown() {
+        _frequencyStats.clear();
+        _rateStats.clear();
+    }
+
     /** may be null */
     public StatLog getStatLog() { return _statLog; }
     public void setStatLog(StatLog log) { 
diff --git a/core/java/src/net/i2p/util/LogConsoleBuffer.java b/core/java/src/net/i2p/util/LogConsoleBuffer.java
index fba4a3c58f..051ffbf5b7 100644
--- a/core/java/src/net/i2p/util/LogConsoleBuffer.java
+++ b/core/java/src/net/i2p/util/LogConsoleBuffer.java
@@ -77,4 +77,12 @@ public class LogConsoleBuffer {
     public List<String> getMostRecentCriticalMessages() {
             return new ArrayList(_critBuffer);
     }
+
+    /**
+     *  @since 0.8.8
+     */
+    public void clear() {
+        _buffer.clear();
+        _critBuffer.clear();
+    }
 }
diff --git a/core/java/src/net/i2p/util/LogManager.java b/core/java/src/net/i2p/util/LogManager.java
index 81b1148b55..55b454da44 100644
--- a/core/java/src/net/i2p/util/LogManager.java
+++ b/core/java/src/net/i2p/util/LogManager.java
@@ -660,6 +660,10 @@ public class LogManager {
                 _writer.notifyAll();
             }
         }
+        _records.clear();
+        _limits.clear();
+        _logs.clear();
+        _consoleBuffer.clear();
     }
 
     private static int __id = 0;
diff --git a/history.txt b/history.txt
index d06b4ebdd4..913a2e3a0d 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,12 @@
+2011-07-03 zzz
+  * AppContext: Add hasWrapper() method
+  * Shutdown:
+    - Clear more resources in peer manager, netdb, stat manager,
+      session key manager, naming service, tunnel dispatcher,
+      OCMOSJ (result of testing with jvisualvm)
+    - Don't call wrapper on shutdown (starting two threads) if we
+      were started with runplain
+
 2011-07-01 zzz
   * EepGet:
     - Fix error output bug
diff --git a/router/java/src/net/i2p/router/ClientMessagePool.java b/router/java/src/net/i2p/router/ClientMessagePool.java
index 750c76915e..9a8c314da3 100644
--- a/router/java/src/net/i2p/router/ClientMessagePool.java
+++ b/router/java/src/net/i2p/router/ClientMessagePool.java
@@ -32,6 +32,13 @@ public class ClientMessagePool {
         OutboundClientMessageOneShotJob.init(_context);
     }
   
+    /**
+     *  @since 0.8.8
+     */
+    public void shutdown() {
+        OutboundClientMessageOneShotJob.clearAllCaches();
+    }
+
     /**
      * Add a new message to the pool.  The message can either be locally or 
      * remotely destined.
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index ad53234bc2..74a098aa2d 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -258,7 +258,7 @@ public class Router {
         // but this is the same method used in LogsHelper and we have no complaints.
         // (we could look for the wrapper.config file and parse it I guess...)
         // If we don't have a wrapper, RouterLaunch does this for us.
-        if (System.getProperty("wrapper.version") != null) {
+        if (_context.hasWrapper()) {
             File f = new File(System.getProperty("java.io.tmpdir"), "wrapper.log");
             if (!f.exists())
                 f = new File(_context.getBaseDir(), "wrapper.log");
@@ -650,7 +650,7 @@ public class Router {
         }
         _context.removeShutdownTasks();
         // hard and ugly
-        if (System.getProperty("wrapper.version") != null)
+        if (_context.hasWrapper())
             _log.log(Log.CRIT, "Restarting with new router identity");
         else
             _log.log(Log.CRIT, "Shutting down because old router identity was invalid - restart I2P");
@@ -981,7 +981,8 @@ public class Router {
         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); }
         //try { _context.adminManager().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the admin manager", t); }        
-        try { _context.statPublisher().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the stats manager", t); }
+        try { _context.statPublisher().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the stats publisher", t); }
+        try { _context.statManager().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the stats manager", t); }
         try { _context.tunnelManager().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the tunnel manager", t); }
         try { _context.tunnelDispatcher().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the tunnel dispatcher", t); }
         try { _context.netDb().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the networkDb", t); }
@@ -991,7 +992,8 @@ public class Router {
         try { _context.messageRegistry().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message registry", t); }
         try { _context.messageValidator().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message validator", t); }
         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); }
+        try { _context.clientMessagePool().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the client msg pool", t); }
+        try { _context.sessionKeyManager().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); }
         _context.deleteTempDir();
         List<RouterContext> contexts = RouterContext.getContexts();
         contexts.remove(_context);
@@ -1054,6 +1056,8 @@ public class Router {
         if (_killVMOnEnd) {
             try { Thread.sleep(1000); } catch (InterruptedException ie) {}
             Runtime.getRuntime().halt(exitCode);
+        } else {
+            Runtime.getRuntime().gc();
         }
     }
     
@@ -1301,7 +1305,7 @@ public class Router {
                     }
                 }
                 // exit whether ok or not
-                if (System.getProperty("wrapper.version") != null)
+                if (_context.hasWrapper())
                     System.out.println("INFO: Restarting after update");
                 else
                     System.out.println("WARNING: Exiting after update, restart I2P");
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 0725033fa6..f6e6df3a5c 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -18,7 +18,7 @@ public class RouterVersion {
     /** deprecated */
     public final static String ID = "Monotone";
     public final static String VERSION = CoreVersion.VERSION;
-    public final static long BUILD = 3;
+    public final static long BUILD = 4;
 
     /** for example "-test" */
     public final static String EXTRA = "";
diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java
index 1fb4e31b33..11151424b3 100644
--- a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java
+++ b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java
@@ -711,6 +711,22 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
         }
     }
 
+    /**
+     *  @since 0.8.8
+     */
+    public static void clearAllCaches() {
+        synchronized(_leaseSetCache) {
+            _leaseSetCache.clear();
+        }
+        synchronized(_leaseCache) {
+            _leaseCache.clear();
+        }
+        synchronized(_tunnelCache) {
+            _backloggedTunnelCache.clear();
+            _tunnelCache.clear();
+        }
+    }
+
     /**
      * Clean out old leaseSets
      * Caller must synchronize on tc.
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KBucketSet.java b/router/java/src/net/i2p/router/networkdb/kademlia/KBucketSet.java
index c630e2e9d1..f27be069a4 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/KBucketSet.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/KBucketSet.java
@@ -90,6 +90,15 @@ class KBucketSet {
         return removed;
     }
     
+    /** @since 0.8.8 */
+    public void clear() {
+        for (int i = 0; i < _buckets.length; i++) {
+            _buckets[i].setEntries(Collections.EMPTY_SET);
+        }
+        _size = 0;
+        _us.clearXorCache();
+    }
+    
     public Set<Hash> getAll() { return getAll(Collections.EMPTY_SET); };
     public Set<Hash> getAll(Set<Hash> toIgnore) {
         Set<Hash> all = new HashSet(1024);
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
index 7a3b7741a9..eb76ecc454 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
@@ -193,6 +193,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
     
     public void shutdown() {
         _initialized = false;
+        if (_kb != null)
+            _kb.clear();
         // don't null out _kb, it can cause NPEs in concurrent operations
         //_kb = null;
         if (_ds != null)
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/LocalHash.java b/router/java/src/net/i2p/router/networkdb/kademlia/LocalHash.java
index 641f8da54c..ebf787ad09 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/LocalHash.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/LocalHash.java
@@ -107,9 +107,10 @@ class LocalHash extends Hash {
         return distance;
     }
     
-    /** @deprecated unused */
     public void clearXorCache() {
-        _xorCache = null;
+        synchronized (_xorCache) {
+            _xorCache.clear();
+        }
     }
     
 /********
diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
index 155f88bbcc..fdc8881c13 100644
--- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
+++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
@@ -229,7 +229,8 @@ public class ProfileOrganizer {
         
     /** @since 0.8.8 */
     void clearProfiles() {
-        getReadLock();
+        if (!getWriteLock())
+            return;
         try {
             _failingPeers.clear();
             _fastPeers.clear();
@@ -237,7 +238,8 @@ public class ProfileOrganizer {
             _notFailingPeers.clear();
             _notFailingPeersList.clear();
             _wellIntegratedPeers.clear();
-        } finally { releaseReadLock(); }
+            _strictCapacityOrder.clear();
+        } finally { releaseWriteLock(); }
     }
 
     /** 
diff --git a/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java b/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java
index 33f5b7ae75..a9e10b8b7c 100644
--- a/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java
+++ b/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java
@@ -722,7 +722,13 @@ public class TunnelDispatcher implements Service {
             _validator.destroy();
         _validator = null;
         _pumper.stopPumping();
+        _outboundGateways.clear();
+        _outboundEndpoints.clear();
+        _participants.clear();
+        _inboundGateways.clear();
+        _participatingConfig.clear();
     }
+
     public void restart() { 
         shutdown(); 
         startup(); 
-- 
GitLab