From 4cec9da0a6bdfe88c4d4ceef14a02af10ccbbd4f Mon Sep 17 00:00:00 2001 From: jrandom <jrandom> Date: Thu, 24 Feb 2005 23:53:35 +0000 Subject: [PATCH] 2005-02-24 jrandom * Throttle the number of tunnel rebuilds per minute, preventing CPU overload under catastrophic failures (thanks Tracker and cervantes!) * Block the router startup process until we've initialized the clock --- core/java/src/net/i2p/time/Timestamper.java | 13 ++++ history.txt | 7 ++- router/java/src/net/i2p/router/Router.java | 8 +++ .../src/net/i2p/router/RouterVersion.java | 4 +- .../i2p/router/tunnel/pool/TunnelPool.java | 59 +++++++++++++++++-- 5 files changed, 84 insertions(+), 7 deletions(-) diff --git a/core/java/src/net/i2p/time/Timestamper.java b/core/java/src/net/i2p/time/Timestamper.java index 622d90b838..ebd29c6ef8 100644 --- a/core/java/src/net/i2p/time/Timestamper.java +++ b/core/java/src/net/i2p/time/Timestamper.java @@ -101,6 +101,15 @@ public class Timestamper implements Runnable { t.start(); } + public void waitForInitialization() { + try { + synchronized (this) { + if (!_initialized) + wait(); + } + } catch (InterruptedException ie) {} + } + public void run() { try { Thread.sleep(1000); } catch (InterruptedException ie) {} _log = _context.logManager().getLog(Timestamper.class); @@ -130,6 +139,9 @@ public class Timestamper implements Runnable { lastFailed = true; } } + + _initialized = true; + synchronized (this) { notifyAll(); } long sleepTime = _context.random().nextInt(_queryFrequency) + _queryFrequency; if (lastFailed) sleepTime = 30*1000; @@ -137,6 +149,7 @@ public class Timestamper implements Runnable { } } catch (Throwable t) { _log.log(Log.CRIT, "Timestamper died!", t); + synchronized (this) { notifyAll(); } } } diff --git a/history.txt b/history.txt index e154998dea..8e6d5fa9a1 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,9 @@ -$Id: history.txt,v 1.155 2005/02/23 16:44:32 jrandom Exp $ +$Id: history.txt,v 1.156 2005/02/24 13:05:26 jrandom Exp $ + +2005-02-24 jrandom + * Throttle the number of tunnel rebuilds per minute, preventing CPU + overload under catastrophic failures (thanks Tracker and cervantes!) + * Block the router startup process until we've initialized the clock 2005-02-24 jrandom * Cache temporary memory allocation in the DSA's SHA1 impl, and the packet diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index 2fe3fcb0d6..600b92c000 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -225,6 +225,14 @@ public class Router { warmupCrypto(); _sessionKeyPersistenceHelper.startup(); //_context.adminManager().startup(); + + // let the timestamper get us sync'ed + long before = System.currentTimeMillis(); + _context.clock().getTimestamper().waitForInitialization(); + long waited = System.currentTimeMillis() - before; + if (_log.shouldLog(Log.INFO)) + _log.info("Waited " + waited + "ms to initialize"); + _context.jobQueue().addJob(new StartupJob(_context)); } diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 897681ad52..9637e9494d 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.150 $ $Date: 2005/02/23 16:44:32 $"; + public final static String ID = "$Revision: 1.151 $ $Date: 2005/02/24 13:05:26 $"; public final static String VERSION = "0.5.0.1"; - public final static long BUILD = 2; + public final static long BUILD = 3; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java index ba6fb1954c..5d7bfabfd4 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java @@ -11,6 +11,7 @@ import net.i2p.data.Lease; import net.i2p.data.LeaseSet; import net.i2p.data.TunnelId; +import net.i2p.router.JobImpl; import net.i2p.router.RouterContext; import net.i2p.router.TunnelPoolSettings; import net.i2p.router.TunnelInfo; @@ -29,6 +30,16 @@ public class TunnelPool { private TunnelPoolManager _manager; private boolean _alive; private long _lifetimeProcessed; + private int _buildsThisMinute; + private long _currentMinute; + private RefreshJob _refreshJob; + + /** + * Only 3 builds per minute per pool, even if we have failing tunnels, + * etc. On overflow, the necessary additional tunnels are built by the + * RefreshJob + */ + private static final int MAX_BUILDS_PER_MINUTE = 3; public TunnelPool(RouterContext ctx, TunnelPoolManager mgr, TunnelPoolSettings settings, TunnelPeerSelector sel, TunnelBuilder builder) { _context = ctx; @@ -40,11 +51,16 @@ public class TunnelPool { _builder = builder; _alive = false; _lifetimeProcessed = 0; + _buildsThisMinute = 0; + _currentMinute = ctx.clock().now(); + _refreshJob = new RefreshJob(ctx); refreshSettings(); } public void startup() { _alive = true; + _refreshJob.getTiming().setStartAfter(_context.clock().now() + 60*1000); + _context.jobQueue().addJob(_refreshJob); int added = refreshBuilders(); if (added <= 0) { // we just reconnected and didn't require any new tunnel builders. @@ -92,10 +108,26 @@ public class TunnelPool { _log.info(toString() + ": refreshing builders, previously had " + usableTunnels + ", want a total of " + target + ", creating " + (target-usableTunnels) + " new ones."); - for (int i = usableTunnels; i < target; i++) - _builder.buildTunnel(_context, this); - - return (target > usableTunnels ? target-usableTunnels : 0); + + if (target > usableTunnels) { + long minute = _context.clock().now(); + minute = minute - (minute % 60*1000); + if (_currentMinute < minute) { + _currentMinute = minute; + _buildsThisMinute = 0; + } + int build = (target - usableTunnels); + if (build > (MAX_BUILDS_PER_MINUTE - _buildsThisMinute)) + build = (MAX_BUILDS_PER_MINUTE - _buildsThisMinute); + + for (int i = 0; i < build; i++) + _builder.buildTunnel(_context, this); + _buildsThisMinute += build; + + return build; + } else { + return 0; + } } void refreshSettings() { @@ -386,4 +418,23 @@ public class TunnelPool { } } + + /** + * We choke the # of rebuilds per pool per minute, so we need this to + * make sure to build enough tunnels. + * + */ + private class RefreshJob extends JobImpl { + public RefreshJob(RouterContext ctx) { + super(ctx); + } + public String getName() { return "Refresh pool"; } + public void runJob() { + if (!_alive) return; + int added = refreshBuilders(); + if ( (added > 0) && (_log.shouldLog(Log.WARN)) ) + _log.warn("Passive rebuilding a tunnel"); + requeue(60*1000); + } + } } -- GitLab