From 82f3f7506ccd1c02c0c9540197bc862bb8548cba Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Mon, 10 May 2010 15:00:13 +0000
Subject: [PATCH]     * NetDB:       - Handle old and duplicate stores more
 efficiently       - Have DataStore put() return success

---
 .../router/networkdb/kademlia/DataStore.java  |  6 +-
 .../kademlia/PersistentDataStore.java         | 14 ++--
 .../kademlia/TransientDataStore.java          | 67 ++++++++++---------
 3 files changed, 48 insertions(+), 39 deletions(-)

diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/DataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/DataStore.java
index ae41326782..b4b55f3f8e 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/DataStore.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/DataStore.java
@@ -18,11 +18,11 @@ public interface DataStore {
     public boolean isKnown(Hash key);
     public DataStructure get(Hash key);
     public DataStructure get(Hash key, boolean persist);
-    public void put(Hash key, DataStructure data);
-    public void put(Hash key, DataStructure data, boolean persist);
+    public boolean put(Hash key, DataStructure data);
+    public boolean put(Hash key, DataStructure data, boolean persist);
     public DataStructure remove(Hash key);
     public DataStructure remove(Hash key, boolean persist);
-    public Set getKeys();
+    public Set<Hash> getKeys();
     public void stop();
     public void restart();
     public void rescan();
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java
index c94ad7a76f..77ea8c4573 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java
@@ -128,20 +128,22 @@ class PersistentDataStore extends TransientDataStore {
     }
     
     @Override
-    public void put(Hash key, DataStructure data) {
-        put(key, data, true);
+    public boolean put(Hash key, DataStructure data) {
+        return put(key, data, true);
     }
 
     /*
      *  @param persist if false, call super only, don't access disk
+     *  @return success
      */
     @Override
-    public void put(Hash key, DataStructure data, boolean persist) {
-        if ( (data == null) || (key == null) ) return;
-        super.put(key, data);
+    public boolean put(Hash key, DataStructure data, boolean persist) {
+        if ( (data == null) || (key == null) ) return false;
+        boolean rv = super.put(key, data);
         // Don't bother writing LeaseSets to disk
-        if (persist && data instanceof RouterInfo)
+        if (rv && persist && data instanceof RouterInfo)
             _writer.queue(key, data);
+        return rv;
     }
     
     private class RemoveJob extends JobImpl {
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java
index 38efb714fb..d5e10738c2 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java
@@ -24,7 +24,7 @@ import net.i2p.util.Log;
 
 class TransientDataStore implements DataStore {
     private Log _log;
-    private Map<Hash, DataStructure> _data;
+    private ConcurrentHashMap<Hash, DataStructure> _data;
     protected RouterContext _context;
     
     public TransientDataStore(RouterContext ctx) {
@@ -47,11 +47,11 @@ class TransientDataStore implements DataStore {
     
     public void rescan() {}
 
-    public Set getKeys() {
+    public Set<Hash> getKeys() {
         return new HashSet(_data.keySet());
     }
     
-    /** for PersistentDataStore only - don't use here */
+    /** for PersistentDataStore only - don't use here @throws IAE always */
     public DataStructure get(Hash key, boolean persist) {
         throw new IllegalArgumentException("no");
     }
@@ -73,22 +73,22 @@ class TransientDataStore implements DataStore {
         return count;
     }
     
-    /** nothing published more than 5 minutes in the future */
-    private final static long MAX_FUTURE_PUBLISH_DATE = 5*60*1000;
-    /** don't accept tunnels set to expire more than 3 hours in the future, which is insane */
-    private final static long MAX_FUTURE_EXPIRATION_DATE = KademliaNetworkDatabaseFacade.MAX_LEASE_FUTURE;
-    
-    /** for PersistentDataStore only - don't use here */
-    public void put(Hash key, DataStructure data, boolean persist) {
+    /** for PersistentDataStore only - don't use here @throws IAE always */
+    public boolean put(Hash key, DataStructure data, boolean persist) {
         throw new IllegalArgumentException("no");
     }
 
-    public void put(Hash key, DataStructure data) {
-        if (data == null) return;
+    /**
+     *  @param data must be validated before here
+     *  @return success
+     */
+    public boolean put(Hash key, DataStructure data) {
+        if (data == null) return false;
         if (_log.shouldLog(Log.DEBUG))
             _log.debug("Storing key " + key);
         DataStructure old = null;
-        old = _data.put(key, data);
+        old = _data.putIfAbsent(key, data);
+        boolean rv = false;
         if (data instanceof RouterInfo) {
             // Don't do this here so we don't reset it at router startup;
             // the StoreMessageJob calls this
@@ -99,26 +99,19 @@ class TransientDataStore implements DataStore {
                 if (ri.getPublished() < ori.getPublished()) {
                     if (_log.shouldLog(Log.INFO))
                         _log.info("Almost clobbered an old router! " + key + ": [old published on " + new Date(ori.getPublished()) + " new on " + new Date(ri.getPublished()) + "]");
-                    if (_log.shouldLog(Log.DEBUG))
-                        _log.debug("Number of router options for " + key + ": " + ri.getOptions().size() + " (old one had: " + ori.getOptions().size() + ")", new Exception("Updated routerInfo"));
-                    _data.put(key, old);
-                } else if (ri.getPublished() > _context.clock().now() + MAX_FUTURE_PUBLISH_DATE) {
+                } else if (ri.getPublished() == ori.getPublished()) {
                     if (_log.shouldLog(Log.INFO))
-                        _log.info("Hmm, someone tried to give us something with the publication date really far in the future (" + new Date(ri.getPublished()) + "), dropping it");
-                    if (_log.shouldLog(Log.DEBUG))
-                        _log.debug("Number of router options for " + key + ": " + ri.getOptions().size() + " (old one had: " + ori.getOptions().size() + ")", new Exception("Updated routerInfo"));
-                    _data.put(key, old);
+                        _log.info("Duplicate " + key);
                 } else {
                     if (_log.shouldLog(Log.INFO))
                         _log.info("Updated the old router for " + key + ": [old published on " + new Date(ori.getPublished()) + " new on " + new Date(ri.getPublished()) + "]");
-                    if (_log.shouldLog(Log.DEBUG))
-                        _log.debug("Number of router options for " + key + ": " + ri.getOptions().size() + " (old one had: " + ori.getOptions().size() + ")", new Exception("Updated routerInfo"));
+                    _data.put(key, data);
+                    rv = true;
                 }
             } else {
                 if (_log.shouldLog(Log.INFO))
-                    _log.info("Brand new router for " + key + ": published on " + new Date(ri.getPublished()));
-                if (_log.shouldLog(Log.DEBUG))
-                    _log.debug("Number of router options for " + key + ": " + ri.getOptions().size(), new Exception("Updated routerInfo"));
+                    _log.info("New router for " + key + ": published on " + new Date(ri.getPublished()));
+                rv = true;
             }
         } else if (data instanceof LeaseSet) {
             LeaseSet ls = (LeaseSet)data;
@@ -127,14 +120,28 @@ class TransientDataStore implements DataStore {
                 if (ls.getEarliestLeaseDate() < ols.getEarliestLeaseDate()) {
                     if (_log.shouldLog(Log.INFO))
                         _log.info("Almost clobbered an old leaseSet! " + key + ": [old published on " + new Date(ols.getEarliestLeaseDate()) + " new on " + new Date(ls.getEarliestLeaseDate()) + "]");
-                    _data.put(key, old);
-                } else if (ls.getEarliestLeaseDate() > _context.clock().now() + MAX_FUTURE_EXPIRATION_DATE) {
+                } else if (ls.getEarliestLeaseDate() == ols.getEarliestLeaseDate()) {
                     if (_log.shouldLog(Log.INFO))
-                        _log.info("Hmm, someone tried to give us something with the expiration date really far in the future (" + new Date(ls.getEarliestLeaseDate()) + "), dropping it");
-                    _data.put(key, old);
+                        _log.info("Duplicate " + key);
+                } else {
+                    if (_log.shouldLog(Log.INFO)) {
+                        _log.info("Updated old leaseSet " + key + ": [old published on " + new Date(ols.getEarliestLeaseDate()) + " new on " + new Date(ls.getEarliestLeaseDate()) + "]");
+                        if (_log.shouldLog(Log.DEBUG))
+                            _log.debug("RAP? " + ls.getReceivedAsPublished() + " RAR? " + ls.getReceivedAsReply());
+                    }
+                    _data.put(key, data);
+                    rv = true;
+                }
+            } else {
+                if (_log.shouldLog(Log.INFO)) {
+                    _log.info("New leaseset for " + key + ": published on " + new Date(ls.getEarliestLeaseDate()));
+                    if (_log.shouldLog(Log.DEBUG))
+                        _log.debug("RAP? " + ls.getReceivedAsPublished() + " RAR? " + ls.getReceivedAsReply());
                 }
+                rv = true;
             }
         }
+        return rv;
     }
     
     @Override
-- 
GitLab