github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/querier/iterators/chunk_merge_iterator.go (about) 1 package iterators 2 3 import ( 4 "container/heap" 5 "sort" 6 7 "github.com/prometheus/common/model" 8 "github.com/prometheus/prometheus/tsdb/chunkenc" 9 10 "github.com/cortexproject/cortex/pkg/chunk" 11 ) 12 13 type chunkMergeIterator struct { 14 its []*nonOverlappingIterator 15 h seriesIteratorHeap 16 17 currTime int64 18 currValue float64 19 currErr error 20 } 21 22 // NewChunkMergeIterator creates a chunkenc.Iterator for a set of chunks. 23 func NewChunkMergeIterator(cs []chunk.Chunk, _, _ model.Time) chunkenc.Iterator { 24 its := buildIterators(cs) 25 c := &chunkMergeIterator{ 26 currTime: -1, 27 its: its, 28 h: make(seriesIteratorHeap, 0, len(its)), 29 } 30 31 for _, iter := range c.its { 32 if iter.Next() { 33 c.h = append(c.h, iter) 34 continue 35 } 36 37 if err := iter.Err(); err != nil { 38 c.currErr = err 39 } 40 } 41 42 heap.Init(&c.h) 43 return c 44 } 45 46 // Build a list of lists of non-overlapping chunk iterators. 47 func buildIterators(cs []chunk.Chunk) []*nonOverlappingIterator { 48 chunks := make([]*chunkIterator, len(cs)) 49 for i := range cs { 50 chunks[i] = &chunkIterator{ 51 Chunk: cs[i], 52 it: cs[i].Data.NewIterator(nil), 53 } 54 } 55 sort.Sort(byFrom(chunks)) 56 57 chunkLists := [][]*chunkIterator{} 58 outer: 59 for _, chunk := range chunks { 60 for i, chunkList := range chunkLists { 61 if chunkList[len(chunkList)-1].Through.Before(chunk.From) { 62 chunkLists[i] = append(chunkLists[i], chunk) 63 continue outer 64 } 65 } 66 chunkLists = append(chunkLists, []*chunkIterator{chunk}) 67 } 68 69 its := make([]*nonOverlappingIterator, 0, len(chunkLists)) 70 for _, chunkList := range chunkLists { 71 its = append(its, newNonOverlappingIterator(chunkList)) 72 } 73 return its 74 } 75 76 func (c *chunkMergeIterator) Seek(t int64) bool { 77 c.h = c.h[:0] 78 79 for _, iter := range c.its { 80 if iter.Seek(t) { 81 c.h = append(c.h, iter) 82 continue 83 } 84 85 if err := iter.Err(); err != nil { 86 c.currErr = err 87 return false 88 } 89 } 90 91 heap.Init(&c.h) 92 93 if len(c.h) > 0 { 94 c.currTime, c.currValue = c.h[0].At() 95 return true 96 } 97 98 return false 99 } 100 101 func (c *chunkMergeIterator) Next() bool { 102 if len(c.h) == 0 { 103 return false 104 } 105 106 lastTime := c.currTime 107 for c.currTime == lastTime && len(c.h) > 0 { 108 c.currTime, c.currValue = c.h[0].At() 109 110 if c.h[0].Next() { 111 heap.Fix(&c.h, 0) 112 continue 113 } 114 115 iter := heap.Pop(&c.h).(chunkenc.Iterator) 116 if err := iter.Err(); err != nil { 117 c.currErr = err 118 return false 119 } 120 } 121 122 return c.currTime != lastTime 123 } 124 125 func (c *chunkMergeIterator) At() (t int64, v float64) { 126 return c.currTime, c.currValue 127 } 128 129 func (c *chunkMergeIterator) Err() error { 130 return c.currErr 131 } 132 133 type extraIterator interface { 134 chunkenc.Iterator 135 AtTime() int64 136 } 137 138 type seriesIteratorHeap []extraIterator 139 140 func (h *seriesIteratorHeap) Len() int { return len(*h) } 141 func (h *seriesIteratorHeap) Swap(i, j int) { (*h)[i], (*h)[j] = (*h)[j], (*h)[i] } 142 143 func (h *seriesIteratorHeap) Less(i, j int) bool { 144 iT := (*h)[i].AtTime() 145 jT := (*h)[j].AtTime() 146 return iT < jT 147 } 148 149 func (h *seriesIteratorHeap) Push(x interface{}) { 150 *h = append(*h, x.(extraIterator)) 151 } 152 153 func (h *seriesIteratorHeap) Pop() interface{} { 154 old := *h 155 n := len(old) 156 x := old[n-1] 157 *h = old[0 : n-1] 158 return x 159 } 160 161 type byFrom []*chunkIterator 162 163 func (b byFrom) Len() int { return len(b) } 164 func (b byFrom) Swap(i, j int) { b[i], b[j] = b[j], b[i] } 165 func (b byFrom) Less(i, j int) bool { return b[i].From < b[j].From } 166 167 type nonOverlappingIterator struct { 168 curr int 169 chunks []*chunkIterator 170 } 171 172 // newNonOverlappingIterator returns a single iterator over an slice of sorted, 173 // non-overlapping iterators. 174 func newNonOverlappingIterator(chunks []*chunkIterator) *nonOverlappingIterator { 175 return &nonOverlappingIterator{ 176 chunks: chunks, 177 } 178 } 179 180 func (it *nonOverlappingIterator) Seek(t int64) bool { 181 for ; it.curr < len(it.chunks); it.curr++ { 182 if it.chunks[it.curr].Seek(t) { 183 return true 184 } 185 } 186 187 return false 188 } 189 190 func (it *nonOverlappingIterator) Next() bool { 191 for it.curr < len(it.chunks) && !it.chunks[it.curr].Next() { 192 it.curr++ 193 } 194 195 return it.curr < len(it.chunks) 196 } 197 198 func (it *nonOverlappingIterator) AtTime() int64 { 199 return it.chunks[it.curr].AtTime() 200 } 201 202 func (it *nonOverlappingIterator) At() (int64, float64) { 203 return it.chunks[it.curr].At() 204 } 205 206 func (it *nonOverlappingIterator) Err() error { 207 return nil 208 }