nodes.sort(lambda a, b, num=num: cmp(num ^ a.num, num ^ b.num))
return nodes[:K]
+ def touch(self, id):
+ """Mark a bucket as having been looked up.
+
+ @type id: C{string} or C{int} or L{node.Node}
+ @param id: the ID in the bucket that was accessed
+ """
+ # Get the bucket number from the input
+ num = self._nodeNum(id)
+ i = self._bucketIndexForInt(num)
+
+ self.buckets[i].touch()
+
def _mergeBucket(self, i):
"""Merge unneeded buckets after removing a node.
# note that we removed the original and replaced it with the new one
# utilizing this nodes new contact info
self.buckets[i].add(node)
- self.buckets[i].touch()
return True
# We don't have this node, check to see if the bucket is full
if contacted:
node.updateLastSeen()
self.buckets[i].add(node)
- self.buckets[i].touch()
log.msg('Added node to routing table: %s/%s' % (node.host, node.port))
return True
return False
except ValueError:
return None
else:
- self.buckets[i].touch()
return tstamp
def invalidateNode(self, n):
self.replaceStaleNode(n)
def nodeFailed(self, node):
- """Mark a node as having failed once, and remove it if it has failed too much."""
+ """Mark a node as having failed once, and remove it if it has failed too much.
+
+ @return: whether the node is in the routing table
+ """
# Get the bucket number
num = self._nodeNum(node)
i = self._bucketIndexForInt(num)
try:
n = self.buckets[i].node(num)
except ValueError:
- return None
+ return False
else:
# The node is in the bucket
if n.msgFailed() >= self.config['MAX_FAILURES']:
self.invalidateNode(n)
+ return False
+ return True
class KBucket:
"""Single bucket of nodes in a kademlia-like routing table.