github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/storage/stores/series/index/schema_test.go (about)

     1  package index
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"testing"
     7  
     8  	jsoniter "github.com/json-iterator/go"
     9  	"github.com/prometheus/common/model"
    10  	"github.com/prometheus/prometheus/model/labels"
    11  	"github.com/prometheus/prometheus/promql/parser"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/grafana/loki/pkg/querier/astmapper"
    16  	"github.com/grafana/loki/pkg/storage/config"
    17  )
    18  
    19  func TestDailyBuckets(t *testing.T) {
    20  	const (
    21  		userID     = "0"
    22  		metricName = model.LabelValue("name")
    23  		tableName  = "table"
    24  	)
    25  	cfg := config.PeriodConfig{
    26  		IndexTables: config.PeriodicTableConfig{Prefix: tableName},
    27  	}
    28  
    29  	type args struct {
    30  		from    model.Time
    31  		through model.Time
    32  	}
    33  	tests := []struct {
    34  		name string
    35  		args args
    36  		want []Bucket
    37  	}{
    38  		{
    39  			"0 day window",
    40  			args{
    41  				from:    model.TimeFromUnix(0),
    42  				through: model.TimeFromUnix(0),
    43  			},
    44  			[]Bucket{{
    45  				from:       0,
    46  				through:    0,
    47  				tableName:  "table",
    48  				hashKey:    "0:d0",
    49  				bucketSize: uint32(millisecondsInDay),
    50  			}},
    51  		},
    52  		{
    53  			"6 hour window",
    54  			args{
    55  				from:    model.TimeFromUnix(0),
    56  				through: model.TimeFromUnix(6 * 3600),
    57  			},
    58  			[]Bucket{{
    59  				from:       0,
    60  				through:    (6 * 3600) * 1000, // ms
    61  				tableName:  "table",
    62  				hashKey:    "0:d0",
    63  				bucketSize: uint32(millisecondsInDay),
    64  			}},
    65  		},
    66  		{
    67  			"1 day window",
    68  			args{
    69  				from:    model.TimeFromUnix(0),
    70  				through: model.TimeFromUnix(24 * 3600),
    71  			},
    72  			[]Bucket{{
    73  				from:       0,
    74  				through:    (24 * 3600) * 1000, // ms
    75  				tableName:  "table",
    76  				hashKey:    "0:d0",
    77  				bucketSize: uint32(millisecondsInDay),
    78  			}, {
    79  				from:       0,
    80  				through:    0,
    81  				tableName:  "table",
    82  				hashKey:    "0:d1",
    83  				bucketSize: uint32(millisecondsInDay),
    84  			}},
    85  		},
    86  		{
    87  			"window spanning 3 days with non-zero start",
    88  			args{
    89  				from:    model.TimeFromUnix(6 * 3600),
    90  				through: model.TimeFromUnix((2 * 24 * 3600) + (12 * 3600)),
    91  			},
    92  			[]Bucket{{
    93  				from:       (6 * 3600) * 1000,  // ms
    94  				through:    (24 * 3600) * 1000, // ms
    95  				tableName:  "table",
    96  				hashKey:    "0:d0",
    97  				bucketSize: uint32(millisecondsInDay),
    98  			}, {
    99  				from:       0,
   100  				through:    (24 * 3600) * 1000, // ms
   101  				tableName:  "table",
   102  				hashKey:    "0:d1",
   103  				bucketSize: uint32(millisecondsInDay),
   104  			}, {
   105  				from:       0,
   106  				through:    (12 * 3600) * 1000, // ms
   107  				tableName:  "table",
   108  				hashKey:    "0:d2",
   109  				bucketSize: uint32(millisecondsInDay),
   110  			}},
   111  		},
   112  	}
   113  	for _, tt := range tests {
   114  		t.Run(tt.name, func(t *testing.T) {
   115  			got := dailyBuckets(cfg)(tt.args.from, tt.args.through, userID)
   116  			assert.Equal(t, tt.want, got)
   117  		})
   118  	}
   119  }
   120  
   121  type ByHashRangeKey []Entry
   122  
   123  func (a ByHashRangeKey) Len() int      { return len(a) }
   124  func (a ByHashRangeKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
   125  func (a ByHashRangeKey) Less(i, j int) bool {
   126  	if a[i].HashValue != a[j].HashValue {
   127  		return a[i].HashValue < a[j].HashValue
   128  	}
   129  	return bytes.Compare(a[i].RangeValue, a[j].RangeValue) < 0
   130  }
   131  
   132  const table = "table"
   133  
   134  func mustMakeSchema(schemaName string) SeriesStoreSchema {
   135  	s, err := CreateSchema(config.PeriodConfig{
   136  		Schema:      schemaName,
   137  		IndexTables: config.PeriodicTableConfig{Prefix: table},
   138  	})
   139  	if err != nil {
   140  		panic(err)
   141  	}
   142  	return s
   143  }
   144  
   145  // range value types
   146  const (
   147  	_ = iota
   148  	MetricNameRangeValue
   149  	ChunkTimeRangeValue
   150  	SeriesRangeValue
   151  )
   152  
   153  func BenchmarkEncodeLabelsJson(b *testing.B) {
   154  	decoded := &labels.Labels{}
   155  	lbs := labels.FromMap(map[string]string{
   156  		"foo":      "bar",
   157  		"fuzz":     "buzz",
   158  		"cluster":  "test",
   159  		"test":     "test1",
   160  		"instance": "cortex-01",
   161  		"bar":      "foo",
   162  		"version":  "0.1",
   163  	})
   164  	json := jsoniter.ConfigFastest
   165  	var data []byte
   166  	var err error
   167  	for n := 0; n < b.N; n++ {
   168  		data, err = json.Marshal(lbs)
   169  		if err != nil {
   170  			panic(err)
   171  		}
   172  		err = json.Unmarshal(data, decoded)
   173  		if err != nil {
   174  			panic(err)
   175  		}
   176  	}
   177  	b.Log("data size", len(data))
   178  	b.Log("decode", decoded)
   179  }
   180  
   181  func BenchmarkEncodeLabelsString(b *testing.B) {
   182  	var decoded labels.Labels
   183  	lbs := labels.FromMap(map[string]string{
   184  		"foo":      "bar",
   185  		"fuzz":     "buzz",
   186  		"cluster":  "test",
   187  		"test":     "test1",
   188  		"instance": "cortex-01",
   189  		"bar":      "foo",
   190  		"version":  "0.1",
   191  	})
   192  	var data []byte
   193  	var err error
   194  	for n := 0; n < b.N; n++ {
   195  		data = []byte(lbs.String())
   196  		decoded, err = parser.ParseMetric(string(data))
   197  		if err != nil {
   198  			panic(err)
   199  		}
   200  	}
   201  	b.Log("data size", len(data))
   202  	b.Log("decode", decoded)
   203  }
   204  
   205  func TestV10IndexQueries(t *testing.T) {
   206  	fromShards := func(n int) (res []Query) {
   207  		for i := 0; i < n; i++ {
   208  			res = append(res, Query{
   209  				TableName:       "tbl",
   210  				HashValue:       fmt.Sprintf("%02d:%s:%s:%s", i, "hash", "metric", "label"),
   211  				RangeValueStart: []byte(fmt.Sprint(i)),
   212  				ValueEqual:      []byte(fmt.Sprint(i)),
   213  			})
   214  		}
   215  		return res
   216  	}
   217  
   218  	testExprs := []struct {
   219  		name     string
   220  		queries  []Query
   221  		shard    *astmapper.ShardAnnotation
   222  		expected []Query
   223  	}{
   224  		{
   225  			name:     "passthrough when no shard specified",
   226  			queries:  fromShards(2),
   227  			shard:    nil,
   228  			expected: fromShards(2),
   229  		},
   230  		{
   231  			name:    "out of bounds shard returns 0 matches",
   232  			queries: fromShards(2),
   233  			shard: &astmapper.ShardAnnotation{
   234  				Shard: 3,
   235  			},
   236  			expected: nil,
   237  		},
   238  		{
   239  			name:    "return correct shard",
   240  			queries: fromShards(3),
   241  			shard: &astmapper.ShardAnnotation{
   242  				Shard: 1,
   243  			},
   244  			expected: []Query{fromShards(2)[1]},
   245  		},
   246  	}
   247  
   248  	for _, c := range testExprs {
   249  		t.Run(c.name, func(t *testing.T) {
   250  			s := v10Entries{}
   251  			filtered := s.FilterReadQueries(c.queries, c.shard)
   252  			require.Equal(t, c.expected, filtered)
   253  		})
   254  	}
   255  }