diff --git a/checklist.txt b/checklist.txt
index 92543048e8a3a9e43460cb099733825b3b616c42..50b07c210ed451dab962761b1f1575fdde610706 100644
--- a/checklist.txt
+++ b/checklist.txt
@@ -3,6 +3,7 @@ Release checklist
 
 Sync with mtn.i2p2.i2p
 Start with a clean checkout mtn -d i2p.mtn co --branch=i2p.i2p
+Double-check trust list
 
 Change revision in:
 	history.txt
@@ -14,7 +15,7 @@ Change revision in:
 Build and tag:
 	ant dist
 	mtn ci
-	mtn tag i2p-0.6.1.xx
+	mtn tag i2p-0.6.1.xx h:
 	Sync with mtn.i2p2.i2p
 
 Create a signed update file with:
@@ -27,11 +28,12 @@ Verify signed update file with:
 
 Make the source tarball:
 	Start with a clean checkout mtn -d i2p.mtn co --branch=i2p.i2p i2p-0.6.1.xx
-	tar tjf i2p-0.6.1.xx.tar.bz2 --exclude i2p-0.6.1.xx/_MTN i2p-0.6.1.xx	
+        Double-check trust list
+	tar cjf i2psource-0.6.1.xx.tar.bz2 --exclude i2p-0.6.1.xx/_MTN i2p-0.6.1.xx	
 	mv i2p-0.6.1.xx.tar.bz2 i2p.i2p
 
 More signatures:
-	sha1sum i2pinstall.exe i2p.tar.bz2 i2p-0.6.1.xx.tar.bz2 i2pupdate.zip
+	sha1sum i2pinstall.exe i2p.tar.bz2 i2psource-0.6.1.xx.tar.bz2 i2pupdate.zip
 	gpg -b i2pinstall.exe
 	gpg -b i2p.tar.bz2
 	gpg -b i2p-0.6.1.xx.tar.bz2
diff --git a/history.txt b/history.txt
index 60a560807f80302473ac586848f2c3725d812710..6109c2925ea9f23180be406a0206954d5fbb6475 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,13 @@
+2008-02-10 zzz
+    * Add new tunnel build algorithm (preliminary)
+    * Change NTCP backlogged message from error to warning
+    * Checklist updates
+
+* 2008-02-10  0.6.1.31 released
+
+2008-02-10 Complication
+    * Update news and version numbers
+
 2008-02-06 zzz
     * build.xml: Add some apps to javadoc
     * checklist.txt: Add some things
diff --git a/initialNews.xml b/initialNews.xml
index de1302491235089ceb4ec0455812a446e2a2a32f..3a67a3ed00d7bb390e2fa81da219d46a2d5f41e4 100644
--- a/initialNews.xml
+++ b/initialNews.xml
@@ -1,4 +1,4 @@
-<i2p.news date="$Date: 2007-08-23 19:33:29 $">
+<i2p.news date="$Date: 2008-02-10 15:00:00 $">
  <i2p.release version="0.6.1.31" date="2008/02/10" minVersion="0.6"
               anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
               publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
diff --git a/news.xml b/news.xml
index 9260af5d0b2b52e5d87721d49f4194cb840fad89..3b31d333f72798619395d591f3291807c299a2b0 100644
--- a/news.xml
+++ b/news.xml
@@ -1,5 +1,5 @@
-<i2p.news date="$Date: 2008-02-05 00:00:00 $">
- <i2p.release version="0.6.1.30" date="2007/02/15" minVersion="0.6"
+<i2p.news date="$Date: 2008-02-10 15:00:00 $">
+ <i2p.release version="0.6.1.31" date="2008/02/10" minVersion="0.6"
               anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
               publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
               anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-September/000878.html" 
