From 395173613ff3fa8938970f2d71319061b3f2cfff Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 21 Jul 2011 15:34:23 +0000 Subject: [PATCH] * Console: Use capability method for counting integrated peers * Netdb: Speed up collection of all the floodfill peers by using PeerManager.getPeersByCapability() * PeerManager: Capability cleanups --- .../router/web/ProfileOrganizerRenderer.java | 3 +- .../src/net/i2p/router/web/SummaryHelper.java | 4 +- core/java/src/net/i2p/data/RouterInfo.java | 2 +- history.txt | 12 ++ .../i2p/router/DummyPeerManagerFacade.java | 3 +- .../src/net/i2p/router/PeerManagerFacade.java | 3 +- router/java/src/net/i2p/router/Router.java | 2 +- .../src/net/i2p/router/RouterVersion.java | 2 +- .../FloodfillNetworkDatabaseFacade.java | 7 +- .../kademlia/FloodfillPeerSelector.java | 22 +++- .../i2p/router/peermanager/PeerManager.java | 111 +++++++----------- .../peermanager/PeerManagerFacadeImpl.java | 16 ++- .../router/peermanager/ProfileOrganizer.java | 5 +- .../tunnel/pool/TunnelPeerSelector.java | 5 +- 14 files changed, 104 insertions(+), 93 deletions(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java index d83720d07..f68a53a36 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java @@ -183,7 +183,8 @@ class ProfileOrganizerRenderer { } buf.append(""); - buf.append("

").append(_("Floodfill and Integrated Peers")).append("

\n"); + buf.append("

").append(_("Floodfill and Integrated Peers")) + .append(" (").append(integratedPeers.size()).append(")

\n"); buf.append(""); buf.append(""); buf.append(""); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java index 35f86d8fd..233f4167b 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -221,8 +221,8 @@ public class SummaryHelper extends HelperBase { public int getWellIntegratedPeers() { if (_context == null) return 0; - else - return _context.profileOrganizer().countWellIntegratedPeers(); + //return _context.profileOrganizer().countWellIntegratedPeers(); + return _context.peerManager().getPeersByCapability(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL).size(); } /** * How many peers the router ranks as failing. diff --git a/core/java/src/net/i2p/data/RouterInfo.java b/core/java/src/net/i2p/data/RouterInfo.java index 8df525f6f..80fbd0b60 100644 --- a/core/java/src/net/i2p/data/RouterInfo.java +++ b/core/java/src/net/i2p/data/RouterInfo.java @@ -317,7 +317,7 @@ public class RouterInfo extends DatabaseEntry { /** * what special capabilities this router offers - * + * @return non-null, empty string if none */ public String getCapabilities() { if (_options == null) return ""; diff --git a/history.txt b/history.txt index 30a9410c7..e41b2b112 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,15 @@ +2011-07-21 zzz + * Atalk: Remove this terrible example + * Console: Use capability method for counting integrated peers + * i2psnark: Don't let connection problem crash the DirMonitor (ticket #495) + * Netdb: Speed up collection of all the floodfill peers by using + PeerManager.getPeersByCapability() + * PeerManager: Capability cleanups + * Tunnel TestJob: + - Don't continue testing after the pool is dead + - Tweak test intervals + * TunnelPool: Make more methods package private + 2011-07-18 zzz * FileUtil: Add a rename method and a new copy method * I2PTunnel: Rename privkey file when deleting tunnel to prevent inadvertent reuse diff --git a/router/java/src/net/i2p/router/DummyPeerManagerFacade.java b/router/java/src/net/i2p/router/DummyPeerManagerFacade.java index 6c76c0738..92f7d006a 100644 --- a/router/java/src/net/i2p/router/DummyPeerManagerFacade.java +++ b/router/java/src/net/i2p/router/DummyPeerManagerFacade.java @@ -10,6 +10,7 @@ package net.i2p.router; import java.io.Writer; import java.util.List; +import java.util.Set; import net.i2p.data.Hash; @@ -25,7 +26,7 @@ class DummyPeerManagerFacade implements PeerManagerFacade { public void restart() {} public void renderStatusHTML(Writer out) { } public List selectPeers(PeerSelectionCriteria criteria) { return null; } - public List getPeersByCapability(char capability) { return null; } + public Set getPeersByCapability(char capability) { return null; } public void setCapabilities(Hash peer, String caps) {} public void removeCapabilities(Hash peer) {} public Hash selectRandomByCapability(char capability) { return null; } diff --git a/router/java/src/net/i2p/router/PeerManagerFacade.java b/router/java/src/net/i2p/router/PeerManagerFacade.java index f8f3cbf1e..be86fca1b 100644 --- a/router/java/src/net/i2p/router/PeerManagerFacade.java +++ b/router/java/src/net/i2p/router/PeerManagerFacade.java @@ -9,6 +9,7 @@ package net.i2p.router; */ import java.util.List; +import java.util.Set; import net.i2p.data.Hash; @@ -26,7 +27,7 @@ public interface PeerManagerFacade extends Service { * @return List of Hash objects of the RouterIdentity for matching peers */ public List selectPeers(PeerSelectionCriteria criteria); - public List getPeersByCapability(char capability); + public Set getPeersByCapability(char capability); public void setCapabilities(Hash peer, String caps); public void removeCapabilities(Hash peer); public Hash selectRandomByCapability(char capability); diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index e51323425..dc673f741 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -551,7 +551,7 @@ public class Router implements RouterClock.ClockShiftListener { // if prop set to true, don't tell people we are ff even if we are if (FloodfillNetworkDatabaseFacade.floodfillEnabled(_context) && !Boolean.valueOf(_context.getProperty("router.hideFloodfillParticipant")).booleanValue()) - ri.addCapability(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL); + ri.addCapability(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL); if(Boolean.valueOf(_context.getProperty(PROP_HIDDEN)).booleanValue()) ri.addCapability(RouterInfo.CAPABILITY_HIDDEN); diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index e36cd3b14..7f4edb975 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 12; + public final static long BUILD = 13; /** for example "-test" */ public final static String EXTRA = ""; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java index 6e5ed2070..ca1259ccb 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java @@ -32,7 +32,7 @@ import net.i2p.util.Log; * */ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacade { - public static final char CAPACITY_FLOODFILL = 'f'; + public static final char CAPABILITY_FLOODFILL = 'f'; private final Map _activeFloodQueries; private boolean _floodfillEnabled; /** for testing, see isFloodfill() below */ @@ -223,10 +223,7 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad } catch (DataFormatException dfe) {} } String caps = peer.getCapabilities(); - if ( (caps != null) && (caps.indexOf(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL) != -1) ) - return true; - else - return false; + return caps.indexOf(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL) >= 0; } public List getKnownRouterData() { diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java index 3606240d2..1b0fa1478 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java @@ -107,12 +107,23 @@ class FloodfillPeerSelector extends PeerSelector { * List is not sorted and not shuffled. */ private List selectFloodfillParticipants(Set toIgnore, KBucketSet kbuckets) { + /***** if (kbuckets == null) return Collections.EMPTY_LIST; // TODO this is very slow - use profile getPeersByCapability('f') instead _context.statManager().addRateData("netDb.newFSC", 0, 0); FloodfillSelectionCollector matches = new FloodfillSelectionCollector(null, toIgnore, 0); kbuckets.getAll(matches); return matches.getFloodfillParticipants(); + *****/ + Set set = _context.peerManager().getPeersByCapability(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL); + List rv = new ArrayList(set.size()); + for (Hash h : set) { + if ((toIgnore != null && toIgnore.contains(h)) || + _context.shitlist().isShitlistedForever(h)) + continue; + rv.add(h); + } + return rv; } /** @@ -251,12 +262,12 @@ class FloodfillPeerSelector extends PeerSelector { } private class FloodfillSelectionCollector implements SelectionCollector { - private TreeSet _sorted; - private List _floodfillMatches; - private Hash _key; - private Set _toIgnore; + private final TreeSet _sorted; + private final List _floodfillMatches; + private final Hash _key; + private final Set _toIgnore; private int _matches; - private int _wanted; + private final int _wanted; /** * Warning - may return our router hash - add to toIgnore if necessary @@ -267,7 +278,6 @@ class FloodfillPeerSelector extends PeerSelector { _sorted = new TreeSet(new XORComparator(key)); _floodfillMatches = new ArrayList(8); _toIgnore = toIgnore; - _matches = 0; _wanted = wanted; } diff --git a/router/java/src/net/i2p/router/peermanager/PeerManager.java b/router/java/src/net/i2p/router/peermanager/PeerManager.java index ab099c129..329c36d93 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerManager.java +++ b/router/java/src/net/i2p/router/peermanager/PeerManager.java @@ -11,8 +11,9 @@ package net.i2p.router.peermanager; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -21,6 +22,7 @@ import java.util.concurrent.ConcurrentHashMap; import net.i2p.data.Hash; import net.i2p.data.RouterInfo; import net.i2p.router.PeerSelectionCriteria; +import net.i2p.router.Router; import net.i2p.router.RouterContext; import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.util.ConcurrentHashSet; @@ -30,15 +32,7 @@ import net.i2p.util.SimpleTimer2; /** * Manage the current state of the statistics * - * All the capabilities methods appear to be almost unused - - * TunnelPeerSelector just looks for unreachables, and that's it? - * If so, a lot of this can go away, including the array of 26 ArrayLists, - * and a lot of synchronization on _capabilitiesByPeer. - * - * We don't trust any published capabilities except for 'K' and 'U'. - * This should be cleaned up. - * - * setCapabilities() and removeCapabilities() can just add/remove the profile and that's it. + * Also maintain Sets for each of the capabilities in TRACKED_CAPS. * */ class PeerManager { @@ -46,12 +40,24 @@ class PeerManager { private final RouterContext _context; private final ProfileOrganizer _organizer; private final ProfilePersistenceHelper _persistenceHelper; - private final Set _peersByCapability[]; + private final Map> _peersByCapability; + /** value strings are lower case */ private final Map _capabilitiesByPeer; private static final long REORGANIZE_TIME = 45*1000; private static final long REORGANIZE_TIME_MEDIUM = 123*1000; private static final long REORGANIZE_TIME_LONG = 551*1000; + public static final String TRACKED_CAPS = "" + + FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL + + RouterInfo.CAPABILITY_HIDDEN + + Router.CAPABILITY_BW12 + + Router.CAPABILITY_BW32 + + Router.CAPABILITY_BW64 + + Router.CAPABILITY_BW128 + + Router.CAPABILITY_BW256 + + Router.CAPABILITY_REACHABLE + + Router.CAPABILITY_UNREACHABLE; + /** * Profiles are now loaded in a separate thread, * so this should return quickly. @@ -63,9 +69,9 @@ class PeerManager { _organizer = context.profileOrganizer(); _organizer.setUs(context.routerHash()); _capabilitiesByPeer = new ConcurrentHashMap(128); - _peersByCapability = new Set[26]; - for (int i = 0; i < _peersByCapability.length; i++) - _peersByCapability[i] = new ConcurrentHashSet(); + _peersByCapability = new HashMap(TRACKED_CAPS.length()); + for (int i = 0; i < TRACKED_CAPS.length(); i++) + _peersByCapability.put(Character.valueOf(Character.toLowerCase(TRACKED_CAPS.charAt(i))), new ConcurrentHashSet()); loadProfilesInBackground(); ////_context.jobQueue().addJob(new EvaluateProfilesJob(_context)); //SimpleScheduler.getInstance().addPeriodicEvent(new Reorg(), 0, REORGANIZE_TIME); @@ -96,9 +102,8 @@ class PeerManager { } void storeProfiles() { - Set peers = selectPeers(); - for (Iterator iter = peers.iterator(); iter.hasNext(); ) { - Hash peer = iter.next(); + Set peers = selectPeers(); + for (Hash peer : peers) { storeProfile(peer); } } @@ -107,11 +112,11 @@ class PeerManager { void clearProfiles() { _organizer.clearProfiles(); _capabilitiesByPeer.clear(); - for (int i = 0; i < _peersByCapability.length; i++) - _peersByCapability[i].clear(); + for (Set p : _peersByCapability.values()) + p.clear(); } - Set selectPeers() { + Set selectPeers() { return _organizer.selectAllPeers(); } @@ -152,13 +157,10 @@ class PeerManager { */ void loadProfiles() { Set profiles = _persistenceHelper.readProfiles(); - for (Iterator iter = profiles.iterator(); iter.hasNext();) { - PeerProfile prof = iter.next(); - if (prof != null) { + for (PeerProfile prof : profiles) { _organizer.addProfile(prof); if (_log.shouldLog(Log.DEBUG)) _log.debug("Profile for " + prof.getPeer().toBase64() + " loaded"); - } } } @@ -207,37 +209,37 @@ class PeerManager { if (_log.shouldLog(Log.WARN)) _log.warn("We ran out of peers when looking for reachable ones after finding " + "0 with " - + _organizer.countWellIntegratedPeers() + "/" + _organizer.countHighCapacityPeers() + "/" - + _organizer.countFastPeers() + " integrated/high capacity/fast peers"); + + _organizer.countFastPeers() + " high capacity/fast peers"); } if (_log.shouldLog(Log.INFO)) _log.info("Peers selected: " + peers); return new ArrayList(peers); } + /** + * @param caps non-null, case is ignored + */ public void setCapabilities(Hash peer, String caps) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Setting capabilities for " + peer.toBase64() + " to " + caps); - if (caps != null) caps = caps.toLowerCase(); + caps = caps.toLowerCase(); - String oldCaps = null; - if (caps != null) - oldCaps = _capabilitiesByPeer.put(peer, caps); - else - oldCaps = _capabilitiesByPeer.remove(peer); + String oldCaps = _capabilitiesByPeer.put(peer, caps); + if (caps.equals(oldCaps)) + return; if (oldCaps != null) { for (int i = 0; i < oldCaps.length(); i++) { char c = oldCaps.charAt(i); - if ( (caps == null) || (caps.indexOf(c) < 0) ) { + if (caps.indexOf(c) < 0) { Set peers = locked_getPeers(c); if (peers != null) peers.remove(peer); } } } - if (caps != null) { + for (int i = 0; i < caps.length(); i++) { char c = caps.charAt(i); if ( (oldCaps != null) && (oldCaps.indexOf(c) >= 0) ) @@ -246,26 +248,19 @@ class PeerManager { if (peers != null) peers.add(peer); } - } } /** locking no longer req'd */ private Set locked_getPeers(char c) { c = Character.toLowerCase(c); - int i = c - 'a'; - if ( (i < 0) || (i >= _peersByCapability.length) ) { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Invalid capability " + c + " (" + i + ")"); - return null; - } - return _peersByCapability[i]; + return _peersByCapability.get(Character.valueOf(c)); } public void removeCapabilities(Hash peer) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Removing capabilities from " + peer.toBase64()); - String oldCaps = (String)_capabilitiesByPeer.remove(peer); + String oldCaps = _capabilitiesByPeer.remove(peer); if (oldCaps != null) { for (int i = 0; i < oldCaps.length(); i++) { char c = oldCaps.charAt(i); @@ -291,33 +286,13 @@ class PeerManager { ********/ /** - * The only user of this is TunnelPeerSelector for unreachables? + * @param capability case-insensitive + * @return non-null unmodifiable set */ - public List getPeersByCapability(char capability) { - if (true) { + public Set getPeersByCapability(char capability) { Set peers = locked_getPeers(capability); if (peers != null) - return new ArrayList(peers); - return null; - } else { - // Wow this looks really slow... - // What is the point of keeping all the data structures above - // if we are going to go through the whole netdb anyway? - // Not sure why jrandom switched to do it this way, - // the checkin comments aren't clear... - // Since the locking is gone, switch back to the above. - FloodfillNetworkDatabaseFacade f = (FloodfillNetworkDatabaseFacade)_context.netDb(); - List routerInfos = f.getKnownRouterData(); - List rv = new ArrayList(); - for (Iterator iter = routerInfos.iterator(); iter.hasNext(); ) { - RouterInfo ri = iter.next(); - String caps = ri.getCapabilities(); - if (caps.indexOf(capability) >= 0) - rv.add(ri.getIdentity().calculateHash()); - } - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Peers with capacity " + capability + ": " + rv.size()); - return rv; - } + return Collections.unmodifiableSet(peers); + return Collections.EMPTY_SET; } } diff --git a/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java b/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java index 840b993be..b84966143 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java +++ b/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java @@ -10,8 +10,10 @@ package net.i2p.router.peermanager; import java.io.IOException; import java.io.Writer; -import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; import java.util.List; +import java.util.Set; import net.i2p.data.Hash; import net.i2p.router.PeerManagerFacade; @@ -63,10 +65,14 @@ public class PeerManagerFacadeImpl implements PeerManagerFacade { return _manager.selectPeers(criteria); } + /** + * @param caps non-null + */ public void setCapabilities(Hash peer, String caps) { if (_manager == null) return; _manager.setCapabilities(peer, caps); } + public void removeCapabilities(Hash peer) { if (_manager == null) return; _manager.removeCapabilities(peer); @@ -79,8 +85,12 @@ public class PeerManagerFacadeImpl implements PeerManagerFacade { return null; } - public List getPeersByCapability(char capability) { - if (_manager == null) return new ArrayList(0); + /** + * @param capability case-insensitive + * @return non-null unmodifiable set + */ + public Set getPeersByCapability(char capability) { + if (_manager == null) return Collections.EMPTY_SET; return _manager.getPeersByCapability(capability); } diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java index fdc8881c1..ee8832923 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java +++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java @@ -46,7 +46,7 @@ public class ProfileOrganizer { private final Map _fastPeers; /** H(routerIdentity) to PeerProfile for all peers that have high capacities */ private final Map _highCapacityPeers; - /** H(routerIdentity) to PeerProfile for all peers that well integrated into the network and not failing horribly */ + /** TO BE REMOVED H(routerIdentity) to PeerProfile for all peers that well integrated into the network and not failing horribly */ private final Map _wellIntegratedPeers; /** H(routerIdentity) to PeerProfile for all peers that are not failing horribly */ private final Map _notFailingPeers; @@ -187,6 +187,7 @@ public class ProfileOrganizer { public int countFastPeers() { return count(_fastPeers); } public int countHighCapacityPeers() { return count(_highCapacityPeers); } + /** @deprecated use ProfileManager.getPeersByCapability('f').size() */ public int countWellIntegratedPeers() { return count(_wellIntegratedPeers); } public int countNotFailingPeers() { return count(_notFailingPeers); } public int countFailingPeers() { return count(_failingPeers); } @@ -408,6 +409,7 @@ public class ProfileOrganizer { /** * Return a set of Hashes for peers that are well integrated into the network. * + * @deprecated unused */ public void selectWellIntegratedPeers(int howMany, Set exclude, Set matches) { selectWellIntegratedPeers(howMany, exclude, matches, 0); @@ -418,6 +420,7 @@ public class ProfileOrganizer { * * @param mask 0-4 Number of bytes to match to determine if peers in the same IP range should * not be in the same tunnel. 0 = disable check; 1 = /8; 2 = /16; 3 = /24; 4 = exact IP match + * @deprecated unused */ public void selectWellIntegratedPeers(int howMany, Set exclude, Set matches, int mask) { getReadLock(); diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java index 25b6ed933..b9a143a88 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java @@ -2,6 +2,7 @@ package net.i2p.router.tunnel.pool; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; @@ -198,7 +199,7 @@ public abstract class TunnelPeerSelector { if (filterUnreachable(ctx, isInbound, isExploratory)) { // NOTE: filterUnreachable returns true for inbound, false for outbound // This is the only use for getPeersByCapability? And the whole set of datastructures in PeerManager? - List caps = ctx.peerManager().getPeersByCapability(Router.CAPABILITY_UNREACHABLE); + Collection caps = ctx.peerManager().getPeersByCapability(Router.CAPABILITY_UNREACHABLE); if (caps != null) peers.addAll(caps); caps = ctx.profileOrganizer().selectPeersLocallyUnreachable(); @@ -352,7 +353,7 @@ public abstract class TunnelPeerSelector { } } int maxLen = 0; - if (cap.indexOf(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL) >= 0) + if (cap.indexOf(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL) >= 0) maxLen++; if (cap.indexOf(Router.CAPABILITY_REACHABLE) >= 0) maxLen++;
").append(_("Peer")).append("