improve findCloseNodes, choose closest contacts from higher and lower buckets

This commit is contained in:
Jack Robison 2018-05-23 17:47:20 -04:00
parent c654bfe296
commit 5631a24881
No known key found for this signature in database
GPG key ID: DF25C68FE0239BB2

View file

@ -106,7 +106,7 @@ class TreeRoutingTable(object):
# contact, and append the new one # contact, and append the new one
df.addErrback(replaceContact, head_contact.id) df.addErrback(replaceContact, head_contact.id)
def findCloseNodes(self, key, count, _rpcNodeID=None): def findCloseNodes(self, key, count, sender_node_id=None):
""" Finds a number of known nodes closest to the node/value with the """ Finds a number of known nodes closest to the node/value with the
specified key. specified key.
@ -114,10 +114,10 @@ class TreeRoutingTable(object):
@type key: str @type key: str
@param count: the amount of contacts to return @param count: the amount of contacts to return
@type count: int @type count: int
@param _rpcNodeID: Used during RPC, this is be the sender's Node ID @param sender_node_id: Used during RPC, this is be the sender's Node ID
Whatever ID is passed in the paramater will get Whatever ID is passed in the paramater will get
excluded from the list of returned contacts. excluded from the list of returned contacts.
@type _rpcNodeID: str @type sender_node_id: str
@return: A list of node contacts (C{kademlia.contact.Contact instances}) @return: A list of node contacts (C{kademlia.contact.Contact instances})
closest to the specified key. closest to the specified key.
@ -129,7 +129,8 @@ class TreeRoutingTable(object):
bucketIndex = self._kbucketIndex(key) bucketIndex = self._kbucketIndex(key)
if bucketIndex < len(self._buckets): if bucketIndex < len(self._buckets):
closestNodes = self._buckets[bucketIndex].getContacts(count, _rpcNodeID) # sort these
closestNodes = self._buckets[bucketIndex].getContacts(count, sender_node_id, sort_distance_to=key)
else: else:
closestNodes = [] closestNodes = []
# This method must return k contacts (even if we have the node # This method must return k contacts (even if we have the node
@ -142,21 +143,27 @@ class TreeRoutingTable(object):
def get_remain(closest): def get_remain(closest):
return min(count, constants.k) - len(closest) return min(count, constants.k) - len(closest)
# Fill up the node list to k nodes, starting with the closest neighbouring nodes known distance = Distance(key)
while len(closestNodes) < min(count, constants.k) and (canGoLower or canGoHigher): while len(closestNodes) < min(count, constants.k) and (canGoLower or canGoHigher):
# TODO: this may need to be optimized iteration_contacts = []
# TODO: add "key" kwarg to getContacts() to sort contacts returned by xor distance # get contacts from lower and/or higher buckets without sorting them
# to the key
if canGoLower and len(closestNodes) < min(count, constants.k): if canGoLower and len(closestNodes) < min(count, constants.k):
closestNodes.extend( lower_bucket = self._buckets[bucketIndex - i]
self._buckets[bucketIndex - i].getContacts(get_remain(closestNodes), contacts = lower_bucket.getContacts(get_remain(closestNodes), sender_node_id, sort_distance_to=False)
_rpcNodeID)) iteration_contacts.extend(contacts)
canGoLower = bucketIndex - (i + 1) >= 0 canGoLower = bucketIndex - (i + 1) >= 0
if canGoHigher and len(closestNodes) < min(count, constants.k): if canGoHigher and len(closestNodes) < min(count, constants.k):
closestNodes.extend(self._buckets[bucketIndex + i].getContacts( higher_bucket = self._buckets[bucketIndex + i]
get_remain(closestNodes), _rpcNodeID)) contacts = higher_bucket.getContacts(get_remain(closestNodes), sender_node_id, sort_distance_to=False)
iteration_contacts.extend(contacts)
canGoHigher = bucketIndex + (i + 1) < len(self._buckets) canGoHigher = bucketIndex + (i + 1) < len(self._buckets)
i += 1 i += 1
# sort the combined contacts and add as many as possible/needed to the combined contact list
iteration_contacts.sort(key=lambda c: distance(c.id), reverse=True)
while len(iteration_contacts) and len(closestNodes) < min(count, constants.k):
closestNodes.append(iteration_contacts.pop())
return closestNodes return closestNodes
def getContact(self, contactID): def getContact(self, contactID):