diff --git a/apps/i2psnark/java/src/net/i2p/kademlia/KBucketSet.java b/apps/i2psnark/java/src/net/i2p/kademlia/KBucketSet.java
index b87a7624a67d0438984916c4ede3cc53eda6fd6f..b84cdc66cf5151e5adfac19985016dd4caace023 100644
--- a/apps/i2psnark/java/src/net/i2p/kademlia/KBucketSet.java
+++ b/apps/i2psnark/java/src/net/i2p/kademlia/KBucketSet.java
@@ -209,10 +209,10 @@ public class KBucketSet<T extends SimpleDataStructure> {
             int s1, e1, s2, e2;
             s1 = b0.getRangeBegin();
             e2 = b0.getRangeEnd();
-            if (B_FACTOR > 1 &&
-                (s1 & (B_FACTOR - 1)) == 0 &&
-                ((e2 + 1) & (B_FACTOR - 1)) == 0 &&
-                e2 > s1 + B_FACTOR) {
+            if (B_VALUE == 1 ||
+                ((s1 & (B_FACTOR - 1)) == 0 &&
+                 ((e2 + 1) & (B_FACTOR - 1)) == 0 &&
+                 e2 > s1 + B_FACTOR)) {
                 // The bucket is a "whole" kbucket with a range > B_FACTOR,
                 // so it should be split into two "whole" kbuckets each with
                 // a range >= B_FACTOR.
@@ -526,17 +526,14 @@ public class KBucketSet<T extends SimpleDataStructure> {
     public List<T> getExploreKeys(long age) {
         List<T> rv = new ArrayList(_buckets.size());
         long old = _context.clock().now() - age;
-        int prevSize = -1;
         getReadLock();
         try {
             for (KBucket b : _buckets) {
                 int curSize = b.getKeyCount();
-                // The first few buckets are all empty, we only need one
-                // explore key for all of them.
-                if ((prevSize != 0 || curSize != 0) &&
+                // Always explore the closest bucket
+                if ((b.getRangeBegin() == 0) ||
                     (b.getLastChanged() < old || curSize < BUCKET_SIZE * 3 / 4))
                     rv.add(generateRandomKey(b));
-                prevSize = curSize;
             }
         } finally { releaseReadLock(); }
         return rv;
@@ -765,8 +762,8 @@ public class KBucketSet<T extends SimpleDataStructure> {
     public String toString() {
         StringBuilder buf = new StringBuilder(1024);
         buf.append("Bucket set rooted on: ").append(_us.toString())
-           .append(" K= ").append(BUCKET_SIZE)
-           .append(" B= ").append(B_VALUE)
+           .append(" K=").append(BUCKET_SIZE)
+           .append(" B=").append(B_VALUE)
            .append(" with ").append(size())
            .append(" keys in ").append(_buckets.size()).append(" buckets:\n");
         getReadLock();
diff --git a/apps/i2psnark/java/src/org/klomp/snark/dht/DHTNodes.java b/apps/i2psnark/java/src/org/klomp/snark/dht/DHTNodes.java
index ee0e8f01fde6f23e16848e95090933a96bc46085..21d394a807843452e44e4f2ff7d9ff0bdaada345 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/dht/DHTNodes.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/dht/DHTNodes.java
@@ -89,8 +89,13 @@ class DHTNodes {
      *  @return the old value if present, else null
      */
     public NodeInfo putIfAbsent(NodeInfo nInfo) {
-        _kad.add(nInfo.getNID());
-        return _nodeMap.putIfAbsent(nInfo.getNID(), nInfo);
+        NodeInfo rv = _nodeMap.putIfAbsent(nInfo.getNID(), nInfo);
+        // ensure same object in both places
+        if (rv != null)
+            _kad.add(rv.getNID());
+        else
+            _kad.add(nInfo.getNID());
+        return rv;
     }
 
     public NodeInfo remove(NID nid) {
diff --git a/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java b/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java
index 910841e79134e779dda97f66671ac39feb359ad5..55521a7876f081fdaf00937c1ef801aa4643c969 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java
@@ -1108,8 +1108,12 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
         if (nInfo.equals(_myNodeInfo))
             return _myNodeInfo;
         NodeInfo rv = _knownNodes.putIfAbsent(nInfo);
-        if (rv == null)
+        if (rv == null) {
             rv = nInfo;
+            // if we didn't know about it before, set the timestamp
+            // so it isn't immediately removed by the DHTNodes cleaner
+            rv.getNID().setLastSeen();
+        }
         return rv;
     }
 
diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
index d0ff6b06643f0c694037eecfbdef58bf0a195155..ea5d751e554cbc2062acdf1343b72d11374c4c18 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
@@ -1638,7 +1638,7 @@ public class I2PSnarkServlet extends DefaultServlet {
         out.write("\" ></td></tr>\n" +
         
                   "<tr><td>");
-        out.write(_("Enable DHT") + " (**BETA**)");
+        out.write(_("Enable DHT"));
         out.write(": <td><input type=\"checkbox\" class=\"optbox\" name=\"useDHT\" value=\"true\" " 
                   + (useDHT ? "checked " : "") 
                   + "title=\"");