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  }