From f61183d2d85bb76cdf2b4db972951ffa34987b82 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Wed, 29 Feb 2012 18:09:16 +0000
Subject: [PATCH]   * DataStructures:     - Remove static logs     - Sort
 addresses in RouterInfo at initialization only;       change from Set to List
 to save space     - Remove unused counters in Lease to save space     -
 Increase max leases to 16

---
 core/java/src/net/i2p/data/DataHelper.java    | 12 +++-
 core/java/src/net/i2p/data/LeaseSet.java      | 42 ++++++++++----
 core/java/src/net/i2p/data/RouterInfo.java    | 55 +++++++++++--------
 router/java/src/net/i2p/router/Blocklist.java |  8 +--
 .../kademlia/FloodfillVerifyStoreJob.java     |  2 +-
 ...andleFloodfillDatabaseStoreMessageJob.java |  9 +--
 .../router/peermanager/ProfileOrganizer.java  |  3 +-
 7 files changed, 83 insertions(+), 48 deletions(-)

diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java
index d809926098..ad6ac6ea9d 100644
--- a/core/java/src/net/i2p/data/DataHelper.java
+++ b/core/java/src/net/i2p/data/DataHelper.java
@@ -1299,10 +1299,20 @@ public class DataHelper {
         //    rv.add(struct);
         //}
         ArrayList<DataStructure> rv = new ArrayList(dataStructures);
-        Collections.sort(rv, new DataStructureComparator());
+        sortStructureList(rv);
         return rv;
     }
 
