github.com/pachyderm/pachyderm@v1.13.4/src/server/pkg/storage/fileset/priority_queue.go (about) 1 package fileset 2 3 import ( 4 "io" 5 6 "github.com/pachyderm/pachyderm/src/client/pkg/errors" 7 ) 8 9 // TODO: Change the code that depends on this to use the stream package priority queue. 10 type stream interface { 11 next() error 12 key() string 13 streamPriority() int 14 } 15 16 type priorityQueue struct { 17 queue []stream 18 size int 19 ss []stream 20 } 21 22 func newPriorityQueue(ss []stream) *priorityQueue { 23 return &priorityQueue{ 24 queue: make([]stream, len(ss)+1), 25 ss: ss, 26 } 27 } 28 29 func (pq *priorityQueue) iterate(f func([]stream, ...string) error) error { 30 for { 31 ss, err := pq.next() 32 if err != nil { 33 if errors.Is(err, io.EOF) { 34 return nil 35 } 36 return err 37 } 38 if err := f(ss, pq.peek()...); err != nil { 39 return err 40 } 41 } 42 } 43 44 func (pq *priorityQueue) isHigherPriority(i, j int) bool { 45 si := pq.queue[i] 46 sj := pq.queue[j] 47 return si.key() < sj.key() || (si.key() == sj.key() && si.streamPriority() > sj.streamPriority()) 48 } 49 50 func (pq *priorityQueue) empty() bool { 51 return len(pq.queue) == 1 || pq.queue[1] == nil 52 } 53 54 func (pq *priorityQueue) insert(s stream) error { 55 // Get next in stream and insert it. 56 if err := s.next(); err != nil { 57 if errors.Is(err, io.EOF) { 58 return nil 59 } 60 return err 61 } 62 pq.queue[pq.size+1] = s 63 pq.size++ 64 // Propagate insert up the queue 65 i := pq.size 66 for i > 1 { 67 if pq.isHigherPriority(i/2, i) { 68 break 69 } 70 pq.swap(i/2, i) 71 i /= 2 72 } 73 return nil 74 } 75 76 func (pq *priorityQueue) next() ([]stream, error) { 77 // Re-insert streams 78 if pq.ss != nil { 79 for _, s := range pq.ss { 80 if err := pq.insert(s); err != nil { 81 return nil, err 82 } 83 } 84 } 85 if pq.empty() { 86 return nil, io.EOF 87 } 88 ss := []stream{pq.queue[1]} 89 pq.fill() 90 // Keep popping streams off the queue if they have the same key. 91 for pq.queue[1] != nil && pq.queue[1].key() == ss[0].key() { 92 ss = append(ss, pq.queue[1]) 93 pq.fill() 94 } 95 pq.ss = ss 96 return ss, nil 97 } 98 99 func (pq *priorityQueue) peek() []string { 100 if pq.empty() { 101 return nil 102 } 103 return []string{pq.queue[1].key()} 104 } 105 106 func (pq *priorityQueue) fill() { 107 // Replace first stream with last 108 pq.queue[1] = pq.queue[pq.size] 109 pq.queue[pq.size] = nil 110 pq.size-- 111 // Propagate last stream down the queue 112 i := 1 113 var next int 114 for { 115 left, right := i*2, i*2+1 116 if left > pq.size { 117 break 118 } else if right > pq.size || pq.isHigherPriority(left, right) { 119 next = left 120 } else { 121 next = right 122 } 123 if pq.isHigherPriority(i, next) { 124 break 125 } 126 pq.swap(i, next) 127 i = next 128 } 129 } 130 131 func (pq *priorityQueue) swap(i, j int) { 132 pq.queue[i], pq.queue[j] = pq.queue[j], pq.queue[i] 133 }