mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-23 19:37:46 +08:00
I think it's time to move a lot of the peer-to-peer networking but-not-ipfs-specific things into its own package: p2p. This could in the future be split off into its own library. The first thing to go is the peer.
102 lines
2.0 KiB
Go
102 lines
2.0 KiB
Go
package queue
|
|
|
|
import (
|
|
"container/heap"
|
|
"math/big"
|
|
"sync"
|
|
|
|
peer "github.com/jbenet/go-ipfs/p2p/peer"
|
|
ks "github.com/jbenet/go-ipfs/routing/keyspace"
|
|
u "github.com/jbenet/go-ipfs/util"
|
|
)
|
|
|
|
// 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
|
|
}
|
|
|
|
// peerMetricHeap implements a heap of peerDistances
|
|
type peerMetricHeap []*peerMetric
|
|
|
|
func (ph peerMetricHeap) Len() int {
|
|
return len(ph)
|
|
}
|
|
|
|
func (ph peerMetricHeap) Less(i, j int) bool {
|
|
return -1 == ph[i].metric.Cmp(ph[j].metric)
|
|
}
|
|
|
|
func (ph peerMetricHeap) Swap(i, j int) {
|
|
ph[i], ph[j] = ph[j], ph[i]
|
|
}
|
|
|
|
func (ph *peerMetricHeap) Push(x interface{}) {
|
|
item := x.(*peerMetric)
|
|
*ph = append(*ph, item)
|
|
}
|
|
|
|
func (ph *peerMetricHeap) Pop() interface{} {
|
|
old := *ph
|
|
n := len(old)
|
|
item := old[n-1]
|
|
*ph = old[0 : n-1]
|
|
return item
|
|
}
|
|
|
|
// distancePQ implements heap.Interface and PeerQueue
|
|
type distancePQ struct {
|
|
// from is the Key this PQ measures against
|
|
from ks.Key
|
|
|
|
// heap is a heap of peerDistance items
|
|
heap peerMetricHeap
|
|
|
|
sync.RWMutex
|
|
}
|
|
|
|
func (pq *distancePQ) Len() int {
|
|
pq.Lock()
|
|
defer pq.Unlock()
|
|
return len(pq.heap)
|
|
}
|
|
|
|
func (pq *distancePQ) Enqueue(p peer.ID) {
|
|
pq.Lock()
|
|
defer pq.Unlock()
|
|
|
|
distance := ks.XORKeySpace.Key([]byte(p)).Distance(pq.from)
|
|
|
|
heap.Push(&pq.heap, &peerMetric{
|
|
peer: p,
|
|
metric: distance,
|
|
})
|
|
}
|
|
|
|
func (pq *distancePQ) Dequeue() peer.ID {
|
|
pq.Lock()
|
|
defer pq.Unlock()
|
|
|
|
if len(pq.heap) < 1 {
|
|
panic("called Dequeue on an empty PeerQueue")
|
|
// will panic internally anyway, but we can help debug here
|
|
}
|
|
|
|
o := heap.Pop(&pq.heap)
|
|
p := o.(*peerMetric)
|
|
return p.peer
|
|
}
|
|
|
|
// NewXORDistancePQ returns a PeerQueue which maintains its peers sorted
|
|
// in terms of their distances to each other in an XORKeySpace (i.e. using
|
|
// XOR as a metric of distance).
|
|
func NewXORDistancePQ(fromKey u.Key) PeerQueue {
|
|
return &distancePQ{
|
|
from: ks.XORKeySpace.Key([]byte(fromKey)),
|
|
heap: peerMetricHeap{},
|
|
}
|
|
}
|