@@ -9,25 +9,22 @@
             publicurl="http://dev.i2p.net/pipermail/i2p/2005-July/000826.html"
             anonlogs="http://i2p/Nf3ab-ZFkmI-LyMt7GjgT-jfvZ3zKDl0L96pmGQXF1B82W2Bfjf0n7~288vafocjFLnQnVcmZd~-p0-Oolfo9aW2Rm-AhyqxnxyLlPBqGxsJBXjPhm1JBT4Ia8FB-VXt0BuY0fMKdAfWwN61-tj4zIcQWRxv3DFquwEf035K~Ra4SWOqiuJgTRJu7~o~DzHVljVgWIzwf8Z84cz0X33pv-mdG~~y0Bsc2qJVnYwjjR178YMcRSmNE0FVMcs6f17c6zqhMw-11qjKpY~EJfHYCx4lBWF37CD0obbWqTNUIbL~78vxqZRT3dgAgnLixog9nqTO-0Rh~NpVUZnoUi7fNR~awW5U3Cf7rU7nNEKKobLue78hjvRcWn7upHUF45QqTDuaM3yZa7OsjbcH-I909DOub2Q0Dno6vIwuA7yrysccN1sbnkwZbKlf4T6~iDdhaSLJd97QCyPOlbyUfYy9QLNExlRqKgNVJcMJRrIual~Lb1CLbnzt0uvobM57UpqSAAAA/meeting141"
             publiclogs="http://www.i2p.net/meeting141" />
-&#149;
-2008-02-05: <b>*.i2p[.net] Replacements</b>
 <p>
-As you probably know, <a href="http://www.i2p.net/">www.i2p.net</a>
-and its related sites and services went down January 13 after
-a power outage at the hosting facility, and did not return fully to service.
-While some pages are still available at
-<a href="http://66.111.51.110/">66.111.51.110</a>
-we have a new official site at
-<a href="http://www.i2p2.de/">www.i2p2.de</a>
-and
-<a href="http://www.i2p2.i2p/">www.i2p2.i2p</a>.
-Extensive information about replacements for the various services
-is available at
-<a href="http://forum.i2p/viewtopic.php?t=2500">the forums</a>,
-<a href="http://complication.i2p/">complication.i2p</a>, and
-<a href="http://zzz.i2p/">zzz.i2p</a>.
-
+&#149;
+2008-02-10: <b>0.6.1.31 released</b>
+</p><p>
+The transitional 0.6.1.31 release will make the I2P
+release process independent of jrandom and *.i2p.net servers,
+introducing two new update verification keys, adding support
+for distributed update hosting inside I2P, and changing many URLs.
 </p><p>
+It introduces version 2 of the SAM protocol,
+along with substantial improvements to the address book,
+I2PSnark and ircproxy. Unless you have already done that,
+read about the update procedure below.
+</p>
+
+<p>
 &#149;
 2008-02-05: <b>Upcoming 0.6.1.31 Release</b>
 </p><p>
@@ -90,6 +87,26 @@ Thank you for your support during this transition. For help please contact us on
 Amiga, Complication, welterde, zzz
 </p>
 
