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  }