+    /**
+     *  See above.
+     *  DEPRECATED - Only used by RouterInfo.
+     *
+     *  @since 0.9
+     */
+    static void sortStructureList(List<? extends DataStructure> dataStructures) {
+        Collections.sort(dataStructures, new DataStructureComparator());
+    }
+
     /**
      * See sortStructures() comments.
      * @since 0.8.3
diff --git a/core/java/src/net/i2p/data/LeaseSet.java b/core/java/src/net/i2p/data/LeaseSet.java
index e372f401cd..9fe9ebb304 100644
--- a/core/java/src/net/i2p/data/LeaseSet.java
+++ b/core/java/src/net/i2p/data/LeaseSet.java
@@ -56,7 +56,6 @@ import net.i2p.util.RandomSource;
  * @author jrandom
  */
 public class LeaseSet extends DatabaseEntry {
-    private final static Log _log = new Log(LeaseSet.class);
     private Destination _destination;
     private PublicKey _encryptionKey;
     private SigningPublicKey _signingKey;
@@ -71,11 +70,26 @@ public class LeaseSet extends DatabaseEntry {
     private boolean _decrypted;
     private boolean _checked;
 
-    /** This seems like plenty  */
-    public final static int MAX_LEASES = 6;
+    /**
+     *  Unlimited before 0.6.3;
+     *  6 as of 0.6.3;
+     *  Increased in version 0.9.
+     *
+     *  Leasesets larger than 6 should be used with caution,
+     *  as each lease adds 44 bytes, and routers older than version 0.9
+     *  will not be able to connect as they will throw an exception in
+     *  readBytes(). Also, the churn will be quite rapid, leading to
+     *  frequent netdb stores and transmission on existing connections.
+     *
+     *  However we increase it now in case some hugely popular eepsite arrives.
+     *  Strategies elsewhere in the router to efficiently handle
+     *  large leasesets are TBD.
+     */
+    public static final int MAX_LEASES = 16;
+    private static final int OLD_MAX_LEASES = 6;
 
     public LeaseSet() {
-        _leases = new ArrayList(MAX_LEASES);
+        _leases = new ArrayList(OLD_MAX_LEASES);
         _firstExpiration = Long.MAX_VALUE;
     }
 
@@ -354,14 +368,16 @@ public class LeaseSet extends DatabaseEntry {
      *  Must be called after all the leases are in place, but before sign().
      */
     public void encrypt(SessionKey key) {
-        if (_log.shouldLog(Log.WARN))
-            _log.warn("encrypting lease: " + _destination.calculateHash());
+        //if (_log.shouldLog(Log.WARN))
+        //    _log.warn("encrypting lease: " + _destination.calculateHash());
         try {
             encryp(key);
         } catch (DataFormatException dfe) {
-            _log.error("Error encrypting lease: " + _destination.calculateHash());
+            Log log = I2PAppContext.getGlobalContext().logManager().getLog(LeaseSet.class);
+            log.error("Error encrypting lease: " + _destination.calculateHash());
         } catch (IOException ioe) {
-            _log.error("Error encrypting lease: " + _destination.calculateHash());
+            Log log = I2PAppContext.getGlobalContext().logManager().getLog(LeaseSet.class);
+            log.error("Error encrypting lease: " + _destination.calculateHash());
         }
     }
 
@@ -420,8 +436,8 @@ public class LeaseSet extends DatabaseEntry {
      *  encrypted leaseset can be sent on to others (via writeBytes())
      */
     private void decrypt(SessionKey key) throws DataFormatException, IOException {
-        if (_log.shouldLog(Log.WARN))
-            _log.warn("decrypting lease: " + _destination.calculateHash());
+        //if (_log.shouldLog(Log.WARN))
+        //    _log.warn("decrypting lease: " + _destination.calculateHash());
         int size = _leases.size();
         if (size < 2)
             throw new DataFormatException("Bad number of leases for decryption");
@@ -468,9 +484,11 @@ public class LeaseSet extends DatabaseEntry {
                 decrypt(key);
                 _decrypted = true;
             } catch (DataFormatException dfe) {
-                _log.error("Error decrypting lease: " + _destination.calculateHash() + dfe);
+                Log log = I2PAppContext.getGlobalContext().logManager().getLog(LeaseSet.class);
+                log.error("Error decrypting lease: " + _destination.calculateHash() + dfe);
             } catch (IOException ioe) {
-                _log.error("Error decrypting lease: " + _destination.calculateHash() + ioe);
+                Log log = I2PAppContext.getGlobalContext().logManager().getLog(LeaseSet.class);
+                log.error("Error decrypting lease: " + _destination.calculateHash() + ioe);
             }
         }
         _checked = true;
diff --git a/core/java/src/net/i2p/data/RouterInfo.java b/core/java/src/net/i2p/data/RouterInfo.java
index 6c34ad2023..398b61e0c8 100644
--- a/core/java/src/net/i2p/data/RouterInfo.java
+++ b/core/java/src/net/i2p/data/RouterInfo.java
@@ -13,6 +13,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
@@ -24,6 +25,7 @@ import java.util.Properties;
 import java.util.Set;
 import java.util.Vector;
 
+import net.i2p.I2PAppContext;
 import net.i2p.crypto.SHA256Generator;
 import net.i2p.util.Clock;
 import net.i2p.util.Log;
@@ -43,10 +45,14 @@ import net.i2p.util.OrderedProperties;
  * @author jrandom
  */
 public class RouterInfo extends DatabaseEntry {
-    private final static Log _log = new Log(RouterInfo.class);
     private RouterIdentity _identity;
     private volatile long _published;
-    private final Set<RouterAddress> _addresses;
+    /**
+     *  Addresses must be sorted by SHA256.
+     *  When an RI is created, they are sorted in setAddresses().
+     *  Save addresses in the order received so we need not resort.
+     */
+    private final List<RouterAddress> _addresses;
     /** may be null to save memory, no longer final */
     private Set<Hash> _peers;
     private final Properties _options;
@@ -71,7 +77,7 @@ public class RouterInfo extends DatabaseEntry {
     public static final String BW_CAPABILITY_CHARS = "KLMNO";
     
     public RouterInfo() {
-        _addresses = new HashSet(2);
+        _addresses = new ArrayList(2);
         _options = new OrderedProperties();
     }
 
@@ -156,21 +162,33 @@ public class RouterInfo extends DatabaseEntry {
      *
      * @return unmodifiable view, non-null
      */
-    public Set<RouterAddress> getAddresses() {
-            return Collections.unmodifiableSet(_addresses);
+    public Collection<RouterAddress> getAddresses() {
+            return Collections.unmodifiableCollection(_addresses);
     }
 
     /**
      * Specify a set of RouterAddress structures at which this router
      * can be contacted.
      *
-     * @throws IllegalStateException if RouterInfo is already signed
+     * Warning - Sorts the addresses here. Do not modify any address
+     *           after calling this, as the sort order is based on the
+     *           hash of the entire address structure.
+     *
+     * @param addresses may be null
+     * @throws IllegalStateException if RouterInfo is already signed or addresses previously set
      */
-    public void setAddresses(Set<RouterAddress> addresses) {
-        if (_signature != null)
+    public void setAddresses(Collection<RouterAddress> addresses) {
+        if (_signature != null || !_addresses.isEmpty())
             throw new IllegalStateException();
-        _addresses.clear();
-        if (addresses != null) _addresses.addAll(addresses);
+        if (addresses != null) {
+            _addresses.addAll(addresses);
+            if (_addresses.size() > 1) {
+                // WARNING this sort algorithm cannot be changed, as it must be consistent
+                // network-wide. The signature is not checked at readin time, but only
+                // later, and the addresses are stored in a Set, not a List.
+                DataHelper.sortStructureList(_addresses);
+            }
+        }
     }
 
     /**
@@ -270,14 +288,7 @@ public class RouterInfo extends DatabaseEntry {
                 DataHelper.writeLong(out, 1, 0);
             } else {
                 DataHelper.writeLong(out, 1, sz);
-                Collection<RouterAddress> addresses = _addresses;
-                if (sz > 1) {
-                    // WARNING this sort algorithm cannot be changed, as it must be consistent
-                    // network-wide. The signature is not checked at readin time, but only
-                    // later, and the addresses are stored in a Set, not a List.
-                    addresses = (Collection<RouterAddress>) DataHelper.sortStructures(addresses);
-                }
-                for (RouterAddress addr : addresses) {
+                for (RouterAddress addr : _addresses) {
                     addr.writeBytes(out);
                 }
             }
@@ -458,16 +469,16 @@ public class RouterInfo extends DatabaseEntry {
         _validated = true;
 
         if (!_isValid) {
+            Log log = I2PAppContext.getGlobalContext().logManager().getLog(RouterInfo.class);
             byte data[] = null;
             try {
                 data = getBytes();
             } catch (DataFormatException dfe) {
-                _log.error("Error validating", dfe);
+                log.error("Error validating", dfe);
                 return;
             }
-            if (_log.shouldLog(Log.ERROR))
-                _log.error("Invalid [" + SHA256Generator.getInstance().calculateHash(data).toBase64()
-                           + (_log.shouldLog(Log.WARN) ? ("]\n" + toString()) : ""),
+            log.error("Invalid [" + SHA256Generator.getInstance().calculateHash(data).toBase64()
+                           + (log.shouldLog(Log.WARN) ? ("]\n" + toString()) : ""),
                            new Exception("Signature failed"));
         }
     }
diff --git a/router/java/src/net/i2p/router/Blocklist.java b/router/java/src/net/i2p/router/Blocklist.java
index 153b14e7c9..48ff328a2c 100644
--- a/router/java/src/net/i2p/router/Blocklist.java
+++ b/router/java/src/net/i2p/router/Blocklist.java
@@ -479,15 +479,9 @@ public class Blocklist {
         List<byte[]> rv = new ArrayList(1);
         RouterInfo pinfo = _context.netDb().lookupRouterInfoLocally(peer);
         if (pinfo == null) return rv;
-        Set<RouterAddress> paddr = pinfo.getAddresses();
-        if (paddr == null || paddr.isEmpty())
-            return rv;
         String oldphost = null;
-        List<RouterAddress> pladdr = new ArrayList(paddr);
         // for each peer address
-        for (int j = 0; j < paddr.size(); j++) {
-            RouterAddress pa = (RouterAddress) pladdr.get(j);
-            if (pa == null) continue;
+        for (RouterAddress pa : pinfo.getAddresses()) {
             String phost = pa.getOption("host");
             if (phost == null) continue;
             if (oldphost != null && oldphost.equals(phost)) continue;
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java
index 9fe6e25221..7b567d6126 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java
@@ -216,7 +216,7 @@ public class FloodfillVerifyStoreJob extends JobImpl {
                 if (_log.shouldLog(Log.WARN))
                     _log.warn("Verify failed (older) for " + _key);
                 if (_log.shouldLog(Log.INFO))
-                    _log.info("Rcvd older lease: " + dsm.getEntry());
+                    _log.info("Rcvd older data: " + dsm.getEntry());
             } else if (_message instanceof DatabaseSearchReplyMessage) {
                 // assume 0 old, all new, 0 invalid, 0 dup
                 getContext().profileManager().dbLookupReply(_target,  0,
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java
index 9774f65bd8..21c6a5ccd5 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java
@@ -8,12 +8,13 @@ package net.i2p.router.networkdb.kademlia;
  *
  */
 
+import java.util.Collection;
 import java.util.Date;
-import java.util.Set;
 
 import net.i2p.data.DatabaseEntry;
 import net.i2p.data.Hash;
 import net.i2p.data.LeaseSet;
+import net.i2p.data.RouterAddress;
 import net.i2p.data.RouterIdentity;
 import net.i2p.data.RouterInfo;
 import net.i2p.data.i2np.DatabaseStoreMessage;
@@ -145,9 +146,9 @@ public class HandleFloodfillDatabaseStoreMessageJob extends JobImpl {
                             _log.shouldLog(Log.WARN))
                                 _log.warn("Blocklisting new peer " + key + ' ' + ri);
                     } else {
-                        Set oldAddr = prevNetDb.getAddresses();
-                        Set newAddr = ri.getAddresses();
-                        if (newAddr != null && (!newAddr.equals(oldAddr)) &&
+                        Collection<RouterAddress> oldAddr = prevNetDb.getAddresses();
+                        Collection<RouterAddress> newAddr = ri.getAddresses();
+                        if ((!newAddr.equals(oldAddr)) &&
                             (!getContext().shitlist().isShitlistedForever(key)) &&
                             getContext().blocklist().isBlocklisted(key) &&
                             _log.shouldLog(Log.WARN))
diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
index 8b14d22a0f..d8459166a5 100644
--- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
+++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
@@ -7,6 +7,7 @@ import java.net.UnknownHostException;
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -1258,7 +1259,7 @@ public class ProfileOrganizer {
         RouterInfo pinfo = _context.netDb().lookupRouterInfoLocally(peer);
         if (pinfo == null)
             return rv;
-        Set<RouterAddress> paddr = pinfo.getAddresses();
+        Collection<RouterAddress> paddr = pinfo.getAddresses();
         if (paddr == null)
             return rv;
         for (RouterAddress pa : paddr) {
-- 
GitLab