diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index 9c71761c199fe73c762beb1b3e1f0587b2e51173..e8dabe0bdba58ac1cf1bac34ebce1a4322d7049b 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -916,11 +916,11 @@ public class Router implements RouterClock.ClockShiftListener {
             } else if (_state == State.EXPL_TUNNELS_READY) {
                 changeState(State.RUNNING);
                 changed = true;
-            } else {
-                _log.warn("Invalid state " + _state + " for setNetDbReady()");
             }
         }
-        if (changed) {
+        if (_context.netDb().isInitialized()) {
+            if (_log.shouldWarn())
+                _log.warn("NetDB ready, publishing RI");
             // any previous calls to netdb().publish() did not
             // actually publish, because netdb init was not complete
             Republish r = new Republish(_context);
@@ -928,6 +928,8 @@ public class Router implements RouterClock.ClockShiftListener {
             // so we probably don't need to throw it to the timer queue,
             // but just to be safe
             _context.simpleTimer2().addEvent(r, 0);
+        }
+        if (changed) {
             _context.commSystem().initGeoIP();
 
             if (!SystemVersion.isSlow() &&
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java
index 7dc2b9d6fa921112394dec979bd630b203a72400..a00de87c30386ee969a0034f382cc120561e3ad1 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java
@@ -11,6 +11,7 @@ package net.i2p.router.networkdb.kademlia;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import net.i2p.crypto.EncType;
 import net.i2p.crypto.SigType;
@@ -337,8 +338,8 @@ abstract class StoreJob extends JobImpl {
             return;
         }
 
-        if (_log.shouldLog(Log.DEBUG))
-            _log.debug(getJobId() + ": Send store timeout is " + responseTime);
+        //if (_log.shouldLog(Log.DEBUG))
+        //    _log.debug(getJobId() + ": Send store timeout is " + responseTime);
 
         sendStore(msg, router, now + responseTime);
     }
@@ -349,19 +350,22 @@ abstract class StoreJob extends JobImpl {
      *
      */
     private void sendStore(DatabaseStoreMessage msg, RouterInfo peer, long expiration) {
+        RouterContext ctx = getContext();
         if (msg.getEntry().isLeaseSet()) {
-            getContext().statManager().addRateData("netDb.storeLeaseSetSent", 1);
+            ctx.statManager().addRateData("netDb.storeLeaseSetSent", 1);
             // if it is an encrypted leaseset...
-            if (getContext().keyRing().get(msg.getKey()) != null)
+            if (ctx.keyRing().get(msg.getKey()) != null)
                 sendStoreThroughExploratory(msg, peer, expiration);
             else if (msg.getEntry().getType() == DatabaseEntry.KEY_TYPE_META_LS2)
                 sendWrappedStoreThroughExploratory(msg, peer, expiration);
             else
                 sendStoreThroughClient(msg, peer, expiration);
         } else {
-            getContext().statManager().addRateData("netDb.storeRouterInfoSent", 1);
+            ctx.statManager().addRateData("netDb.storeRouterInfoSent", 1);
             // if we can't connect to peer directly, just send it out an exploratory tunnel
-            if (_connectChecker.canConnect(_connectMask, peer))
+            Hash h = peer.getIdentity().getHash();
+            if (ctx.commSystem().isEstablished(h) ||
+                (!ctx.commSystem().wasUnreachable(h) && _connectChecker.canConnect(_connectMask, peer)))
                 sendDirect(msg, peer, expiration);
             else
                 sendStoreThroughExploratory(msg, peer, expiration);
@@ -756,6 +760,7 @@ abstract class StoreJob extends JobImpl {
     private class FailedJob extends JobImpl {
         private final RouterInfo _peer;
         private final long _sendOn;
+        private final AtomicBoolean _wasRun = new AtomicBoolean();
 
         public FailedJob(RouterContext enclosingContext, RouterInfo peer, long sendOn) {
             super(enclosingContext);
@@ -763,6 +768,8 @@ abstract class StoreJob extends JobImpl {
             _sendOn = sendOn;
         }
         public void runJob() {
+            if (!_wasRun.compareAndSet(false, true))
+                return;
             Hash hash = _peer.getIdentity().getHash();
             if (_log.shouldLog(Log.INFO))
                 _log.info(StoreJob.this.getJobId() + ": Peer " + hash.toBase64()