github.com/thanos-io/thanos@v0.32.5/pkg/query/iter.go (about)

     1  // Copyright (c) The Thanos Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package query
     5  
     6  import (
     7  	"github.com/pkg/errors"
     8  	"github.com/prometheus/prometheus/model/histogram"
     9  	"github.com/prometheus/prometheus/model/labels"
    10  	"github.com/prometheus/prometheus/storage"
    11  	"github.com/prometheus/prometheus/tsdb/chunkenc"
    12  
    13  	"github.com/thanos-io/thanos/pkg/compact/downsample"
    14  	"github.com/thanos-io/thanos/pkg/dedup"
    15  	"github.com/thanos-io/thanos/pkg/store/storepb"
    16  )
    17  
    18  // promSeriesSet implements the SeriesSet interface of the Prometheus storage
    19  // package on top of our storepb SeriesSet. Overlapping chunks will be naively deduplicated (random selection).
    20  type promSeriesSet struct {
    21  	set storepb.SeriesSet
    22  
    23  	mint, maxt int64
    24  	aggrs      []storepb.Aggr
    25  
    26  	warns storage.Warnings
    27  }
    28  
    29  func (s *promSeriesSet) Next() bool {
    30  	return s.set.Next()
    31  }
    32  
    33  func (s *promSeriesSet) At() storage.Series {
    34  	if s.set.Err() != nil {
    35  		return nil
    36  	}
    37  
    38  	currLset, currChunks := s.set.At()
    39  	return newChunkSeries(currLset, currChunks, s.mint, s.maxt, s.aggrs)
    40  }
    41  
    42  func (s *promSeriesSet) Err() error {
    43  	return s.set.Err()
    44  }
    45  
    46  func (s *promSeriesSet) Warnings() storage.Warnings {
    47  	return s.warns
    48  }
    49  
    50  // storeSeriesSet implements a storepb SeriesSet against a list of storepb.Series.
    51  type storeSeriesSet struct {
    52  	// TODO(bwplotka): Don't buffer all, we have to buffer single series (to sort and dedup chunks), but nothing more.
    53  	series []storepb.Series
    54  	i      int
    55  }
    56  
    57  func newStoreSeriesSet(s []storepb.Series) *storeSeriesSet {
    58  	return &storeSeriesSet{series: s, i: -1}
    59  }
    60  
    61  func (s *storeSeriesSet) Next() bool {
    62  	if s.i >= len(s.series)-1 {
    63  		return false
    64  	}
    65  	s.i++
    66  	return true
    67  }
    68  
    69  func (*storeSeriesSet) Err() error {
    70  	return nil
    71  }
    72  
    73  func (s *storeSeriesSet) At() (labels.Labels, []storepb.AggrChunk) {
    74  	return s.series[s.i].PromLabels(), s.series[s.i].Chunks
    75  }
    76  
    77  // chunkSeries implements storage.Series for a series on storepb types.
    78  type chunkSeries struct {
    79  	lset       labels.Labels
    80  	chunks     []storepb.AggrChunk
    81  	mint, maxt int64
    82  	aggrs      []storepb.Aggr
    83  }
    84  
    85  // newChunkSeries allows to iterate over samples for each sorted and non-overlapped chunks.
    86  func newChunkSeries(lset labels.Labels, chunks []storepb.AggrChunk, mint, maxt int64, aggrs []storepb.Aggr) *chunkSeries {
    87  	return &chunkSeries{
    88  		lset:   lset,
    89  		chunks: chunks,
    90  		mint:   mint,
    91  		maxt:   maxt,
    92  		aggrs:  aggrs,
    93  	}
    94  }
    95  
    96  func (s *chunkSeries) Labels() labels.Labels {
    97  	return s.lset
    98  }
    99  
   100  func (s *chunkSeries) Iterator(_ chunkenc.Iterator) chunkenc.Iterator {
   101  	var sit chunkenc.Iterator
   102  	its := make([]chunkenc.Iterator, 0, len(s.chunks))
   103  
   104  	if len(s.aggrs) == 1 {
   105  		switch s.aggrs[0] {
   106  		case storepb.Aggr_COUNT:
   107  			for _, c := range s.chunks {
   108  				its = append(its, getFirstIterator(c.Count, c.Raw))
   109  			}
   110  			sit = newChunkSeriesIterator(its)
   111  		case storepb.Aggr_SUM:
   112  			for _, c := range s.chunks {
   113  				its = append(its, getFirstIterator(c.Sum, c.Raw))
   114  			}
   115  			sit = newChunkSeriesIterator(its)
   116  		case storepb.Aggr_MIN:
   117  			for _, c := range s.chunks {
   118  				its = append(its, getFirstIterator(c.Min, c.Raw))
   119  			}
   120  			sit = newChunkSeriesIterator(its)
   121  		case storepb.Aggr_MAX:
   122  			for _, c := range s.chunks {
   123  				its = append(its, getFirstIterator(c.Max, c.Raw))
   124  			}
   125  			sit = newChunkSeriesIterator(its)
   126  		case storepb.Aggr_COUNTER:
   127  			for _, c := range s.chunks {
   128  				its = append(its, getFirstIterator(c.Counter, c.Raw))
   129  			}
   130  			// TODO(bwplotka): This breaks resets function. See https://github.com/thanos-io/thanos/issues/3644
   131  			sit = downsample.NewApplyCounterResetsIterator(its...)
   132  		default:
   133  			return errSeriesIterator{err: errors.Errorf("unexpected result aggregate type %v", s.aggrs)}
   134  		}
   135  		return dedup.NewBoundedSeriesIterator(sit, s.mint, s.maxt)
   136  	}
   137  
   138  	if len(s.aggrs) != 2 {
   139  		return errSeriesIterator{err: errors.Errorf("unexpected result aggregate type %v", s.aggrs)}
   140  	}
   141  
   142  	switch {
   143  	case s.aggrs[0] == storepb.Aggr_SUM && s.aggrs[1] == storepb.Aggr_COUNT,
   144  		s.aggrs[0] == storepb.Aggr_COUNT && s.aggrs[1] == storepb.Aggr_SUM:
   145  
   146  		for _, c := range s.chunks {
   147  			if c.Raw != nil {
   148  				its = append(its, getFirstIterator(c.Raw))
   149  			} else {
   150  				sum, cnt := getFirstIterator(c.Sum), getFirstIterator(c.Count)
   151  				its = append(its, downsample.NewAverageChunkIterator(cnt, sum))
   152  			}
   153  		}
   154  		sit = newChunkSeriesIterator(its)
   155  	default:
   156  		return errSeriesIterator{err: errors.Errorf("unexpected result aggregate type %v", s.aggrs)}
   157  	}
   158  	return dedup.NewBoundedSeriesIterator(sit, s.mint, s.maxt)
   159  }
   160  
   161  func getFirstIterator(cs ...*storepb.Chunk) chunkenc.Iterator {
   162  	for _, c := range cs {
   163  		if c == nil {
   164  			continue
   165  		}
   166  		chk, err := chunkenc.FromData(chunkEncoding(c.Type), c.Data)
   167  		if err != nil {
   168  			return errSeriesIterator{err}
   169  		}
   170  		return chk.Iterator(nil)
   171  	}
   172  	return errSeriesIterator{errors.New("no valid chunk found")}
   173  }
   174  
   175  func chunkEncoding(e storepb.Chunk_Encoding) chunkenc.Encoding {
   176  	switch e {
   177  	case storepb.Chunk_XOR:
   178  		return chunkenc.EncXOR
   179  	case storepb.Chunk_HISTOGRAM:
   180  		return chunkenc.EncHistogram
   181  	case storepb.Chunk_FLOAT_HISTOGRAM:
   182  		return chunkenc.EncFloatHistogram
   183  	}
   184  	return 255 // Invalid.
   185  }
   186  
   187  type errSeriesIterator struct {
   188  	err error
   189  }
   190  
   191  func (errSeriesIterator) Seek(int64) chunkenc.ValueType                        { return chunkenc.ValNone }
   192  func (errSeriesIterator) Next() chunkenc.ValueType                             { return chunkenc.ValNone }
   193  func (errSeriesIterator) At() (int64, float64)                                 { return 0, 0 }
   194  func (errSeriesIterator) AtHistogram() (int64, *histogram.Histogram)           { return 0, nil }
   195  func (errSeriesIterator) AtFloatHistogram() (int64, *histogram.FloatHistogram) { return 0, nil }
   196  func (errSeriesIterator) AtT() int64                                           { return 0 }
   197  func (it errSeriesIterator) Err() error                                        { return it.err }
   198  
   199  // chunkSeriesIterator implements a series iterator on top
   200  // of a list of time-sorted, non-overlapping chunks.
   201  type chunkSeriesIterator struct {
   202  	chunks  []chunkenc.Iterator
   203  	i       int
   204  	lastVal chunkenc.ValueType
   205  }
   206  
   207  func newChunkSeriesIterator(cs []chunkenc.Iterator) chunkenc.Iterator {
   208  	if len(cs) == 0 {
   209  		// This should not happen. StoreAPI implementations should not send empty results.
   210  		return errSeriesIterator{err: errors.Errorf("store returned an empty result")}
   211  	}
   212  	return &chunkSeriesIterator{chunks: cs}
   213  }
   214  
   215  func (it *chunkSeriesIterator) Seek(t int64) chunkenc.ValueType {
   216  	// We generally expect the chunks already to be cut down
   217  	// to the range we are interested in. There's not much to be gained from
   218  	// hopping across chunks so we just call next until we reach t.
   219  	for {
   220  		ct := it.AtT()
   221  		if ct >= t {
   222  			return it.lastVal
   223  		}
   224  		it.lastVal = it.Next()
   225  		if it.lastVal == chunkenc.ValNone {
   226  			return chunkenc.ValNone
   227  		}
   228  	}
   229  }
   230  
   231  func (it *chunkSeriesIterator) At() (t int64, v float64) {
   232  	return it.chunks[it.i].At()
   233  }
   234  
   235  func (it *chunkSeriesIterator) AtHistogram() (int64, *histogram.Histogram) {
   236  	return it.chunks[it.i].AtHistogram()
   237  }
   238  
   239  func (it *chunkSeriesIterator) AtFloatHistogram() (int64, *histogram.FloatHistogram) {
   240  	return it.chunks[it.i].AtFloatHistogram()
   241  }
   242  
   243  func (it *chunkSeriesIterator) AtT() int64 {
   244  	return it.chunks[it.i].AtT()
   245  }
   246  
   247  func (it *chunkSeriesIterator) Next() chunkenc.ValueType {
   248  	lastT := it.AtT()
   249  
   250  	if valueType := it.chunks[it.i].Next(); valueType != chunkenc.ValNone {
   251  		it.lastVal = valueType
   252  		return valueType
   253  	}
   254  	if it.Err() != nil {
   255  		return chunkenc.ValNone
   256  	}
   257  	if it.i >= len(it.chunks)-1 {
   258  		return chunkenc.ValNone
   259  	}
   260  	// Chunks are guaranteed to be ordered but not generally guaranteed to not overlap.
   261  	// We must ensure to skip any overlapping range between adjacent chunks.
   262  	it.i++
   263  	return it.Seek(lastT + 1)
   264  }
   265  
   266  func (it *chunkSeriesIterator) Err() error {
   267  	return it.chunks[it.i].Err()
   268  }
   269  
   270  type lazySeriesSet struct {
   271  	create func() (s storage.SeriesSet, ok bool)
   272  
   273  	set storage.SeriesSet
   274  }
   275  
   276  func (c *lazySeriesSet) Next() bool {
   277  	if c.set != nil {
   278  		return c.set.Next()
   279  	}
   280  
   281  	var ok bool
   282  	c.set, ok = c.create()
   283  	return ok
   284  }
   285  
   286  func (c *lazySeriesSet) Err() error {
   287  	if c.set != nil {
   288  		return c.set.Err()
   289  	}
   290  	return nil
   291  }
   292  
   293  func (c *lazySeriesSet) At() storage.Series {
   294  	if c.set != nil {
   295  		return c.set.At()
   296  	}
   297  	return nil
   298  }
   299  
   300  func (c *lazySeriesSet) Warnings() storage.Warnings {
   301  	if c.set != nil {
   302  		return c.set.Warnings()
   303  	}
   304  	return nil
   305  }