Fix depth calculation for bucket splitting

This commit is contained in:
kdeme 2020-06-22 16:46:58 +02:00
parent 2d7b3440f2
commit ceb4a20463
2 changed files with 26 additions and 17 deletions

View File

@ -153,7 +153,7 @@ proc binaryGetBucketForNode(buckets: openarray[KBucket],
if result.isNil: if result.isNil:
raise (ref Defect)(msg: "No bucket found for node with id " & $id) raise (ref Defect)(msg: "No bucket found for node with id " & $id)
proc computeSharedPrefixBits(nodes: openarray[Node]): int = proc computeSharedPrefixBits(nodes: openarray[NodeId]): int =
## Count the number of prefix bits shared by all nodes. ## Count the number of prefix bits shared by all nodes.
if nodes.len < 2: if nodes.len < 2:
return ID_SIZE return ID_SIZE
@ -163,13 +163,14 @@ proc computeSharedPrefixBits(nodes: openarray[Node]): int =
for i in 1 .. ID_SIZE: for i in 1 .. ID_SIZE:
mask = mask or (one shl (ID_SIZE - i)) mask = mask or (one shl (ID_SIZE - i))
let reference = nodes[0].id and mask let reference = nodes[0] and mask
for j in 1 .. nodes.high: for j in 1 .. nodes.high:
if (nodes[j].id and mask) != reference: return i - 1 if (nodes[j] and mask) != reference: return i - 1
for n in nodes: for n in nodes:
echo n.id.toHex() echo n.toHex()
# Reaching this would mean that all node ids are equal
doAssert(false, "Unable to calculate number of shared prefix bits") doAssert(false, "Unable to calculate number of shared prefix bits")
proc init*(r: var RoutingTable, thisNode: Node, bitsPerHop = 8) {.inline.} = proc init*(r: var RoutingTable, thisNode: Node, bitsPerHop = 8) {.inline.} =
@ -199,8 +200,10 @@ proc addNode*(r: var RoutingTable, n: Node): Node =
if not evictionCandidate.isNil: if not evictionCandidate.isNil:
# Split if the bucket has the local node in its range or if the depth is not # Split if the bucket has the local node in its range or if the depth is not
# congruent to 0 mod `bitsPerHop` # congruent to 0 mod `bitsPerHop`
#
let depth = computeSharedPrefixBits(bucket.nodes) # Calculate the prefix shared by all nodes in the bucket's range, not the
# ones actually in the bucket.
let depth = computeSharedPrefixBits(@[bucket.istart, bucket.iend])
# TODO: Shouldn't the adding to replacement cache be done only if the bucket # TODO: Shouldn't the adding to replacement cache be done only if the bucket
# doesn't get split? # doesn't get split?
if bucket.inRange(r.thisNode) or if bucket.inRange(r.thisNode) or

View File

@ -40,22 +40,28 @@ suite "Routing Table Tests":
let node = generateNode() let node = generateNode()
var table: RoutingTable var table: RoutingTable
# bitsPerHop = 2, allow not in range branch to split once. # bitsPerHop = 2, allow not in range branch to split once (2 buckets).
table.init(node, 2) table.init(node, 2)
# Add 16 nodes, distance 256 # Add 16 nodes, distance 256 from `node`, but all with 2 bits shared prefix
for i in 0..<BUCKET_SIZE: # among themselves.
check table.addNode(node.nodeAtDistance(256)) == nil let firstNode = node.nodeAtDistance(256)
check table.addNode(firstNode) == nil
for n in 1..<BUCKET_SIZE:
check table.addNode(firstNode.nodeAtDistance(254)) == nil
# Add another 32 nodes, to make the not in range branch split and be be sure # Add 16 more nodes with only 1 bit shared prefix with previous 16. This
# both buckets are full. # should cause the initial bucket to split and and fill the second bucket
# TODO: Could improve by adding specific nodes for one of the buckets. # with the 16 new entries.
for i in 0..<BUCKET_SIZE*2: for n in 0..<16:
discard table.addNode(node.nodeAtDistance(256)) check table.addNode(firstNode.nodeAtDistance(255)) == nil
# Adding another should fail as both buckets should be full and not be # Adding another should fail as both buckets will be full and not be
# allowed to split another time # allowed to split another time.
check table.addNode(node.nodeAtDistance(256)) != nil check table.addNode(node.nodeAtDistance(256)) != nil
# And also when targetting one of the two specific buckets.
check table.addNode(firstNode.nodeAtDistance(255)) != nil
check table.addNode(firstNode.nodeAtDistance(254)) != nil
# This add should be allowed as it is on the branch where the own node's id # This add should be allowed as it is on the branch where the own node's id
# id belongs to. # id belongs to.
check table.addNode(node.nodeAtDistance(255)) == nil check table.addNode(node.nodeAtDistance(255)) == nil