diff --git a/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelManagerFacade.java b/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelManagerFacade.java
index f4539b7400fd03bc8f09c44896be145d75bf718e..8eced3acfc25a2c9f8a1b6c3e9972580f13b9e7f 100644
--- a/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelManagerFacade.java
+++ b/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelManagerFacade.java
@@ -146,6 +146,10 @@ public class PoolingTunnelManagerFacade implements TunnelManagerFacade {
      *
      */
     public void peerFailed(Hash peer) {
+        if (true) {
+            _log.error("Peer " + peer.toBase64() + " failed, but we're not going to kill their tunnels", new Exception("wtf"));
+            return;
+        }
         int numFailed = 0;
         for (Iterator iter = _pool.getManagedTunnelIds().iterator(); iter.hasNext(); ) {
             TunnelId id = (TunnelId)iter.next();
diff --git a/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelSelector.java b/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelSelector.java
index 396d16a3a426d3e4b0e86d9d74103539c4aec99a..4a429f140ad5034537e3ac617c296bf36cbf2fb9 100644
--- a/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelSelector.java
+++ b/router/java/src/net/i2p/router/tunnelmanager/PoolingTunnelSelector.java
@@ -4,7 +4,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
@@ -30,20 +30,19 @@ class PoolingTunnelSelector {
     }
     
     public List selectOutboundTunnelIds(TunnelPool pool, TunnelSelectionCriteria criteria) {
-        List tunnelIds = new LinkedList();
-        
-        for (int i = pool.getOutboundTunnelCount(); i < criteria.getMinimumTunnelsRequired(); i++) {
-            if (_log.shouldLog(Log.WARN))
-                _log.warn("Building fake tunnels because the outbound tunnels weren't sufficient");
-            pool.buildFakeTunnels();
-        }
+        List tunnelIds = new ArrayList(criteria.getMinimumTunnelsRequired());
         
         Set outIds = pool.getOutboundTunnels();
         for (Iterator iter = outIds.iterator(); iter.hasNext(); ) {
             TunnelId id = (TunnelId)iter.next();
             TunnelInfo info = pool.getOutboundTunnel(id);
             if ( (info != null) && (info.getIsReady()) ) {
-                tunnelIds.add(id);
+                if (isAlmostExpired(pool, id, POOL_USE_SAFETY_MARGIN)) {
+                    if (_log.shouldLog(Log.INFO)) 
+                        _log.info("Tunnel " + id + " is almost expired");
+                } else {
+                    tunnelIds.add(id);
+                }
             } else {
                 if (info == null) {
                     if (_log.shouldLog(Log.WARN))
@@ -54,6 +53,17 @@ class PoolingTunnelSelector {
                 }
             }
         }
+        
+        boolean rebuilt = false;
+        for (int i = outIds.size(); i < criteria.getMinimumTunnelsRequired(); i++) {
+            if (_log.shouldLog(Log.WARN))
+                _log.warn("Building fake tunnels because the outbound tunnels weren't sufficient");
+            pool.buildFakeTunnels();
+            rebuilt = true;
+        }
+        if (rebuilt)
+            return selectOutboundTunnelIds(pool, criteria);
+        
         List ordered = randomize(pool, tunnelIds);
         List rv = new ArrayList(criteria.getMinimumTunnelsRequired());
         for (Iterator iter = ordered.iterator(); iter.hasNext() && (rv.size() < criteria.getMinimumTunnelsRequired()); ) {
@@ -66,20 +76,19 @@ class PoolingTunnelSelector {
     }
     
     public List selectInboundTunnelIds(TunnelPool pool, TunnelSelectionCriteria criteria) {
-        List tunnels = new LinkedList();
-        
-        for (int i = pool.getFreeTunnelCount(); i < criteria.getMinimumTunnelsRequired(); i++) {
-            if (_log.shouldLog(Log.WARN))
-                _log.warn("Building fake tunnels because the inbound tunnels weren't sufficient");
-            pool.buildFakeTunnels();
-        }
+        List tunnels = new ArrayList(criteria.getMinimumTunnelsRequired());
         
         for (Iterator iter = pool.getFreeTunnels().iterator(); iter.hasNext(); ) {
             TunnelId id = (TunnelId)iter.next();
             TunnelInfo info = pool.getFreeTunnel(id);
             if (info == null) continue;
             if (info.getIsReady()) {
-                tunnels.add(id);
+                if (isAlmostExpired(pool, id, POOL_USE_SAFETY_MARGIN)) {
+                    if (_log.shouldLog(Log.INFO)) 
+                        _log.info("Tunnel " + id + " is almost expired");
+                } else {
+                    tunnels.add(id);
+                }
             } else {
                 if (_log.shouldLog(Log.DEBUG))
                     _log.debug("Inbound tunnel " + id + " is not ready?! " 
@@ -87,6 +96,16 @@ class PoolingTunnelSelector {
             }
         }
         
+        boolean rebuilt = false;
+        for (int i = tunnels.size(); i < criteria.getMinimumTunnelsRequired(); i++) {
+            if (_log.shouldLog(Log.WARN))
+                _log.warn("Building fake tunnels because the inbound tunnels weren't sufficient");
+            pool.buildFakeTunnels();
+            rebuilt = true;
+        }
+        if (rebuilt)
+            return selectInboundTunnelIds(pool, criteria);
+        
         List ordered = randomize(pool, tunnels);
         List rv = new ArrayList(criteria.getMinimumTunnelsRequired());
         for (Iterator iter = ordered.iterator(); iter.hasNext() && (rv.size() < criteria.getMinimumTunnelsRequired()); ) {
@@ -107,8 +126,6 @@ class PoolingTunnelSelector {
         List rv = new ArrayList(tunnelIds.size());
         for (Iterator iter = tunnelIds.iterator(); iter.hasNext(); ) {
             TunnelId id = (TunnelId)iter.next();
-            if (isAlmostExpired(pool, id, POOL_USE_SAFETY_MARGIN))
-                continue;
             rv.add(id);
         }
         Collections.shuffle(rv, _context.random());
@@ -117,9 +134,21 @@ class PoolingTunnelSelector {
     
     private boolean isAlmostExpired(TunnelPool pool, TunnelId id, long safetyMargin) {
         TunnelInfo info = pool.getTunnelInfo(id);
-        if (info == null) return true;
-        if (info.getSettings() == null) return true;
-        if (info.getSettings().getExpiration() <= 0) return true;
+        if (info == null) {
+            if (_log.shouldLog(Log.ERROR))
+                _log.error("Tunnel " + id.getTunnelId() + " is not known");
+            return true;
+        }
+        if (info.getSettings() == null) {
+            if (_log.shouldLog(Log.ERROR))
+                _log.error("Tunnel " + id.getTunnelId() + " has no settings");
+            return true;
+        }
+        if (info.getSettings().getExpiration() <= 0) {
+            if (_log.shouldLog(Log.ERROR))
+                _log.error("Tunnel " + id.getTunnelId() + " has no expiration");
+            return true;
+        }
         if (info.getSettings().getExpiration() - safetyMargin <= _context.clock().now()) {
             if (_log.shouldLog(Log.DEBUG))
                 _log.debug("Expiration of tunnel " + id.getTunnelId() 
diff --git a/router/java/src/net/i2p/router/tunnelmanager/TunnelPool.java b/router/java/src/net/i2p/router/tunnelmanager/TunnelPool.java
index de352d1e37b72165795a42f3d9635531bef00b08..dd83a0f0d0257a582084724a2a8192292996e4f1 100644
--- a/router/java/src/net/i2p/router/tunnelmanager/TunnelPool.java
+++ b/router/java/src/net/i2p/router/tunnelmanager/TunnelPool.java
@@ -524,8 +524,8 @@ class TunnelPool {
     
     public void tunnelFailed(TunnelId id) {
         if (!_isLive) return;
-        if (_log.shouldLog(Log.INFO)) 
-            _log.info("Tunnel " + id + " marked as not ready, since it /failed/", new Exception("Failed tunnel"));
+        if (_log.shouldLog(Log.ERROR)) 
+            _log.error("Tunnel " + id + " marked as not ready, since it /failed/", new Exception("Failed tunnel"));
         TunnelInfo info = getTunnelInfo(id);
         if (info == null)
             return;
diff --git a/router/java/src/net/i2p/router/tunnelmanager/TunnelPoolManagerJob.java b/router/java/src/net/i2p/router/tunnelmanager/TunnelPoolManagerJob.java
index 87b9b55e6955e1715675daddb20ae065d4e1ea5c..004f4aae47156ebc21a9934692cee75394295691 100644
--- a/router/java/src/net/i2p/router/tunnelmanager/TunnelPoolManagerJob.java
+++ b/router/java/src/net/i2p/router/tunnelmanager/TunnelPoolManagerJob.java
@@ -18,9 +18,6 @@ class TunnelPoolManagerJob extends JobImpl {
     private Log _log;
     private TunnelPool _pool;
     
-    /** whether we built tunnels on the last run */
-    private boolean _builtOnLastRun;
-    
     /**
      * How frequently to check the pool (and fire appropriate refill jobs)
      *
@@ -48,8 +45,8 @@ class TunnelPoolManagerJob extends JobImpl {
             boolean built = false;
     
             int targetClients = _pool.getTargetClients();
-            int targetInboundTunnels = targetClients*_pool.getPoolSettings().getNumInboundTunnels() + 3;
-            int targetOutboundTunnels = targetClients*_pool.getPoolSettings().getNumOutboundTunnels() + 3;
+            int targetInboundTunnels = targetClients*_pool.getPoolSettings().getNumInboundTunnels() + 1;
+            int targetOutboundTunnels = targetClients*_pool.getPoolSettings().getNumOutboundTunnels() + 1;
     
             int curFreeInboundTunnels = getFreeTunnelCount();
             if (curFreeInboundTunnels < targetInboundTunnels) {
@@ -60,7 +57,8 @@ class TunnelPoolManagerJob extends JobImpl {
                 //requestFakeInboundTunnels(1);
                 built = true;
             } else {
-                if (_builtOnLastRun) {
+                // 10% chance of building a new tunnel
+                if (getContext().random().nextInt(9) > 0) {
                     // all good, no need for more inbound tunnels
                     if (_log.shouldLog(Log.DEBUG))
                         _log.debug("Sufficient inbound tunnels (" + curFreeInboundTunnels + ")");
@@ -81,7 +79,8 @@ class TunnelPoolManagerJob extends JobImpl {
                 //requestFakeOutboundTunnels(1);
                 built = true;
             } else {
-                if (_builtOnLastRun) {
+                // 10% chance of building a new tunnel
+                if (getContext().random().nextInt(9) > 0) {
                     // all good, no need for more outbound tunnels
                     if (_log.shouldLog(Log.DEBUG))
                         _log.debug("Sufficient outbound tunnels (" + curOutboundTunnels + ")");
@@ -94,7 +93,6 @@ class TunnelPoolManagerJob extends JobImpl {
             }
 
             _pool.buildFakeTunnels();
-            _builtOnLastRun = built;
         } catch (Throwable t) {
             _log.log(Log.CRIT, "Unhandled exception managing the tunnel pool", t);
         }
@@ -109,6 +107,7 @@ class TunnelPoolManagerJob extends JobImpl {
     private int getFreeTunnelCount() {
         Set freeTunnels = _pool.getFreeTunnels();
         int free = 0;
+        int tooShort = 0;
         int minLength = _pool.getPoolSettings().getDepthInbound();
         long mustExpireAfter = getContext().clock().now() + EXPIRE_FUDGE_PERIOD;
         for (Iterator iter = freeTunnels.iterator(); iter.hasNext(); ) {
@@ -131,14 +130,20 @@ class TunnelPoolManagerJob extends JobImpl {
                         // for the moment we'll keep these around so that we can use them
                         // for tunnel management and db messages, rather than force all
                         // tunnels to be the 2+ hop length as required for clients
-                        free++;
+                        tooShort++; // free++;
                     }
                 } else {
                     _log.info("Inbound tunnel " + id + " is expiring in the upcoming period, consider it not-free");
                 }
             }
         }
-        return free;
+        if (free <= 0) {
+            if (_log.shouldLog(Log.WARN)) 
+                _log.warn("No free tunnels that are long enough, but there are " + tooShort + " shorter ones");
+            return tooShort;
+        } else {
+            return free;
+        }
     }
     
     /**