From c5e74fefe55b1a1133efa97f1d41527e4b2e899c Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 19 Aug 2011 15:34:30 +0000 Subject: [PATCH] * Soft restart: - Allow NTP to reinitialize clock after the comm system in the first minute of uptime - Fix i2ptunnels not restarting - Increase minimum forward clock shift for soft restart - Reduce minimum backward clock shift for soft restart - Signal the I2CP client with a different message when restarting - I2CP client reconnects when receiving restart message --- .../i2p/client/DisconnectMessageHandler.java | 22 ++++++++++++++++++- history.txt | 10 +++++++++ .../net/i2p/router/ClientManagerFacade.java | 3 +++ .../i2p/router/DummyClientManagerFacade.java | 1 + router/java/src/net/i2p/router/Router.java | 3 ++- .../java/src/net/i2p/router/RouterClock.java | 18 ++++++++++----- .../src/net/i2p/router/RouterVersion.java | 2 +- .../net/i2p/router/client/ClientManager.java | 9 +++++--- .../client/ClientManagerFacadeImpl.java | 10 ++++++++- 9 files changed, 65 insertions(+), 13 deletions(-) diff --git a/core/java/src/net/i2p/client/DisconnectMessageHandler.java b/core/java/src/net/i2p/client/DisconnectMessageHandler.java index 56ad3fa38a..8dd47f10b2 100644 --- a/core/java/src/net/i2p/client/DisconnectMessageHandler.java +++ b/core/java/src/net/i2p/client/DisconnectMessageHandler.java @@ -12,6 +12,7 @@ package net.i2p.client; import net.i2p.I2PAppContext; import net.i2p.data.i2cp.DisconnectMessage; import net.i2p.data.i2cp.I2CPMessage; +import net.i2p.util.I2PAppThread; import net.i2p.util.Log; /** @@ -27,7 +28,26 @@ class DisconnectMessageHandler extends HandlerImpl { public void handleMessage(I2CPMessage message, I2PSessionImpl session) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Handle message " + message); - session.propogateError(((DisconnectMessage)message).getReason(), new I2PSessionException("Disconnect Message received")); + String reason = ((DisconnectMessage)message).getReason(); + session.propogateError(reason, new I2PSessionException("Disconnect Message received")); session.destroySession(false); + if (reason.contains("restart")) { + Thread t = new I2PAppThread(new Reconnector(session), "Reconnect " + session, true); + t.start(); + } + } + + /** @since 0.8.8 */ + private static class Reconnector implements Runnable { + private final I2PSessionImpl _session; + + public Reconnector(I2PSessionImpl session) { + _session = session; + } + + public void run() { + try { Thread.sleep(10*1000); } catch (InterruptedException ie) {} + _session.reconnect(); + } } } diff --git a/history.txt b/history.txt index 337203eaa4..cb1bc02acd 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,13 @@ +2011-08-19 zzz + * Soft restart: + - Allow NTP to reinitialize clock after the comm system + in the first minute of uptime + - Fix i2ptunnels not restarting + - Increase minimum forward clock shift for soft restart + - Reduce minimum backward clock shift for soft restart + - Signal the I2CP client with a different message when restarting + - I2CP client reconnects when receiving restart message + 2011-08-17 kytv * Fix #506: Don't attempt to load systray4j when using a 64bit JVM in Windows. diff --git a/router/java/src/net/i2p/router/ClientManagerFacade.java b/router/java/src/net/i2p/router/ClientManagerFacade.java index 1318232879..dca7f5b303 100644 --- a/router/java/src/net/i2p/router/ClientManagerFacade.java +++ b/router/java/src/net/i2p/router/ClientManagerFacade.java @@ -94,4 +94,7 @@ public abstract class ClientManagerFacade implements Service { public abstract SessionConfig getClientSessionConfig(Destination dest); public abstract SessionKeyManager getClientSessionKeyManager(Hash dest); public void renderStatusHTML(Writer out) throws IOException { } + + /** @since 0.8.8 */ + public abstract void shutdown(String msg); } diff --git a/router/java/src/net/i2p/router/DummyClientManagerFacade.java b/router/java/src/net/i2p/router/DummyClientManagerFacade.java index 9c0c6838e0..30daf47e56 100644 --- a/router/java/src/net/i2p/router/DummyClientManagerFacade.java +++ b/router/java/src/net/i2p/router/DummyClientManagerFacade.java @@ -36,6 +36,7 @@ public class DummyClientManagerFacade extends ClientManagerFacade { public void startup() {} public void stopAcceptingClients() { } public void shutdown() {} + public void shutdown(String msg) {} public void restart() {} public void messageDeliveryStatusUpdate(Destination fromDest, MessageId id, boolean delivered) {} diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index dc673f741c..8114d1ffe2 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -1308,7 +1308,8 @@ public class Router implements RouterClock.ClockShiftListener { _started = _context.clock().now(); _log.error("Stopping the router for a restart..."); _log.logAlways(Log.WARN, "Stopping the client manager"); - try { _context.clientManager().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error stopping the client manager", t); } + // NOTE: DisconnectMessageHandler keys off "restart" + try { _context.clientManager().shutdown("Router restart"); } catch (Throwable t) { _log.log(Log.CRIT, "Error stopping the client manager", t); } _log.logAlways(Log.WARN, "Stopping the comm system"); try { _context.messageRegistry().restart(); } catch (Throwable t) { _log.log(Log.CRIT, "Error restarting the message registry", t); } try { _context.commSystem().restart(); } catch (Throwable t) { _log.log(Log.CRIT, "Error restarting the comm system", t); } diff --git a/router/java/src/net/i2p/router/RouterClock.java b/router/java/src/net/i2p/router/RouterClock.java index 4a5164f179..8f8d205047 100644 --- a/router/java/src/net/i2p/router/RouterClock.java +++ b/router/java/src/net/i2p/router/RouterClock.java @@ -40,11 +40,13 @@ public class RouterClock extends Clock { private int _lastStratum; /** - * If the system clock shifts by this much (positive or negative), + * If the system clock shifts by this much, * call the callback, we probably need a soft restart. * @since 0.8.8 */ - private static final long MASSIVE_SHIFT = 75*1000; + private static final long MASSIVE_SHIFT_FORWARD = 150*1000; + private static final long MASSIVE_SHIFT_BACKWARD = 61*1000; + private final Set _shiftListeners; private volatile long _lastShiftNanos; @@ -137,7 +139,11 @@ public class RouterClock extends Clock { } // check sanity } - if (_alreadyChanged) { + // In first minute, allow a lower (better) stratum to do a step adjustment after + // a previous step adjustment. + // This allows NTP to trump a peer offset after a soft restart + if (_alreadyChanged && + (stratum >= _lastStratum || _startedOn - System.currentTimeMillis() > 60*1000)) { // Update the target offset, slewing will take care of the rest if (delta > 15*1000) getLog().error("Warning - Updating target clock offset to " + offsetMs + "ms from " + _offset + "ms, Stratum " + stratum); @@ -192,8 +198,8 @@ public class RouterClock extends Clock { // copy the global, so two threads don't both increment or decrement _offset long offset = _offset; long sinceLastSlewed = systemNow - _lastSlewed; - if (sinceLastSlewed >= MASSIVE_SHIFT || - sinceLastSlewed <= 0 - MASSIVE_SHIFT) { + if (sinceLastSlewed >= MASSIVE_SHIFT_FORWARD || + sinceLastSlewed <= 0 - MASSIVE_SHIFT_BACKWARD) { _lastSlewed = systemNow; notifyMassive(sinceLastSlewed); } else if (sinceLastSlewed >= MAX_SLEW) { @@ -224,7 +230,7 @@ public class RouterClock extends Clock { long nowNanos = System.nanoTime(); // try to prevent dups, not guaranteed // nanoTime() isn't guaranteed to be monotonic either :( - if (nowNanos < _lastShiftNanos + MASSIVE_SHIFT) + if (nowNanos < _lastShiftNanos + MASSIVE_SHIFT_FORWARD) return; _lastShiftNanos = nowNanos; diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index a85b0c8aa2..9535f12e9f 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 = 22; + public final static long BUILD = 23; /** for example "-test" */ public final static String EXTRA = "-rc"; diff --git a/router/java/src/net/i2p/router/client/ClientManager.java b/router/java/src/net/i2p/router/client/ClientManager.java index ef061e771b..da09267239 100644 --- a/router/java/src/net/i2p/router/client/ClientManager.java +++ b/router/java/src/net/i2p/router/client/ClientManager.java @@ -86,7 +86,7 @@ class ClientManager { } public void restart() { - shutdown(); + shutdown("Router restart"); // to let the old listener die try { Thread.sleep(2*1000); } catch (InterruptedException ie) {} @@ -96,7 +96,10 @@ class ClientManager { startListeners(port); } - public void shutdown() { + /** + * @param msg message to send to the clients + */ + public void shutdown(String msg) { _isStarted = false; _log.info("Shutting down the ClientManager"); if (_listener != null) @@ -116,7 +119,7 @@ class ClientManager { } for (Iterator iter = runners.iterator(); iter.hasNext(); ) { ClientConnectionRunner runner = iter.next(); - runner.disconnectClient("Router shutdown", Log.WARN); + runner.disconnectClient(msg, Log.WARN); } } diff --git a/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java b/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java index 35492936c4..94e2c0cf35 100644 --- a/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java +++ b/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java @@ -58,8 +58,16 @@ public class ClientManagerFacadeImpl extends ClientManagerFacade implements Inte } public void shutdown() { + shutdown("Router shutdown"); + } + + /** + * @param msg message to send to the clients + * @since 0.8.8 + */ + public void shutdown(String msg) { if (_manager != null) - _manager.shutdown(); + _manager.shutdown(msg); } public void restart() {