/** @since 0.8.8 */ public void clear() { getReadLock(); try { for (KBucket<T> b : _buckets) { b.clear(); } } finally { releaseReadLock(); } _rangeCalc.clear(); }
public void getAll(SelectionCollector<T> collector) { getReadLock(); try { for (KBucket<T> b : _buckets) { b.getEntries(collector); } } finally { releaseReadLock(); } }
public boolean remove(T entry) { KBucket<T> kbucket; getReadLock(); try { kbucket = getBucket(entry); } finally { releaseReadLock(); } if (kbucket == null) // us return false; boolean removed = kbucket.remove(entry); return removed; }
/** @since 0.9.10 */ public void testAudit() { int errors = 0; for (KBucket<Hash> b : set.getBuckets()) { for (Hash sds : b.getEntries()) { int range = set.getRange(sds); if (range < b.getRangeBegin() || range > b.getRangeEnd()) { log.error("Hash " + sds + " with range " + range + " does not belong in " + b); errors++; } } } assertTrue(errors == 0); }
/** @since 0.9.10 */ public void testGenRandom() { int errors = 0; for (KBucket<Hash> b : set.getBuckets()) { for (int j = 0; j < 4000; j++) { Hash rand = set.generateRandomKey(b); int range = set.getRange(rand); if (range < b.getRangeBegin() || range > b.getRangeEnd()) { log.error("Generate random key failed range=" + range + " for " + rand + " meant for bucket " + b); errors++; } } } assertTrue(errors == 0); }
/** * No lock required. * FIXME will split the closest buckets too far if B > 1 and K < 2**B * Won't ever really happen and if it does it still works. */ private boolean shouldSplit(KBucket<T> b) { return b.getRangeBegin() != b.getRangeEnd() && b.getKeyCount() > BUCKET_SIZE; }
public int compare(KBucket<T> l, KBucket<T> r) { if (l.getRangeEnd() < r.getRangeBegin()) return -1; if (l.getRangeBegin() > r.getRangeEnd()) return 1; return 0; } }
public void testSelf() { // new implementation will never include myself assertFalse(set.add(usHash)); }
/** @since 0.9.10 */ public void testExplore() { List<Hash> keys = set.getExploreKeys(-1000); assertTrue(keys.size() > 0); }
/** * The current number of entries. */ public int size() { int rv = 0; getReadLock(); try { for (KBucket<T> b : _buckets) { rv += b.getKeyCount(); } } finally { releaseReadLock(); } return rv; }
/** * DHT - get random keys to explore */ public List<NID> getExploreKeys() { return _kad.getExploreKeys(MAX_BUCKET_AGE); }
/** * Grabs the write lock. * Caller must NOT have the read lock. * The bucket should be splittable (range start != range end). * @param r the range start of the bucket to be split */ private void split(int r) { if (!getWriteLock()) return; try { locked_split(r); } finally { releaseWriteLock(); } }
public boolean trim(KBucket<T> kbucket, T toAdd) { if (kbucket.getLastChanged() > _ctx.clock().now() - 5*60*1000) return false; return super.trim(kbucket, toAdd); } }
/** * This is fast and doesn't use synchronization, * but it includes both routerinfos and leasesets. * Use it to avoid deadlocks. * No - not true - the KBS contains RIs only. */ protected int getKBucketSetSize() { if (_kb == null) return 0; return _kb.size(); }
/** * Sets last-changed if rv is true OR if the peer is already present. * Calls the trimmer if begin == end and we are full. * If begin != end then add it and caller must do bucket splitting. * @return true if added */ public boolean add(T peer) { if (_begin != _end || _entries.size() < _max || _entries.contains(peer) || _trimmer.trim(this, peer)) { // do this even if already contains, to call setLastChanged() boolean rv = _entries.add(peer); setLastChanged(); return rv; } return false; }
public void getEntries(SelectionCollector<T> collector) { for (T h : _entries) { collector.add(h); } }
/** * Use the default trim strategy, which removes a random entry. * @param us the local identity (typically a SHA1Hash or Hash) * The class must have a zero-argument constructor. * @param max the Kademlia value "k", the max per bucket, k >= 4 * @param b the Kademlia value "b", split buckets an extra 2**(b-1) times, * b > 0, use 1 for bittorrent, Kademlia paper recommends 5 */ public KBucketSet(I2PAppContext context, T us, int max, int b) { this(context, us, max, b, new RandomTrimmer<T>(context, max)); }
/** * The number of bits minus 1 (range number) for the xor of the key. * Package private for testing only. Others shouldn't need this. * @return 0 to max-1 or -1 for us */ int getRange(T key) { return _rangeCalc.getRange(key); }
public void testRandom(){ addRandom(1000); }
/** * @return a copy in a new set */ public Set<T> getAll() { Set<T> all = new HashSet<T>(256); getReadLock(); try { for (KBucket<T> b : _buckets) { all.addAll(b.getEntries()); } } finally { releaseReadLock(); } return all; }