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