swarm/network: kademlia suggestPeer cleanup, improved comments

This commit is contained in:
zelig 2019-01-15 08:18:59 +01:00
parent 4ceac79069
commit 94cd49d17d

View file

@ -173,30 +173,30 @@ func (k *Kademlia) SuggestPeer() (suggestedPeer *BzzAddr, saturationDepth int, c
k.lock.Lock() k.lock.Lock()
defer k.lock.Unlock() defer k.lock.Unlock()
radius := neighbourhoodRadiusForPot(k.conns, k.NeighbourhoodSize, k.base) radius := neighbourhoodRadiusForPot(k.conns, k.NeighbourhoodSize, k.base)
// find the undersaturated bins from lowest cardinality from shallow to deep // first collect undersaturated bins starting from smallest size from shallow to deep
// first map unsaturated bins to cardinalities // saturation is a map: bin size (int) -> deepening list of PO bins with that size ([]int)
spo := make(map[int][]int) saturation := make(map[int][]int)
var prev int var lastPO int // the last non-empty PO bin in the iteration
saturationDepth = -1 saturationDepth = -1 // the deepest PO such that all shallower bins have >= k.MinBinSize peers
var pastDepth bool var pastDepth bool // whether po of iteration >= depth
k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool { k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val) bool) bool) bool {
// process skipped empty bins // process skipped empty bins
for ; prev < po; prev++ { for ; lastPO < po; lastPO++ {
// find the lowest unsaturated bin // find the lowest unsaturated bin
if saturationDepth == -1 { if saturationDepth == -1 {
saturationDepth = prev saturationDepth = lastPO
} }
// if there is an empty bin, depth is surely passed // if there is an empty bin, depth is surely passed
pastDepth = true pastDepth = true
spo[0] = append(spo[0], prev) saturation[0] = append(saturation[0], lastPO)
} }
prev = po + 1 lastPO = po + 1
// past radius, depth is surely passed // past radius, depth is surely passed
if po >= radius { if po >= radius {
pastDepth = true pastDepth = true
} }
// beyond depth the bin is treated as unsaturated to achieve full connectivity // beyond depth the bin is treated as unsaturated even if size >= k.MinBinSize
// to all neighbours // in order to achieve full connectivity to all neighbours
if pastDepth && size >= k.MinBinSize { if pastDepth && size >= k.MinBinSize {
size = k.MinBinSize - 1 size = k.MinBinSize - 1
} }
@ -206,7 +206,7 @@ func (k *Kademlia) SuggestPeer() (suggestedPeer *BzzAddr, saturationDepth int, c
if saturationDepth == -1 { if saturationDepth == -1 {
saturationDepth = po saturationDepth = po
} }
spo[size] = append(spo[size], po) saturation[size] = append(saturation[size], po)
} }
return true return true
}) })
@ -217,53 +217,57 @@ func (k *Kademlia) SuggestPeer() (suggestedPeer *BzzAddr, saturationDepth int, c
nearestAddrAt = po nearestAddrAt = po
return false return false
}) })
for ; prev <= nearestAddrAt; prev++ { // including bins as size 0 has the effect that requesting connection
spo[0] = append(spo[0], prev) // is prioritised over non-empty shallower bins
for ; lastPO <= nearestAddrAt; lastPO++ {
saturation[0] = append(saturation[0], lastPO)
} }
// all PO bins are saturated, ie., minsize >= k.MinBinSize, no peer suggested // all PO bins are saturated, ie., minsize >= k.MinBinSize, no peer suggested
if len(spo) == 0 { if len(saturation) == 0 {
return nil, 0, false return nil, 0, false
} }
// find the first callable peer // find the first callable peer in the address book
// starting from the lowest cardinality // starting from the bins with smallest size proceeding from shallow to deep
// for each bin (up until neighbourhood radius) we find callable candidate peers // for each bin (up until neighbourhood radius) we find callable candidate peers
for i := 0; i < k.MinBinSize && suggestedPeer == nil; i++ { for size := 0; size < k.MinBinSize && suggestedPeer == nil; size++ {
bins, ok := spo[i] bins, ok := saturation[size]
if !ok { if !ok {
// no bin with this size
continue continue
} }
ci := 0 cur := 0
cpo := bins[0] curPO := bins[0]
k.addrs.EachBin(k.base, Pof, cpo, func(po, _ int, f func(func(pot.Val) bool) bool) bool { k.addrs.EachBin(k.base, Pof, curPO, func(po, _ int, f func(func(pot.Val) bool) bool) bool {
cpo = bins[ci] curPO = bins[cur]
// find the next bin with cardinality i // find the next bin that has size size
if cpo == po { if curPO == po {
ci++ cur++
} else { } else {
// skip bins that have no addresses // skip bins that have no addresses
for ; ci < len(bins) && cpo < po; ci++ { for ; cur < len(bins) && curPO < po; cur++ {
cpo = bins[ci] curPO = bins[cur]
} }
if po < cpo { if po < curPO {
ci-- cur--
return true return true
} }
// stop if there are no addresses // stop if there are no addresses
if cpo < po { if curPO < po {
return false return false
} }
} }
// curPO found
// find a callable peer out of the addresses in the unsaturated bin // find a callable peer out of the addresses in the unsaturated bin
// stop if found // stop if found
f(func(val pot.Val) bool { f(func(val pot.Val) bool {
e := val.(*entry) e := val.(*entry)
c := k.callable(e) if k.callable(e) {
if c {
suggestedPeer = e.BzzAddr suggestedPeer = e.BzzAddr
return false
} }
return !c return true
}) })
return ci < len(bins) && suggestedPeer == nil return cur < len(bins) && suggestedPeer == nil
}) })
} }
@ -434,7 +438,7 @@ func (k *Kademlia) NeighbourhoodDepth() (depth int) {
} }
// neighbourhoodRadiusForPot returns the neighbourhood radius of the kademlia // neighbourhoodRadiusForPot returns the neighbourhood radius of the kademlia
// neighbourhood radius encloses the nearest neighbour set with cardinality >= neighbourhoodSize // neighbourhood radius encloses the nearest neighbour set with size >= neighbourhoodSize
// i.e., neighbourhood radius is the deepest PO such that all bins not shallower altogether // i.e., neighbourhood radius is the deepest PO such that all bins not shallower altogether
// contain at least neighbourhoodSize connected peers // contain at least neighbourhoodSize connected peers
// if there is altogether less than neighbourhoodSize peers connected, it returns 0 // if there is altogether less than neighbourhoodSize peers connected, it returns 0