I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit ececf540 authored by zzz's avatar zzz
Browse files

concurrentify shitlist

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