package lbms.plugins.mldht.kad; import java.net.InetSocketAddress; import java.util.Collection; import java.util.Collections; import java.util.SortedMap; import java.util.TreeMap; import lbms.plugins.mldht.kad.DHT.DHTtype; /** * @author Damokles * */ public class KClosestNodesSearch { private Key targetKey; private SortedMap<Key, KBucketEntry> entries = new TreeMap<Key, KBucketEntry>(); private int max_entries; private DHT owner; /** * Constructor sets the key to compare with * @param key The key to compare with * @param max_entries The maximum number of entries can be in the map * @return */ public KClosestNodesSearch (Key key, int max_entries, DHT owner) { this.targetKey = key; this.owner = owner; this.max_entries = max_entries; } /** * @return the Target key of the search */ public Key getSearchTarget () { return targetKey; } /** * @return the number of entries */ public int getNumEntries () { return entries.size(); } /** * Try to insert an entry. * @param e The entry * @return true if insert was successful */ public boolean tryInsert (KBucketEntry e) { // calculate distance between key and e Key dist = targetKey.distance(e.getID()); if (entries.size() < max_entries) { // room in the map so just insert entries.put(dist, e); return true; } // now find the max distance // seeing that the last element of the map has also // the biggest distance to key (std::map is sorted on the distance) // we just take the last Key max = entries.lastKey(); if (dist.compareTo(max) == -1) { // insert if d is smaller then max entries.put(dist, e); // erase the old max value entries.remove(max); return true; } return false; } public void fill() { fill(false); } public void fill(boolean includeOurself) { owner.getNode().findKClosestNodes(this); if(includeOurself && owner.getServer().getPublicAddress() != null && entries.size() < max_entries) { InetSocketAddress sockAddr = new InetSocketAddress(owner.getServer().getPublicAddress(), owner.getServer().getPort()); entries.put(targetKey.distance(owner.getOurID()), new KBucketEntry(sockAddr, owner.getOurID())); } } public boolean isFull () { return entries.size() >= max_entries; } /** * Packs the results in a byte array. * * @return the encoded results. */ public byte[] pack () { if(entries.size() == 0) return null; int entryLength = owner.getType().NODES_ENTRY_LENGTH; byte[] buffer = new byte[entries.size() * entryLength]; int max_items = buffer.length / 26; int j = 0; for (KBucketEntry e : entries.values()) { if (j >= max_items) { break; } PackUtil.PackBucketEntry(e, buffer, j * entryLength, owner.getType()); j++; } return buffer; } /** * @return a unmodifiable Collection of the entries */ public Collection<KBucketEntry> getEntries () { return Collections.unmodifiableCollection(entries.values()); } }