mirror of
https://github.com/fluencelabs/go-libp2p-kad-dht
synced 2025-07-05 23:51:38 +00:00
159 lines
3.0 KiB
Go
159 lines
3.0 KiB
Go
package kpeerset
|
|
|
|
import (
|
|
"github.com/libp2p/go-libp2p-core/peer"
|
|
"math/big"
|
|
)
|
|
|
|
type IPeerMetric interface {
|
|
Peer() peer.ID
|
|
Metric() *big.Int
|
|
}
|
|
|
|
// peerMetric tracks a peer and its distance to something else.
|
|
type peerMetric struct {
|
|
// the peer
|
|
peer peer.ID
|
|
|
|
// big.Int for XOR metric
|
|
metric *big.Int
|
|
}
|
|
|
|
func (pm peerMetric) Peer() peer.ID { return pm.peer }
|
|
func (pm peerMetric) Metric() *big.Int { return pm.metric }
|
|
|
|
type peerMetricHeapItem struct {
|
|
IPeerMetric
|
|
|
|
// The index of the item in the heap
|
|
index int
|
|
}
|
|
|
|
// peerMetricHeap implements a heap of peerDistances.
|
|
// The heap sorts by furthest if direction = 1 and closest if direction = -1
|
|
type peerMetricHeap struct {
|
|
data []*peerMetricHeapItem
|
|
direction int
|
|
}
|
|
|
|
func (ph *peerMetricHeap) Len() int {
|
|
return len(ph.data)
|
|
}
|
|
|
|
func (ph *peerMetricHeap) Less(i, j int) bool {
|
|
h := ph.data
|
|
return ph.direction == h[i].Metric().Cmp(h[j].Metric())
|
|
}
|
|
|
|
func (ph *peerMetricHeap) Swap(i, j int) {
|
|
h := ph.data
|
|
h[i], h[j] = h[j], h[i]
|
|
h[i].index = i
|
|
h[j].index = j
|
|
}
|
|
|
|
func (ph *peerMetricHeap) Push(x interface{}) {
|
|
n := len(ph.data)
|
|
item := x.(*peerMetricHeapItem)
|
|
item.index = n
|
|
ph.data = append(ph.data, item)
|
|
}
|
|
|
|
func (ph *peerMetricHeap) Pop() interface{} {
|
|
old := ph.data
|
|
n := len(old)
|
|
item := old[n-1]
|
|
old[n-1] = nil // avoid memory leak
|
|
item.index = -1 // for safety
|
|
ph.data = old[0 : n-1]
|
|
return item
|
|
}
|
|
|
|
/*
|
|
// KPeerSet implements heap.Interface and PeerQueue
|
|
type KPeerSet struct {
|
|
kvalue int
|
|
|
|
// from is the Key this PQ measures against
|
|
from ks.Key
|
|
|
|
// heap is a heap of peerDistance items
|
|
heap peerMetricHeap
|
|
|
|
lock sync.RWMutex
|
|
}
|
|
|
|
func (pq *KPeerSet) Len() int {
|
|
pq.lock.RLock()
|
|
defer pq.lock.RUnlock()
|
|
|
|
return len(pq.heap)
|
|
}
|
|
|
|
func (pq *KPeerSet) Check(p peer.ID) bool {
|
|
pq.lock.RLock()
|
|
defer pq.lock.RUnlock()
|
|
|
|
if pq.heap.Len() < pq.kvalue {
|
|
return true
|
|
}
|
|
|
|
distance := ks.XORKeySpace.Key([]byte(p)).Distance(pq.from)
|
|
return distance.Cmp(pq.heap[0].metric) != -1
|
|
}
|
|
|
|
func (pq *KPeerSet) Add(p peer.ID) (bool, peer.ID) {
|
|
pq.lock.Lock()
|
|
defer pq.lock.Unlock()
|
|
|
|
distance := ks.XORKeySpace.Key([]byte(p)).Distance(pq.from)
|
|
|
|
var replacedPeer peer.ID
|
|
if pq.heap.Len() >= pq.kvalue {
|
|
// If we're not closer than the worst peer, drop this.
|
|
if distance.Cmp(pq.heap[0].metric) != -1 {
|
|
return false, replacedPeer
|
|
}
|
|
// Replacing something, remove it.
|
|
replacedPeer = heap.Pop(&pq.heap).(*peerMetric).peer
|
|
}
|
|
|
|
heap.Push(&pq.heap, &peerMetric{
|
|
peer: p,
|
|
metric: distance,
|
|
})
|
|
return true, replacedPeer
|
|
}
|
|
|
|
func (pq *KPeerSet) Remove(id peer.ID) {
|
|
pq.lock.Lock()
|
|
defer pq.lock.Unlock()
|
|
|
|
for i, pm := range pq.heap {
|
|
if pm.peer == id {
|
|
heap.Remove(&pq.heap, i)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (pq *KPeerSet) Peers() []peer.ID {
|
|
pq.lock.RLock()
|
|
defer pq.lock.RUnlock()
|
|
|
|
ret := make([]peer.ID, len(pq.heap))
|
|
for _, pm := range pq.heap {
|
|
ret = append(ret, pm.peer)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func New(kvalue int, from string) *KPeerSet {
|
|
return &KPeerSet{
|
|
from: ks.XORKeySpace.Key([]byte(from)),
|
|
kvalue: kvalue,
|
|
heap: make([]*peerMetric, 0, kvalue),
|
|
}
|
|
}
|
|
*/
|