forked from LBRYCommunity/lbry-sdk
fix improper sorting when getting the closest peers to a hash
This commit is contained in:
parent
396542dc26
commit
b6289d101d
5 changed files with 13 additions and 43 deletions
|
@ -16,6 +16,7 @@ at anytime.
|
||||||
* `blob_list` raising an error when blobs in a stream haven't yet been created
|
* `blob_list` raising an error when blobs in a stream haven't yet been created
|
||||||
* stopping a download from raising `NoneType object has no attribute finished_deferred`
|
* stopping a download from raising `NoneType object has no attribute finished_deferred`
|
||||||
* file manager startup locking up when there are many files for some channels
|
* file manager startup locking up when there are many files for some channels
|
||||||
|
* improper sorting when getting the closest peers to a hash
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
*
|
*
|
||||||
|
|
|
@ -550,7 +550,7 @@ class Node(MockKademliaHelper):
|
||||||
if len(key) != constants.key_bits / 8:
|
if len(key) != constants.key_bits / 8:
|
||||||
raise ValueError("invalid contact id length: %i" % len(key))
|
raise ValueError("invalid contact id length: %i" % len(key))
|
||||||
|
|
||||||
contacts = self._routingTable.findCloseNodes(key, constants.k, rpc_contact.id)
|
contacts = self._routingTable.findCloseNodes(key, sender_node_id=rpc_contact.id)
|
||||||
contact_triples = []
|
contact_triples = []
|
||||||
for contact in contacts:
|
for contact in contacts:
|
||||||
contact_triples.append((contact.id, contact.address, contact.port))
|
contact_triples.append((contact.id, contact.address, contact.port))
|
||||||
|
@ -644,7 +644,7 @@ class Node(MockKademliaHelper):
|
||||||
raise ValueError("invalid key length: %i" % len(key))
|
raise ValueError("invalid key length: %i" % len(key))
|
||||||
|
|
||||||
if startupShortlist is None:
|
if startupShortlist is None:
|
||||||
shortlist = self._routingTable.findCloseNodes(key, constants.k)
|
shortlist = self._routingTable.findCloseNodes(key)
|
||||||
# if key != self.node_id:
|
# if key != self.node_id:
|
||||||
# # Update the "last accessed" timestamp for the appropriate k-bucket
|
# # Update the "last accessed" timestamp for the appropriate k-bucket
|
||||||
# self._routingTable.touchKBucket(key)
|
# self._routingTable.touchKBucket(key)
|
||||||
|
|
|
@ -141,13 +141,13 @@ class TreeRoutingTable(object):
|
||||||
self.touchKBucketByIndex(bucketIndex)
|
self.touchKBucketByIndex(bucketIndex)
|
||||||
return defer.succeed(None)
|
return defer.succeed(None)
|
||||||
|
|
||||||
def findCloseNodes(self, key, count, sender_node_id=None):
|
def findCloseNodes(self, key, count=None, 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.
|
||||||
|
|
||||||
@param key: the n-bit key (i.e. the node or value ID) to search for
|
@param key: the n-bit key (i.e. the node or value ID) to search for
|
||||||
@type key: str
|
@type key: str
|
||||||
@param count: the amount of contacts to return
|
@param count: the amount of contacts to return, default of k (8)
|
||||||
@type count: int
|
@type count: int
|
||||||
@param sender_node_id: 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
|
||||||
|
@ -161,45 +161,14 @@ class TreeRoutingTable(object):
|
||||||
node is returning all of the contacts that it knows of.
|
node is returning all of the contacts that it knows of.
|
||||||
@rtype: list
|
@rtype: list
|
||||||
"""
|
"""
|
||||||
bucketIndex = self._kbucketIndex(key)
|
|
||||||
|
|
||||||
if bucketIndex < len(self._buckets):
|
|
||||||
# sort these
|
|
||||||
closestNodes = self._buckets[bucketIndex].getContacts(count, sender_node_id, sort_distance_to=key)
|
|
||||||
else:
|
|
||||||
closestNodes = []
|
|
||||||
# This method must return k contacts (even if we have the node
|
|
||||||
# with the specified key as node ID), unless there is less
|
|
||||||
# than k remote nodes in the routing table
|
|
||||||
i = 1
|
|
||||||
canGoLower = bucketIndex - i >= 0
|
|
||||||
canGoHigher = bucketIndex + i < len(self._buckets)
|
|
||||||
|
|
||||||
def get_remain(closest):
|
|
||||||
return min(count, constants.k) - len(closest)
|
|
||||||
|
|
||||||
|
count = count or constants.k
|
||||||
|
sender_node_id = sender_node_id or self._parentNodeID
|
||||||
distance = Distance(key)
|
distance = Distance(key)
|
||||||
|
contacts = self.get_contacts()
|
||||||
while len(closestNodes) < min(count, constants.k) and (canGoLower or canGoHigher):
|
contacts = [c for c in contacts if c.id != sender_node_id]
|
||||||
iteration_contacts = []
|
contacts.sort(key=lambda c: distance(c.id))
|
||||||
# get contacts from lower and/or higher buckets without sorting them
|
return contacts[:min(count, len(contacts))]
|
||||||
if canGoLower and len(closestNodes) < min(count, constants.k):
|
|
||||||
lower_bucket = self._buckets[bucketIndex - i]
|
|
||||||
contacts = lower_bucket.getContacts(get_remain(closestNodes), sender_node_id, sort_distance_to=False)
|
|
||||||
iteration_contacts.extend(contacts)
|
|
||||||
canGoLower = bucketIndex - (i + 1) >= 0
|
|
||||||
|
|
||||||
if canGoHigher and len(closestNodes) < min(count, constants.k):
|
|
||||||
higher_bucket = self._buckets[bucketIndex + i]
|
|
||||||
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)
|
|
||||||
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
|
|
||||||
|
|
||||||
def getContact(self, contactID):
|
def getContact(self, contactID):
|
||||||
""" Returns the (known) contact with the specified node ID
|
""" Returns the (known) contact with the specified node ID
|
||||||
|
|
|
@ -99,7 +99,7 @@ class TestStoreExpiration(TestKademliaBase):
|
||||||
self.nodes.remove(announcing_node)
|
self.nodes.remove(announcing_node)
|
||||||
yield self.run_reactor(31, [announcing_node.stop()])
|
yield self.run_reactor(31, [announcing_node.stop()])
|
||||||
# run the network for an hour, which should expire the removed node and turn the announced value stale
|
# run the network for an hour, which should expire the removed node and turn the announced value stale
|
||||||
self.pump_clock(constants.checkRefreshInterval * 4, constants.checkRefreshInterval/2)
|
self.pump_clock(constants.checkRefreshInterval * 5, constants.checkRefreshInterval/2)
|
||||||
self.verify_all_nodes_are_routable()
|
self.verify_all_nodes_are_routable()
|
||||||
|
|
||||||
# make sure the contact isn't returned as a peer for the blob, but that we still have the entry in the
|
# make sure the contact isn't returned as a peer for the blob, but that we still have the entry in the
|
||||||
|
|
|
@ -45,7 +45,7 @@ class TreeRoutingTableTest(unittest.TestCase):
|
||||||
# Now add it...
|
# Now add it...
|
||||||
yield self.routingTable.addContact(contact)
|
yield self.routingTable.addContact(contact)
|
||||||
# ...and request the closest nodes to it (will retrieve it)
|
# ...and request the closest nodes to it (will retrieve it)
|
||||||
closestNodes = self.routingTable.findCloseNodes(contactID, constants.k)
|
closestNodes = self.routingTable.findCloseNodes(contactID)
|
||||||
self.failUnlessEqual(len(closestNodes), 1, 'Wrong amount of contacts returned; expected 1,'
|
self.failUnlessEqual(len(closestNodes), 1, 'Wrong amount of contacts returned; expected 1,'
|
||||||
' got %d' % len(closestNodes))
|
' got %d' % len(closestNodes))
|
||||||
self.failUnless(contact in closestNodes, 'Added contact not found by issueing '
|
self.failUnless(contact in closestNodes, 'Added contact not found by issueing '
|
||||||
|
|
Loading…
Reference in a new issue