1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-09-10 05:52:20 +08:00
Files
Brian Tiger Chow 61e4300d59 feat(PQ)
refactor: peerRequestQueue

	it's a mistake to make one queue to fit all. Go's lack of algebraic
	types turns a generalized queue into a monstrosity of type
	checking/casting. Better to have individual queues for individual
	purposes.

	Conflicts:
		exchange/bitswap/decision/bench_test.go
		exchange/bitswap/decision/tasks/task_queue.go

	fix(bitswap.decision.PRQ): if peers match, always return result of pri comparison

	fix(bitswap.decision.Engine): push to the queue before notifying

	TOCTOU bug

	1. client notifies
	2. worker checks (finds nil)
	3. worker sleeps
	3. client pushes (worker missed the update)

	test(PQ): improve documentation and add test

	test(bitswap.decision.Engine): handling received messages

	License: MIT
	Signed-off-by: Brian Tiger Chow <brian@perfmode.com>
2015-01-18 15:09:54 -08:00

106 lines
2.5 KiB
Go

package pq
import "container/heap"
// PQ is a basic priority queue.
type PQ interface {
// Push adds the ele
Push(Elem)
// Pop returns the highest priority Elem in PQ.
Pop() Elem
// Len returns the number of elements in the PQ.
Len() int
// Update `fixes` the PQ.
Update(index int)
// TODO explain why this interface should not be extended
// It does not support Remove. This is because...
}
// Elem describes elements that can be added to the PQ. Clients must implement
// this interface.
type Elem interface {
// SetIndex stores the int index.
SetIndex(int)
// Index returns the last given by SetIndex(int).
Index() int
}
// ElemComparator returns true if pri(a) > pri(b)
type ElemComparator func(a, b Elem) bool
// New creates a PQ with a client-supplied comparator.
func New(cmp ElemComparator) PQ {
q := &wrapper{heapinterface{
elems: make([]Elem, 0),
cmp: cmp,
}}
heap.Init(&q.heapinterface)
return q
}
// wrapper exists because we cannot re-define Push. We want to expose
// Push(Elem) but heap.Interface requires Push(interface{})
type wrapper struct {
heapinterface
}
var _ PQ = &wrapper{}
func (w *wrapper) Push(e Elem) {
heap.Push(&w.heapinterface, e)
}
func (w *wrapper) Pop() Elem {
return heap.Pop(&w.heapinterface).(Elem)
}
func (w *wrapper) Update(index int) {
heap.Fix(&w.heapinterface, index)
}
// heapinterface handles dirty low-level details of managing the priority queue.
type heapinterface struct {
elems []Elem
cmp ElemComparator
}
var _ heap.Interface = &heapinterface{}
// public interface
func (q *heapinterface) Len() int {
return len(q.elems)
}
// Less delegates the decision to the comparator
func (q *heapinterface) Less(i, j int) bool {
return q.cmp(q.elems[i], q.elems[j])
}
// Swap swaps the elements with indexes i and j.
func (q *heapinterface) Swap(i, j int) {
q.elems[i], q.elems[j] = q.elems[j], q.elems[i]
q.elems[i].SetIndex(i)
q.elems[j].SetIndex(j)
}
// Note that Push and Pop in this interface are for package heap's
// implementation to call. To add and remove things from the heap, wrap with
// the pq struct to call heap.Push and heap.Pop.
func (q *heapinterface) Push(x interface{}) { // where to put the elem?
t := x.(Elem)
t.SetIndex(len(q.elems))
q.elems = append(q.elems, t)
}
func (q *heapinterface) Pop() interface{} {
old := q.elems
n := len(old)
elem := old[n-1] // remove the last
elem.SetIndex(-1) // for safety // FIXME why?
q.elems = old[0 : n-1] // shrink
return elem
}