github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/peer/queue/distance.go (about) 1 package queue 2 3 import ( 4 "container/heap" 5 "math/big" 6 "sync" 7 8 peer "github.com/jbenet/go-ipfs/peer" 9 ks "github.com/jbenet/go-ipfs/routing/keyspace" 10 u "github.com/jbenet/go-ipfs/util" 11 ) 12 13 // peerMetric tracks a peer and its distance to something else. 14 type peerMetric struct { 15 // the peer 16 peer peer.Peer 17 18 // big.Int for XOR metric 19 metric *big.Int 20 } 21 22 // peerMetricHeap implements a heap of peerDistances 23 type peerMetricHeap []*peerMetric 24 25 func (ph peerMetricHeap) Len() int { 26 return len(ph) 27 } 28 29 func (ph peerMetricHeap) Less(i, j int) bool { 30 return -1 == ph[i].metric.Cmp(ph[j].metric) 31 } 32 33 func (ph peerMetricHeap) Swap(i, j int) { 34 ph[i], ph[j] = ph[j], ph[i] 35 } 36 37 func (ph *peerMetricHeap) Push(x interface{}) { 38 item := x.(*peerMetric) 39 *ph = append(*ph, item) 40 } 41 42 func (ph *peerMetricHeap) Pop() interface{} { 43 old := *ph 44 n := len(old) 45 item := old[n-1] 46 *ph = old[0 : n-1] 47 return item 48 } 49 50 // distancePQ implements heap.Interface and PeerQueue 51 type distancePQ struct { 52 // from is the Key this PQ measures against 53 from ks.Key 54 55 // heap is a heap of peerDistance items 56 heap peerMetricHeap 57 58 sync.RWMutex 59 } 60 61 func (pq *distancePQ) Len() int { 62 pq.Lock() 63 defer pq.Unlock() 64 return len(pq.heap) 65 } 66 67 func (pq *distancePQ) Enqueue(p peer.Peer) { 68 pq.Lock() 69 defer pq.Unlock() 70 71 distance := ks.XORKeySpace.Key(p.ID()).Distance(pq.from) 72 73 heap.Push(&pq.heap, &peerMetric{ 74 peer: p, 75 metric: distance, 76 }) 77 } 78 79 func (pq *distancePQ) Dequeue() peer.Peer { 80 pq.Lock() 81 defer pq.Unlock() 82 83 if len(pq.heap) < 1 { 84 panic("called Dequeue on an empty PeerQueue") 85 // will panic internally anyway, but we can help debug here 86 } 87 88 o := heap.Pop(&pq.heap) 89 p := o.(*peerMetric) 90 return p.peer 91 } 92 93 // NewXORDistancePQ returns a PeerQueue which maintains its peers sorted 94 // in terms of their distances to each other in an XORKeySpace (i.e. using 95 // XOR as a metric of distance). 96 func NewXORDistancePQ(fromKey u.Key) PeerQueue { 97 return &distancePQ{ 98 from: ks.XORKeySpace.Key([]byte(fromKey)), 99 heap: peerMetricHeap{}, 100 } 101 }