github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/querier/queryrange/queryrangebase/test_utils.go (about)

     1  package queryrangebase
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/pkg/errors"
     9  	"github.com/prometheus/common/model"
    10  	"github.com/prometheus/prometheus/model/labels"
    11  	"github.com/prometheus/prometheus/storage"
    12  
    13  	"github.com/grafana/loki/pkg/querier/astmapper"
    14  	"github.com/grafana/loki/pkg/querier/series"
    15  )
    16  
    17  // genLabels will create a slice of labels where each label has an equal chance to occupy a value from [0,labelBuckets]. It returns a slice of length labelBuckets^len(labelSet)
    18  func genLabels(
    19  	labelSet []string,
    20  	labelBuckets int,
    21  ) (result []labels.Labels) {
    22  	if len(labelSet) == 0 {
    23  		return result
    24  	}
    25  
    26  	l := labelSet[0]
    27  	rest := genLabels(labelSet[1:], labelBuckets)
    28  
    29  	for i := 0; i < labelBuckets; i++ {
    30  		x := labels.Label{
    31  			Name:  l,
    32  			Value: fmt.Sprintf("%d", i),
    33  		}
    34  		if len(rest) == 0 {
    35  			set := labels.Labels{x}
    36  			result = append(result, set)
    37  			continue
    38  		}
    39  		for _, others := range rest {
    40  			set := append(others, x)
    41  			result = append(result, set)
    42  		}
    43  	}
    44  	return result
    45  
    46  }
    47  
    48  // NewMockShardedQueryable creates a shard-aware in memory queryable.
    49  func NewMockShardedQueryable(
    50  	nSamples int,
    51  	labelSet []string,
    52  	labelBuckets int,
    53  	delayPerSeries time.Duration,
    54  ) *MockShardedQueryable {
    55  	samples := make([]model.SamplePair, 0, nSamples)
    56  	for i := 0; i < nSamples; i++ {
    57  		samples = append(samples, model.SamplePair{
    58  			Timestamp: model.Time(i * 1000),
    59  			Value:     model.SampleValue(i),
    60  		})
    61  	}
    62  	sets := genLabels(labelSet, labelBuckets)
    63  	xs := make([]storage.Series, 0, len(sets))
    64  	for _, ls := range sets {
    65  		xs = append(xs, series.NewConcreteSeries(ls, samples))
    66  	}
    67  
    68  	return &MockShardedQueryable{
    69  		series:         xs,
    70  		delayPerSeries: delayPerSeries,
    71  	}
    72  }
    73  
    74  // MockShardedQueryable is exported to be reused in the querysharding benchmarking
    75  type MockShardedQueryable struct {
    76  	series         []storage.Series
    77  	delayPerSeries time.Duration
    78  }
    79  
    80  // Querier impls storage.Queryable
    81  func (q *MockShardedQueryable) Querier(ctx context.Context, mint, maxt int64) (storage.Querier, error) {
    82  	return q, nil
    83  }
    84  
    85  // Select implements storage.Querier interface.
    86  // The bool passed is ignored because the series is always sorted.
    87  func (q *MockShardedQueryable) Select(_ bool, _ *storage.SelectHints, matchers ...*labels.Matcher) storage.SeriesSet {
    88  	tStart := time.Now()
    89  
    90  	shard, _, err := astmapper.ShardFromMatchers(matchers)
    91  	if err != nil {
    92  		return storage.ErrSeriesSet(err)
    93  	}
    94  
    95  	var (
    96  		start int
    97  		end   int
    98  	)
    99  
   100  	if shard == nil {
   101  		start = 0
   102  		end = len(q.series)
   103  	} else {
   104  		// return the series range associated with this shard
   105  		seriesPerShard := len(q.series) / shard.Of
   106  		start = shard.Shard * seriesPerShard
   107  		end = start + seriesPerShard
   108  
   109  		// if we're clipping an odd # of series, add the final series to the last shard
   110  		if end == len(q.series)-1 && len(q.series)%2 == 1 {
   111  			end = len(q.series)
   112  		}
   113  	}
   114  
   115  	var name string
   116  	for _, m := range matchers {
   117  		if m.Type == labels.MatchEqual && m.Name == "__name__" {
   118  			name = m.Value
   119  		}
   120  	}
   121  
   122  	results := make([]storage.Series, 0, end-start)
   123  	for i := start; i < end; i++ {
   124  		results = append(results, &ShardLabelSeries{
   125  			shard:  shard,
   126  			name:   name,
   127  			Series: q.series[i],
   128  		})
   129  	}
   130  
   131  	// loosely enforce the assumption that an operation on 1/nth of the data
   132  	// takes 1/nth of the time.
   133  	duration := q.delayPerSeries * time.Duration(len(q.series))
   134  	if shard != nil {
   135  		duration = duration / time.Duration(shard.Of)
   136  	}
   137  
   138  	remaining := time.Until(tStart.Add(duration))
   139  	if remaining > 0 {
   140  		time.Sleep(remaining)
   141  	}
   142  
   143  	// sorted
   144  	return series.NewConcreteSeriesSet(results)
   145  }
   146  
   147  // ShardLabelSeries allows extending a Series with new labels. This is helpful for adding cortex shard labels
   148  type ShardLabelSeries struct {
   149  	shard *astmapper.ShardAnnotation
   150  	name  string
   151  	storage.Series
   152  }
   153  
   154  // Labels impls storage.Series
   155  func (s *ShardLabelSeries) Labels() labels.Labels {
   156  	ls := s.Series.Labels()
   157  
   158  	if s.name != "" {
   159  		ls = append(ls, labels.Label{
   160  			Name:  "__name__",
   161  			Value: s.name,
   162  		})
   163  	}
   164  
   165  	if s.shard != nil {
   166  		ls = append(ls, s.shard.Label())
   167  	}
   168  
   169  	return ls
   170  }
   171  
   172  // LabelValues impls storage.Querier
   173  func (q *MockShardedQueryable) LabelValues(name string, matchers ...*labels.Matcher) ([]string, storage.Warnings, error) {
   174  	return nil, nil, errors.Errorf("unimplemented")
   175  }
   176  
   177  // LabelNames returns all the unique label names present in the block in sorted order.
   178  func (q *MockShardedQueryable) LabelNames(matchers ...*labels.Matcher) ([]string, storage.Warnings, error) {
   179  	return nil, nil, errors.Errorf("unimplemented")
   180  }
   181  
   182  // Close releases the resources of the Querier.
   183  func (q *MockShardedQueryable) Close() error {
   184  	return nil
   185  }