github.com/grafana/pyroscope@v1.18.0/pkg/util/loser/tree.go (about) 1 // Loser tree, from https://en.wikipedia.org/wiki/K-way_merge_algorithm#Tournament_Tree 2 3 package loser 4 5 type Sequence interface { 6 Next() bool // Advances and returns true if there is a value at this new position. 7 Err() error // Returns any error encountered while advancing. 8 } 9 10 // New returns a new loser tree that merges the given sequences. 11 // The sequences must be sorted according to the less function already. 12 // The maxVal is used to initialize the tree. 13 // The at function returns the current value of the sequence. 14 // The less function compares two values. 15 // The close function is called on each sequence when the tree is closed or when a sequence returns false from Next(). 16 // If any sequence returns an error from Err() after Next() = false, the tree will stop and return that error in Err(). 17 // Examples: 18 // 19 // tree := loser.New(...) 20 // defer tree.Close() 21 // for tree.Next() { 22 // value := tree.Winner().At() 23 // ... 24 // } 25 // if err := tree.Err(); err != nil { 26 // ... 27 // } 28 func New[E any, S Sequence](sequences []S, maxVal E, at func(S) E, less func(E, E) bool, close func(S)) *Tree[E, S] { 29 nSequences := len(sequences) 30 t := Tree[E, S]{ 31 maxVal: maxVal, 32 at: at, 33 less: less, 34 close: close, 35 nodes: make([]node[E, S], nSequences*2), 36 } 37 for i, s := range sequences { 38 t.nodes[i+nSequences].items = s 39 if !t.moveNext(i + nSequences) { // Must call Next on each item so that At() has a value. 40 if t.err != nil { 41 // error during initialize, requires us to close sequences not touched yet and mark nodes as uninitialized 42 for j := i + 1; j < nSequences; j++ { 43 t.close(sequences[j]) 44 t.nodes[j+nSequences].index = -1 45 } 46 break 47 } 48 } 49 } 50 if nSequences > 0 { 51 t.nodes[0].index = -1 // flag to be initialized on first call to Next(). 52 } 53 return &t 54 } 55 56 // Call the close function on all sequences that are still open. 57 func (t *Tree[E, S]) Close() { 58 for _, e := range t.nodes[len(t.nodes)/2 : len(t.nodes)] { 59 if e.index == -1 { 60 continue 61 } 62 t.close(e.items) 63 } 64 } 65 66 // A loser tree is a binary tree laid out such that nodes N and N+1 have parent N/2. 67 // We store M leaf nodes in positions M...2M-1, and M-1 internal nodes in positions 1..M-1. 68 // Node 0 is a special node, containing the winner of the contest. 69 type Tree[E any, S Sequence] struct { 70 maxVal E 71 at func(S) E 72 less func(E, E) bool 73 close func(S) // Called when Next() returns false. 74 nodes []node[E, S] 75 76 err error 77 } 78 79 type node[E any, S Sequence] struct { 80 index int // This is the loser for all nodes except the 0th, where it is the winner. 81 value E // Value copied from the loser node, or winner for node 0. 82 items S // Only populated for leaf nodes. 83 } 84 85 func (t *Tree[E, S]) moveNext(index int) bool { 86 n := &t.nodes[index] 87 if n.items.Next() { 88 n.value = t.at(n.items) 89 return true 90 } 91 t.close(n.items) // Next() returned false; close it and mark as finished. 92 t.err = n.items.Err() 93 n.value = t.maxVal 94 n.index = -1 95 return false 96 } 97 98 func (t *Tree[E, S]) Winner() S { 99 return t.nodes[t.nodes[0].index].items 100 } 101 102 func (t *Tree[E, S]) Next() bool { 103 if len(t.nodes) == 0 || t.err != nil { 104 return false 105 } 106 if t.nodes[0].index == -1 { // If tree has not been initialized yet, do that. 107 t.initialize() 108 return t.nodes[t.nodes[0].index].index != -1 109 } 110 if t.nodes[t.nodes[0].index].index == -1 { // already exhausted 111 return false 112 } 113 if !t.moveNext(t.nodes[0].index) && t.err != nil { 114 return false 115 } 116 t.replayGames(t.nodes[0].index) 117 return t.nodes[t.nodes[0].index].index != -1 118 } 119 120 func (t *Tree[E, S]) Err() error { 121 return t.err 122 } 123 124 func (t *Tree[E, S]) initialize() { 125 winners := make([]int, len(t.nodes)) 126 // Initialize leaf nodes as winners to start. 127 for i := len(t.nodes) / 2; i < len(t.nodes); i++ { 128 winners[i] = i 129 } 130 for i := len(t.nodes) - 2; i > 0; i -= 2 { 131 // At each stage the winners play each other, and we record the loser in the node. 132 loser, winner := t.playGame(winners[i], winners[i+1]) 133 p := parent(i) 134 t.nodes[p].index = loser 135 t.nodes[p].value = t.nodes[loser].value 136 winners[p] = winner 137 } 138 t.nodes[0].index = winners[1] 139 t.nodes[0].value = t.nodes[winners[1]].value 140 } 141 142 // Starting at pos, re-consider all values up to the root. 143 func (t *Tree[E, S]) replayGames(pos int) { 144 // At the start, pos is a leaf node, and is the winner at that level. 145 n := parent(pos) 146 for n != 0 { 147 if t.less(t.nodes[n].value, t.nodes[pos].value) { 148 loser := pos 149 // Record pos as the loser here, and the old loser is the new winner. 150 pos = t.nodes[n].index 151 t.nodes[n].index = loser 152 t.nodes[n].value = t.nodes[loser].value 153 } 154 n = parent(n) 155 } 156 // pos is now the winner; store it in node 0. 157 t.nodes[0].index = pos 158 t.nodes[0].value = t.nodes[pos].value 159 } 160 161 func (t *Tree[E, S]) playGame(a, b int) (loser, winner int) { 162 if t.less(t.nodes[a].value, t.nodes[b].value) { 163 return b, a 164 } 165 return a, b 166 } 167 168 func parent(i int) int { return i / 2 } 169 170 // Add a new sequence to the merge set 171 func (t *Tree[E, S]) Push(sequence S) error { 172 // First, see if we can replace one that was previously finished. 173 for newPos := len(t.nodes) / 2; newPos < len(t.nodes); newPos++ { 174 if t.nodes[newPos].index == -1 { 175 t.nodes[newPos].index = newPos 176 t.nodes[newPos].items = sequence 177 if !t.moveNext(newPos) { 178 if t.err != nil { 179 return t.err 180 } 181 } 182 t.nodes[0].index = -1 // flag for re-initialize on next call to Next() 183 return nil 184 } 185 } 186 // We need to expand the tree. Pick the next biggest power of 2 to amortise resizing cost. 187 size := 1 188 for ; size <= len(t.nodes)/2; size *= 2 { 189 } 190 newPos := size + len(t.nodes)/2 191 newNodes := make([]node[E, S], size*2) 192 // Copy data over and fix up the indexes. 193 for i, n := range t.nodes[len(t.nodes)/2:] { 194 newNodes[i+size] = n 195 newNodes[i+size].index = i + size 196 } 197 t.nodes = newNodes 198 t.nodes[newPos].index = newPos 199 t.nodes[newPos].items = sequence 200 // Mark all the empty nodes we have added as finished. 201 for i := newPos + 1; i < len(t.nodes); i++ { 202 t.nodes[i].index = -1 203 t.nodes[i].value = t.maxVal 204 } 205 if !t.moveNext(newPos) { 206 if t.err != nil { 207 return t.err 208 } 209 } 210 t.nodes[0].index = -1 // flag for re-initialize on next call to Next() 211 return nil 212 }