Files
go-libp2p-kad-dht/kpeerset/kpeerset.go
2020-03-04 22:11:53 -08:00

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),
}
}
*/