From ececf5407d0004999a22005d0f85c135a71ea870 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Tue, 3 Feb 2009 15:15:09 +0000
Subject: [PATCH] concurrentify shitlist

---
 .../src/net/i2p/util/ConcurrentHashSet.java   |   7 +
 router/java/src/net/i2p/router/Shitlist.java  | 124 +++++++-----------
 2 files changed, 57 insertions(+), 74 deletions(-)

diff --git a/core/java/src/net/i2p/util/ConcurrentHashSet.java b/core/java/src/net/i2p/util/ConcurrentHashSet.java
index b7bea9ee10..2db9e195ef 100644
--- a/core/java/src/net/i2p/util/ConcurrentHashSet.java
+++ b/core/java/src/net/i2p/util/ConcurrentHashSet.java
@@ -50,4 +50,11 @@ public class ConcurrentHashSet<E> extends AbstractSet<E> implements Set<E> {
     public Iterator<E> iterator() {
         return _map.keySet().iterator();
     }
+
+    public boolean addAll(Collection<? extends E> c) {
+        boolean rv = false;
+        for (E e : c)
+            rv |= _map.put(e, DUMMY) == null;
+        return rv;
+    }
 }
diff --git a/router/java/src/net/i2p/router/Shitlist.java b/router/java/src/net/i2p/router/Shitlist.java
index 2005366c26..4f866c7f71 100644
--- a/router/java/src/net/i2p/router/Shitlist.java
+++ b/router/java/src/net/i2p/router/Shitlist.java
@@ -10,6 +10,7 @@ package net.i2p.router;
 
 import java.io.IOException;
 import java.io.Writer;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -23,6 +24,7 @@ import java.util.TreeMap;
 import net.i2p.data.DataHelper;
 import net.i2p.data.Hash;
 import net.i2p.router.peermanager.PeerProfile;
+import net.i2p.util.ConcurrentHashSet;
 import net.i2p.util.Log;
 
 /**
@@ -34,7 +36,7 @@ import net.i2p.util.Log;
 public class Shitlist {
     private Log _log;
     private RouterContext _context;
-    private Map _entries;
+    private Map<Hash, Entry> _entries;
     
     private static class Entry {
         /** when it should expire, per the i2p clock */
@@ -42,7 +44,7 @@ public class Shitlist {
         /** why they were shitlisted */
         String cause;
         /** what transports they were shitlisted for (String), or null for all transports */
-        Set transports;
+        Set<String> transports;
     }
     
     public final static long SHITLIST_DURATION_MS = 20*60*1000;
