- Type Parameters:
T- type of SimpleDataStructure objects stored in this bucket
- All Implemented Interfaces:
KBucket<T>
ConcurrentHashSet. The max size (K) may be temporarily exceeded due to concurrency, a pending split, or the behavior of the supplied trimmer, as explained below. The creator is responsible for splits.This class has no knowledge of the DHT base used for XORing, and thus there are no validity checks in add/remove.
The begin and end values are immutable. All entries in this bucket will have at least one bit different from us in the range [begin, end] inclusive. Splits must be implemented by creating two new buckets and discarding this one.
The keys are kept in a Set and are NOT sorted by last-seen. Per-key last-seen-time, failures, etc. must be tracked elsewhere.
If this bucket is full (i.e. begin == end && size >= max) then add() will call KBucketTrimmer.trim(KBucket, K) do (possibly) remove older entries, and indicate whether to add the new entry. If the trimmer returns true without removing entries, this KBucket will exceed the max size.
A newcomer rejected by a full bucket is not thrown away but held in a small Kademlia replacement cache and promoted into the bucket when a slot frees up, so live candidates survive transient bucket pressure instead of needing to be re-discovered.
Refactored from net.i2p.router.networkdb.kademlia.
Field Summary
FieldsModifier and TypeFieldDescriptionprivate final intInclude if any bits equal or higher to this bit (in big endian order).private final I2PAppContextSupplies the clock and the random.private final intInclude if no bits higher than this bit (inclusive) are set.The peers in the kbucket, stored in a set.private longWhen did we last shake things up.private final intContacts the bucket holds before splitting.private final intReplacement cache capacity, bounded so 2048 buckets stay cheap.private final LinkedHashSet<T> Kademlia replacement cache — newcomers rejected by a full bucket, insertion-ordered, oldest dropped when over capacity.private final KBucketTrimmer<T> Chooses which contact to drop when the bucket is full.Constructor Summary
ConstructorsConstructorDescriptionKBucketImpl(I2PAppContext context, int begin, int end, int max, KBucketTrimmer<T> trimmer) All entries in this bucket will have at least one bit different from us in the range [begin, end] inclusive.Method Summary
Modifier and TypeMethodDescriptionbooleanUpdates last-changed if rv is true OR if the peer is already present.voidclear()Remove all entries from this bucket.Unmodifiable view of the entries in this bucket.voidgetEntries(SelectionCollector<T> collector) Add all entries in this bucket to the provided collector.intNumber of keys already contained in this kbucket.longThe last-changed timestamp, which actually indicates last-added or last-seen.intLowest order high bit for difference keys.intHighest high bit for the difference keys.(package private) intNumber of held replacement candidates.private voidofferReplacement(T peer) Hold a rejected newcomer as a future slot-filler, dropping the oldest candidate when over capacity.private TTake the newest replacement candidate, or null if the cache is empty.booleanRemove the peer from this bucket.voidUpdate the last-changed timestamp to now.toString()
Field Details
_entries
The peers in the kbucket, stored in a set._begin
private final int _beginInclude if any bits equal or higher to this bit (in big endian order)._end
private final int _endInclude if no bits higher than this bit (inclusive) are set._max
private final int _maxContacts the bucket holds before splitting._trimmer
Chooses which contact to drop when the bucket is full._replacements
Kademlia replacement cache — newcomers rejected by a full bucket, insertion-ordered, oldest dropped when over capacity. Guarded by its own monitor; never exposed outside this class except for the test hook._replacementMax
private final int _replacementMaxReplacement cache capacity, bounded so 2048 buckets stay cheap._lastChanged
private long _lastChangedWhen did we last shake things up._context
Supplies the clock and the random.
Constructor Details
KBucketImpl
All entries in this bucket will have at least one bit different from us in the range [begin, end] inclusive.- Parameters:
context- the router contextbegin- the range beginend- the range endmax- the maximum entries per buckettrimmer- the trim strategy
Method Details
getRangeBegin
public int getRangeBegin()Description copied from interface:KBucketLowest order high bit for difference keys. The lower-bounds distance of this bucket is 2**begin. If begin == 0, this is the closest bucket.- Specified by:
getRangeBeginin interfaceKBucket<T extends SimpleDataStructure>- Returns:
- the beginning of this bucket's range
getRangeEnd
public int getRangeEnd()Description copied from interface:KBucketHighest high bit for the difference keys. The upper-bounds distance of this bucket is (2**(end+1)) - 1. If begin == end, the bucket cannot be split further. If end == (numbits - 1), this is the furthest bucket.- Specified by:
getRangeEndin interfaceKBucket<T extends SimpleDataStructure>- Returns:
- the end of this bucket's range
getKeyCount
public int getKeyCount()Description copied from interface:KBucketNumber of keys already contained in this kbucket.- Specified by:
getKeyCountin interfaceKBucket<T extends SimpleDataStructure>- Returns:
- the number of entries in this bucket
getEntries
Unmodifiable view of the entries in this bucket.- Specified by:
getEntriesin interfaceKBucket<T extends SimpleDataStructure>- Returns:
- an unmodifiable view; not a copy
getEntries
Description copied from interface:KBucketAdd all entries in this bucket to the provided collector.- Specified by:
getEntriesin interfaceKBucket<T extends SimpleDataStructure>- Parameters:
collector- the collector to add entries to
clear
public void clear()Description copied from interface:KBucketRemove all entries from this bucket.- Specified by:
clearin interfaceKBucket<T extends SimpleDataStructure>
add
Updates last-changed if rv is true OR if the peer is already present. Calls the trimmer if begin == end and we are full. If the trimmer rejects the newcomer it is kept in the replacement cache for promotion when a slot frees up. If begin != end then add it and caller must do bucket splitting.- Specified by:
addin interfaceKBucket<T extends SimpleDataStructure>- Parameters:
peer- the key to store; a full bucket may still accept it if the trimmer makes room- Returns:
- true if added
remove
Remove the peer from this bucket. If a slot frees up, the newest replacement candidate (if any) is promoted into the bucket.- Specified by:
removein interfaceKBucket<T extends SimpleDataStructure>- Parameters:
peer- the key to evict from this bucket- Returns:
- if removed. Does NOT set lastChanged.
offerReplacement
Hold a rejected newcomer as a future slot-filler, dropping the oldest candidate when over capacity.- Parameters:
peer- the rejected newcomer to hold for a future free slot
pollReplacement
Take the newest replacement candidate, or null if the cache is empty.- Returns:
- the most recently held candidate, removed from the cache, or null if it was empty
getReplacementCount
int getReplacementCount()Number of held replacement candidates. Package private for testing.- Returns:
- the count of candidates currently in the replacement cache
setLastChanged
public void setLastChanged()Update the last-changed timestamp to now.- Specified by:
setLastChangedin interfaceKBucket<T extends SimpleDataStructure>
getLastChanged
public long getLastChanged()The last-changed timestamp, which actually indicates last-added or last-seen.- Specified by:
getLastChangedin interfaceKBucket<T extends SimpleDataStructure>- Returns:
- the last changed
toString