+<p>
+&#149;
+2008-02-05: <b>*.i2p[.net] Replacements</b>
+<p>
+As you probably know, <a href="http://www.i2p.net/">www.i2p.net</a>
+and its related sites and services went down January 13 after
+a power outage at the hosting facility, and did not return fully to service.
+While some pages are still available at
+<a href="http://66.111.51.110/">66.111.51.110</a>
+we have a new official site at
+<a href="http://www.i2p2.de/">www.i2p2.de</a>
+and
+<a href="http://www.i2p2.i2p/">www.i2p2.i2p</a>.
+Extensive information about replacements for the various services
+is available at
+<a href="http://forum.i2p/viewtopic.php?t=2500">the forums</a>,
+<a href="http://complication.i2p/">complication.i2p</a>, and
+<a href="http://zzz.i2p/">zzz.i2p</a>.
+</p>
+
 <!--
 &#149;
 2007-04-10:
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 94d7e4b28ca64e73298dbab03245a38f23fd9777..8c95f8e9c3fdc29f47e8595c18c3bc2bfc7bdb72 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.548 $ $Date: 2008-01-08 21:15:43 $";
-    public final static String VERSION = "0.6.1.30";
-    public final static long BUILD = 27;
+    public final static String ID = "$Revision: 1.548 $ $Date: 2008-02-10 15:00:00 $";
+    public final static String VERSION = "0.6.1.31";
+    public final static long BUILD = 1;
     public static void main(String args[]) {
         System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
         System.out.println("Router ID: " + RouterVersion.ID);
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java
index 4efa61c24a96cb1ae296d3047302803cf58b333c..fe5569ef3881ce7297b550fa7f66cf2a28fa1e27 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java
@@ -268,8 +268,8 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener {
                 try { wantsWrite = ( (_conKey.interestOps() & SelectionKey.OP_WRITE) != 0); } catch (Exception e) {}
                 int blocks = 0;
 		synchronized (_writeBufs) { blocks = _writeBufs.size(); }
-                if (_log.shouldLog(Log.ERROR))
-                    _log.error("Too backlogged for too long (" + _consecutiveBacklog + " messages for " + DataHelper.formatDuration(queueTime()) + ", sched? " + wantsWrite + ", blocks: " + blocks + ") sending to " + _remotePeer.calculateHash().toBase64());
+                if (_log.shouldLog(Log.WARN))
+                    _log.warn("Too backlogged for too long (" + _consecutiveBacklog + " messages for " + DataHelper.formatDuration(queueTime()) + ", sched? " + wantsWrite + ", blocks: " + blocks + ") sending to " + _remotePeer.calculateHash().toBase64());
                 _context.statManager().addRateData("ntcp.closeOnBacklog", getUptime(), getUptime());
                 close();
             }
diff --git a/router/java/src/net/i2p/router/tunnel/pool/ExpireJob.java b/router/java/src/net/i2p/router/tunnel/pool/ExpireJob.java
index 953d2adbe3b9eb7ff98597d26d66882e43cc0dc8..1c0bb75e4c96960508863345d4d768401431cca3 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/ExpireJob.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/ExpireJob.java
@@ -19,9 +19,12 @@ class ExpireJob extends JobImpl {
         // so we rebuild out of sync.  otoh, we will honor tunnel messages on it
         // up through the full lifetime of the tunnel, plus a clock skew, since
         // others may be sending to the published lease expirations
+        // Also skew the inbound away from the outbound
         long expire = cfg.getExpiration();
         _dropAfter = expire + Router.CLOCK_FUDGE_FACTOR;
-        expire -= ctx.random().nextLong(5*60*1000);
+        expire -= ctx.random().nextLong(60*1000);
+        if (_pool.getSettings().isInbound())
+            expire -= ctx.random().nextLong(15*1000);
         cfg.setExpiration(expire);
         getTiming().setStartAfter(expire);
     }
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 256e905faab47bf913f0f24fed779a3fe84e4cd4..6faa1abbd76aea279cac0ba01b19c2a22bb6d642 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java
@@ -1,5 +1,6 @@
 package net.i2p.router.tunnel.pool;
 
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -16,6 +17,8 @@ import net.i2p.router.RouterContext;
 import net.i2p.router.TunnelPoolSettings;
 import net.i2p.router.TunnelInfo;
 import net.i2p.router.tunnel.HopConfig;
+import net.i2p.stat.Rate;
+import net.i2p.stat.RateStat;
 import net.i2p.util.Log;
 
 /**
@@ -36,7 +39,9 @@ public class TunnelPool {
     private long _started;
     private long _lastRateUpdate;
     private long _lastLifetimeProcessed;
-    private String _rateName;
+    private final String _rateName;
+    private final String _buildStatName;
+    private static final int TUNNEL_LIFETIME = 10*60*1000;
     
     public TunnelPool(RouterContext ctx, TunnelPoolManager mgr, TunnelPoolSettings settings, TunnelPeerSelector sel) {
         _context = ctx;
@@ -56,6 +61,9 @@ public class TunnelPool {
         _rateName = "tunnel.Bps." +
                     (_settings.isExploratory() ? "exploratory" : _settings.getDestinationNickname()) +
                     (_settings.isInbound() ? ".in" : ".out");
+        _buildStatName = "tunnel.build." +
+                    (_settings.isExploratory() ? "exploratory" : _settings.getDestinationNickname()) +
+                    (_settings.isInbound() ? ".in" : ".out");
         refreshSettings();
     }
     
@@ -79,6 +87,9 @@ public class TunnelPool {
         _context.statManager().createRateStat(_rateName,
                                "Tunnel Bandwidth", "Tunnels", 
                                new long[] { 5*60*1000l });
+        _context.statManager().createRateStat(_buildStatName,
+                               "Tunnel Build Frequency", "Tunnels", 
+                               new long[] { TUNNEL_LIFETIME });
     }
     
     public void shutdown() {
@@ -148,25 +159,43 @@ public class TunnelPool {
                 
                 // if there are nonzero hop tunnels and the zero hop tunnels are fallbacks, 
                 // avoid the zero hop tunnels
+                TunnelInfo backloggedTunnel = null;
                 if (avoidZeroHop) {
                     for (int i = 0; i < _tunnels.size(); i++) {
                         TunnelInfo info = (TunnelInfo)_tunnels.get(i);
                         if ( (info.getLength() > 1) && (info.getExpiration() > _context.clock().now()) ) {
-                            _lastSelected = info;
-                            return info;
+                            // avoid outbound tunnels where the 1st hop is backlogged
+                            if (_settings.isInbound() || !_context.commSystem().isBacklogged(info.getPeer(1))) {
+                                _lastSelected = info;
+                                return info;
+                            } else {
+                                backloggedTunnel = info;
+                            }
                         }
                     }
+                    // return a random backlogged tunnel
+                    if (backloggedTunnel != null)
+                        return backloggedTunnel;
                 }
                 // ok, either we are ok using zero hop tunnels, or only fallback tunnels remain.  pick 'em
                 // randomly
                 for (int i = 0; i < _tunnels.size(); i++) {
                     TunnelInfo info = (TunnelInfo)_tunnels.get(i);
                     if (info.getExpiration() > _context.clock().now()) {
-                        //_log.debug("Selecting tunnel: " + info + " - " + _tunnels);
-                        _lastSelected = info;
-                        return info;
+                        // avoid outbound tunnels where the 1st hop is backlogged
+                        if (_settings.isInbound() || info.getLength() <= 1 ||
+                            !_context.commSystem().isBacklogged(info.getPeer(1))) {
+                            //_log.debug("Selecting tunnel: " + info + " - " + _tunnels);
+                            _lastSelected = info;
+                            return info;
+                        } else {
+                            backloggedTunnel = info;
+                        }
                     }
                 }
+                // return a random backlogged tunnel
+                if (backloggedTunnel != null)
+                    return backloggedTunnel;
                 if (_log.shouldLog(Log.WARN))
                     _log.warn(toString() + ": after " + _tunnels.size() + " tries, no unexpired ones were found: " + _tunnels);
             }
@@ -445,6 +474,106 @@ public class TunnelPool {
         
         boolean allowZeroHop = ((getSettings().getLength() + getSettings().getLengthVariance()) <= 0);
           
+        /**
+         * This algorithm builds based on the previous average length of time it takes
+         * to build a tunnel. This average is kept in the _buildRateName stat.
+         * It is a separate stat for each pool, since in and out building use different methods,
+         * and each pool can have separate length and length variance settings.
+         * We add one minute to the stat for safety.
+         *
+         * We linearly increase the number of builds per expiring tunnel from
+         * 1 to PANIC_FACTOR as the time-to-expire gets shorter.
+         *
+         * The stat will be 0 for first 10m of uptime so we will use the conservative algorithm
+         * further below instead. It will take about 30m of uptime to settle down.
+         * Or, if we are building more than 33% of the time something is seriously wrong,
+         * we also use the conservative algorithm instead
+         *
+         **/
+
+        int avg = 0;
+        RateStat rs = _context.statManager().getRate(_buildStatName);
+        if (rs != null) {
+            Rate r = rs.getRate(TUNNEL_LIFETIME);
+            if (r != null)
+                avg = (int) ( TUNNEL_LIFETIME * r.getAverageValue() / wanted);
+        }
+
+        if (avg > 0 && avg < TUNNEL_LIFETIME / 3) {
+            final int PANIC_FACTOR = 4;  // how many builds to kick off when time gets short
+            avg += 60*1000;   // one minute safety factor
+            if (_settings.isExploratory())
+                avg += 60*1000;   // two minute safety factor
+            long now = _context.clock().now();
+
+            int expireSoon = 0;
+            int expireLater = 0;
+            int expireTime[];
+            int fallback = 0;
+            synchronized (_tunnels) {
+                expireTime = new int[_tunnels.size()];
+                for (int i = 0; i < _tunnels.size(); i++) {
+                    TunnelInfo info = (TunnelInfo)_tunnels.get(i);
+                    if (allowZeroHop || (info.getLength() > 1)) {
+                        int timeToExpire = (int) (info.getExpiration() - now);
+                        if (timeToExpire > 0 && timeToExpire < avg) {
+                            expireTime[expireSoon++] = timeToExpire;
+                        } else {
+                            expireLater++;
+                        }
+                    } else if (info.getExpiration() - now > avg) {
+                        fallback++;
+                    }
+                }
+            }
+
+            int inProgress;
+            synchronized (_inProgress) {
+                inProgress = _inProgress.size();
+            }
+            int remainingWanted = (wanted - expireLater) - inProgress;
+            if (allowZeroHop)
+                remainingWanted -= fallback;
+
+            int rv = 0;
+            int latesttime = 0;
+            if (remainingWanted > 0) {
+                if (remainingWanted > expireSoon) {
+                    rv = PANIC_FACTOR * (remainingWanted - expireSoon);  // for tunnels completely missing
+                    remainingWanted = expireSoon;
+                }
+                // add from 1 to PANIC_FACTOR builds, depending on how late it is
+                // only use the expire times of the latest-expiring tunnels,
+                // the other ones are extras
+                for (int i = 0; i < remainingWanted; i++) {
+                    int latestidx = 0;
+                    // given the small size of the array this is efficient enough
+                    for (int j = 0; j < expireSoon; j++) {
+                        if (expireTime[j] > latesttime) {
+                            latesttime = expireTime[j];
+                            latestidx = j;
+                        }
+                    }
+                    expireTime[latestidx] = 0;
+                    if (latesttime > avg / 2)
+                        rv += 1;
+                    else
+                        rv += 2 + ((PANIC_FACTOR - 2) * (((avg / 2) - latesttime) / (avg / 2)));
+                }
+            }
+
+            if (rv > 0 && _log.shouldLog(Log.DEBUG))
+                _log.debug("New Count: rv: " + rv + " allow? " + allowZeroHop
+                       + " avg " + avg + " latesttime " + latesttime
+                       + " soon " + expireSoon + " later " + expireLater
+                       + " std " + wanted + " inProgress " + inProgress + " fallback " + fallback 
+                       + " for " + toString());
+            _context.statManager().addRateData(_buildStatName, rv + inProgress, 0);
+            return rv;
+        }
+
+        // fixed, conservative algorithm - starts building 3 1/2 - 6m before expiration
+        // (210 or 270s) + (0..90s random)
         long expireAfter = _context.clock().now() + _expireSkew; // + _settings.getRebuildPeriod() + _expireSkew;
         int expire30s = 0;
         int expire90s = 0;
@@ -491,8 +620,11 @@ public class TunnelPool {
             }
         }
         
-        return countHowManyToBuild(allowZeroHop, expire30s, expire90s, expire150s, expire210s, expire270s, 
+        int rv = countHowManyToBuild(allowZeroHop, expire30s, expire90s, expire150s, expire210s, expire270s, 
                                    expireLater, wanted, inProgress, fallback);
+        _context.statManager().addRateData(_buildStatName, (rv > 0 || inProgress > 0) ? 1 : 0, 0);
+        return rv;
+
     }
     
     /**
@@ -590,7 +722,7 @@ public class TunnelPool {
         if ( (lifetime < 60*1000) && (rv + inProgress + fallback >= standardAmount) )
                 rv = standardAmount - inProgress - fallback;
         
-        if (_log.shouldLog(Log.DEBUG))
+        if (rv > 0 && _log.shouldLog(Log.DEBUG))
             _log.debug("Count: rv: " + rv + " allow? " + allowZeroHop
                        + " 30s " + expire30s + " 90s " + expire90s + " 150s " + expire150s + " 210s " + expire210s
                        + " 270s " + expire270s + " later " + expireLater