@@ -54,49 +56,38 @@ public class Shitlist {
     public Shitlist(RouterContext context) {
         _context = context;
         _log = context.logManager().getLog(Shitlist.class);
-        _entries = new HashMap(32);
+        _entries = new ConcurrentHashMap(8);
         _context.jobQueue().addJob(new Cleanup(_context));
     }
     
     private class Cleanup extends JobImpl {
-        private List _toUnshitlist;
         public Cleanup(RouterContext ctx) {
             super(ctx);
-            _toUnshitlist = new ArrayList(4);
-            getTiming().setStartAfter(_context.clock().now() + SHITLIST_CLEANER_START_DELAY);
+            getTiming().setStartAfter(ctx.clock().now() + SHITLIST_CLEANER_START_DELAY);
         }
         public String getName() { return "Cleanup shitlist"; }
         public void runJob() {
-            _toUnshitlist.clear();
             long now = getContext().clock().now();
-            synchronized (_entries) {
-                for (Iterator iter = _entries.keySet().iterator(); iter.hasNext(); ) {
-                    Hash peer = (Hash)iter.next();
-                    Entry entry = (Entry)_entries.get(peer);
-                    if (entry.expireOn <= now) {
-                        iter.remove();
-                        _toUnshitlist.add(peer);
-                    }
+            for (Iterator iter = _entries.entrySet().iterator(); iter.hasNext(); ) {
+                Map.Entry<Hash, Entry> e = (Map.Entry) iter.next();
+                if (e.getValue().expireOn <= now) {
+                    iter.remove();
+                    Hash peer = e.getKey();
+                    PeerProfile prof = _context.profileOrganizer().getProfile(peer);
+                    if (prof != null)
+                        prof.unshitlist();
+                    _context.messageHistory().unshitlist(peer);
+                    if (_log.shouldLog(Log.INFO))
+                        _log.info("Unshitlisting router (expired) " + peer.toBase64());
                 }
             }
-            for (int i = 0; i < _toUnshitlist.size(); i++) {
-                Hash peer = (Hash)_toUnshitlist.get(i);
-                PeerProfile prof = _context.profileOrganizer().getProfile(peer);
-                if (prof != null)
-                    prof.unshitlist();
-                _context.messageHistory().unshitlist(peer);
-                if (_log.shouldLog(Log.INFO))
-                    _log.info("Unshitlisting router (expired) " + peer.toBase64());
-            }
             
             requeue(30*1000);
         }
     }
     
     public int getRouterCount() {
-        synchronized (_entries) {
-            return _entries.size();
-        }
+        return _entries.size();
     }
     
     public boolean shitlistRouter(Hash peer) {
@@ -143,12 +134,11 @@ public class Shitlist {
         e.cause = reason;
         e.transports = null;
         if (transport != null) {
-            e.transports = new HashSet(1);
+            e.transports = new ConcurrentHashSet(1);
             e.transports.add(transport);
         }
         
-        synchronized (_entries) {
-            Entry old = (Entry)_entries.get(peer);
+            Entry old = _entries.get(peer);
             if (old != null) {
                 wasAlready = true;
                 // take the oldest expiration and cause, combine transports
@@ -166,7 +156,6 @@ public class Shitlist {
                 }
             }
             _entries.put(peer, e);
-        }
         
         if (transport == null) {
             // we hate the peer on *any* transport
@@ -190,20 +179,19 @@ public class Shitlist {
             _log.debug("Calling unshitlistRouter " + peer.toBase64()
                       + (transport != null ? "/" + transport : ""));
         boolean fully = false;
-        Entry e;
-        synchronized (_entries) {
-            e = (Entry)_entries.remove(peer);
-            if ( (e == null) || (e.transports == null) || (transport == null) || (e.transports.size() <= 1) ) {
-                // fully unshitlisted
+
+        Entry e = _entries.remove(peer);
+        if ( (e == null) || (e.transports == null) || (transport == null) || (e.transports.size() <= 1) ) {
+            // fully unshitlisted
+            fully = true;
+        } else {
+            e.transports.remove(transport);
+            if (e.transports.size() <= 0)
                 fully = true;
-            } else {
-                e.transports.remove(transport);
-                if (e.transports.size() <= 0)
-                    fully = true;
-                else
-                    _entries.put(peer, e);
-            }
+            else
+                _entries.put(peer, e);
         }
+
         if (fully) {
             if (realUnshitlist) {
                 PeerProfile prof = _context.profileOrganizer().getProfile(peer);
@@ -221,25 +209,18 @@ public class Shitlist {
     public boolean isShitlisted(Hash peer, String transport) {
         boolean rv = false;
         boolean unshitlist = false;
-        synchronized (_entries) {
-            Entry entry = (Entry)_entries.get(peer);
-            if (entry == null) {
-                rv = false;
-            } else {
-                if (entry.expireOn <= _context.clock().now()) {
-                    _entries.remove(peer);
-                    unshitlist = true;
-                    rv = false;
-                } else {
-                    if (entry.transports == null) {
-                        rv = true;
-                    } else if (entry.transports.contains(transport)) {
-                        rv = true;
-                    } else {
-                        rv = false;
-                    }
-                }
-            }
+
+        Entry entry = _entries.get(peer);
+        if (entry == null) {
+            rv = false;
+        } else if (entry.expireOn <= _context.clock().now()) {
+            _entries.remove(peer);
+            unshitlist = true;
+            rv = false;
+        } else if (entry.transports == null) {
+            rv = true;
+        } else {
+            rv = entry.transports.contains(transport);
         }
         
         if (unshitlist) {
@@ -255,10 +236,7 @@ public class Shitlist {
     }
     
     public boolean isShitlistedForever(Hash peer) {
-        Entry entry;
-        synchronized (_entries) {
-            entry = (Entry)_entries.get(peer);
-        }
+        Entry entry = _entries.get(peer);
         return entry != null && entry.expireOn > _context.clock().now() + SHITLIST_DURATION_MAX;
     }
 
@@ -271,17 +249,15 @@ public class Shitlist {
     public void renderStatusHTML(Writer out) throws IOException {
         StringBuffer buf = new StringBuffer(1024);
         buf.append("<h2>Shitlist</h2>");
-        Map entries = new TreeMap(new HashComparator());
+        Map<Hash, Entry> entries = new TreeMap(new HashComparator());
         
-        synchronized (_entries) {
-            entries.putAll(_entries);
-        }
+        entries.putAll(_entries);
+
         buf.append("<ul>");
         
-        for (Iterator iter = entries.entrySet().iterator(); iter.hasNext(); ) {
-            Map.Entry mentry = (Map.Entry)iter.next();
-            Hash key = (Hash)mentry.getKey();
-            Entry entry = (Entry)mentry.getValue();
+        for (Map.Entry<Hash, Entry> e : entries.entrySet()) {
+            Hash key = e.getKey();
+            Entry entry = e.getValue();
             buf.append("<li><b>").append(key.toBase64()).append("</b>");
             buf.append(" (<a href=\"netdb.jsp?r=").append(key.toBase64().substring(0, 6)).append("\">netdb</a>)");
             buf.append(" expiring in ");
-- 
GitLab