Commit 47a36442 authored by Steven Allen's avatar Steven Allen

fix: when the target bucket is empty or low, pull from all other buckets

The neighbors may _also_ be empty or low. This can cause peers with a low number
of peers in their routing table to fail to find _any_ peers in their routing table.
parent 193d952d
......@@ -8,3 +8,5 @@ require (
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16
github.com/multiformats/go-multihash v0.0.1
)
go 1.13
......@@ -243,27 +243,25 @@ func (rt *RoutingTable) NearestPeers(id ID, count int) []peer.ID {
// It's assumed that this also protects the buckets.
rt.tabLock.RLock()
// Get bucket at cpl index or last bucket
var bucket *Bucket
// Get bucket index or last bucket
if cpl >= len(rt.Buckets) {
cpl = len(rt.Buckets) - 1
}
bucket = rt.Buckets[cpl]
pds := peerDistanceSorter{
peers: make([]peerDistance, 0, 3*rt.bucketsize),
target: id,
}
pds.appendPeersFromList(bucket.list)
if pds.Len() < count {
// In the case of an unusual split, one bucket may be short or empty.
// if this happens, search both surrounding buckets for nearby peers
if cpl > 0 {
pds.appendPeersFromList(rt.Buckets[cpl-1].list)
}
if cpl < len(rt.Buckets)-1 {
pds.appendPeersFromList(rt.Buckets[cpl+1].list)
}
// Add peers from the target bucket and _less_ specific buckets until we
// have enough peers.
for i := cpl; i < len(rt.Buckets) && pds.Len() < count; i++ {
pds.appendPeersFromList(rt.Buckets[i].list)
}
// If we're still short, add more specific buckets (i.e., closer to us).
for i := cpl - 1; i >= 0 && pds.Len() < count; i-- {
pds.appendPeersFromList(rt.Buckets[i].list)
}
rt.tabLock.RUnlock()
......
......@@ -229,6 +229,26 @@ func TestTableFindMultiple(t *testing.T) {
}
}
func TestTableFindMultipleBuckets(t *testing.T) {
local := test.RandPeerIDFatal(t)
m := pstore.NewMetrics()
rt := NewRoutingTable(5, ConvertPeerID(local), time.Hour, m)
peers := make([]peer.ID, 100)
for i := 0; i < 100; i++ {
peers[i] = test.RandPeerIDFatal(t)
rt.Update(peers[i])
}
t.Logf("Searching for peer: '%s'", peers[2])
// should be able to find at least 30
// ~31 (logtwo(100) * 5)
found := rt.NearestPeers(ConvertPeerID(peers[2]), 20)
if len(found) != 20 {
t.Fatalf("asked for 15 peers, got %d", len(found))
}
}
// Looks for race conditions in table operations. For a more 'certain'
// test, increase the loop counter from 1000 to a much higher number
// and set GOMAXPROCS above 1
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment