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

     1  // Copyright 2017 The Prometheus Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package index
    15  
    16  import (
    17  	"encoding/binary"
    18  	"fmt"
    19  	"math/rand"
    20  	"sort"
    21  	"strconv"
    22  	"testing"
    23  
    24  	"github.com/stretchr/testify/require"
    25  
    26  	"github.com/prometheus/prometheus/model/labels"
    27  	"github.com/prometheus/prometheus/storage"
    28  )
    29  
    30  func TestMemPostings_addFor(t *testing.T) {
    31  	p := NewMemPostings()
    32  	p.m[allPostingsKey.Name] = map[string][]storage.SeriesRef{}
    33  	p.m[allPostingsKey.Name][allPostingsKey.Value] = []storage.SeriesRef{1, 2, 3, 4, 6, 7, 8}
    34  
    35  	p.addFor(5, allPostingsKey)
    36  
    37  	require.Equal(t, []storage.SeriesRef{1, 2, 3, 4, 5, 6, 7, 8}, p.m[allPostingsKey.Name][allPostingsKey.Value])
    38  }
    39  
    40  func TestMemPostings_ensureOrder(t *testing.T) {
    41  	p := NewUnorderedMemPostings()
    42  	p.m["a"] = map[string][]storage.SeriesRef{}
    43  
    44  	for i := 0; i < 100; i++ {
    45  		l := make([]storage.SeriesRef, 100)
    46  		for j := range l {
    47  			l[j] = storage.SeriesRef(rand.Uint64())
    48  		}
    49  		v := fmt.Sprintf("%d", i)
    50  
    51  		p.m["a"][v] = l
    52  	}
    53  
    54  	p.EnsureOrder()
    55  
    56  	for _, e := range p.m {
    57  		for _, l := range e {
    58  			ok := sort.SliceIsSorted(l, func(i, j int) bool {
    59  				return l[i] < l[j]
    60  			})
    61  			if !ok {
    62  				t.Fatalf("postings list %v is not sorted", l)
    63  			}
    64  		}
    65  	}
    66  }
    67  
    68  func BenchmarkMemPostings_ensureOrder(b *testing.B) {
    69  	tests := map[string]struct {
    70  		numLabels         int
    71  		numValuesPerLabel int
    72  		numRefsPerValue   int
    73  	}{
    74  		"many values per label": {
    75  			numLabels:         100,
    76  			numValuesPerLabel: 10000,
    77  			numRefsPerValue:   100,
    78  		},
    79  		"few values per label": {
    80  			numLabels:         1000000,
    81  			numValuesPerLabel: 1,
    82  			numRefsPerValue:   100,
    83  		},
    84  		"few refs per label value": {
    85  			numLabels:         1000,
    86  			numValuesPerLabel: 1000,
    87  			numRefsPerValue:   10,
    88  		},
    89  	}
    90  
    91  	for testName, testData := range tests {
    92  		b.Run(testName, func(b *testing.B) {
    93  			p := NewUnorderedMemPostings()
    94  
    95  			// Generate postings.
    96  			for l := 0; l < testData.numLabels; l++ {
    97  				labelName := strconv.Itoa(l)
    98  				p.m[labelName] = map[string][]storage.SeriesRef{}
    99  
   100  				for v := 0; v < testData.numValuesPerLabel; v++ {
   101  					refs := make([]storage.SeriesRef, testData.numRefsPerValue)
   102  					for j := range refs {
   103  						refs[j] = storage.SeriesRef(rand.Uint64())
   104  					}
   105  
   106  					labelValue := strconv.Itoa(v)
   107  					p.m[labelName][labelValue] = refs
   108  				}
   109  			}
   110  
   111  			b.ResetTimer()
   112  
   113  			for n := 0; n < b.N; n++ {
   114  				p.EnsureOrder()
   115  				p.ordered = false
   116  			}
   117  		})
   118  	}
   119  }
   120  
   121  func TestIntersect(t *testing.T) {
   122  	a := newListPostings(1, 2, 3)
   123  	b := newListPostings(2, 3, 4)
   124  
   125  	cases := []struct {
   126  		in []Postings
   127  
   128  		res Postings
   129  	}{
   130  		{
   131  			in:  []Postings{},
   132  			res: EmptyPostings(),
   133  		},
   134  		{
   135  			in:  []Postings{a, b, EmptyPostings()},
   136  			res: EmptyPostings(),
   137  		},
   138  		{
   139  			in:  []Postings{b, a, EmptyPostings()},
   140  			res: EmptyPostings(),
   141  		},
   142  		{
   143  			in:  []Postings{EmptyPostings(), b, a},
   144  			res: EmptyPostings(),
   145  		},
   146  		{
   147  			in:  []Postings{EmptyPostings(), a, b},
   148  			res: EmptyPostings(),
   149  		},
   150  		{
   151  			in:  []Postings{a, EmptyPostings(), b},
   152  			res: EmptyPostings(),
   153  		},
   154  		{
   155  			in:  []Postings{b, EmptyPostings(), a},
   156  			res: EmptyPostings(),
   157  		},
   158  		{
   159  			in:  []Postings{b, EmptyPostings(), a, a, b, a, a, a},
   160  			res: EmptyPostings(),
   161  		},
   162  		{
   163  			in: []Postings{
   164  				newListPostings(1, 2, 3, 4, 5),
   165  				newListPostings(6, 7, 8, 9, 10),
   166  			},
   167  			res: newListPostings(),
   168  		},
   169  		{
   170  			in: []Postings{
   171  				newListPostings(1, 2, 3, 4, 5),
   172  				newListPostings(4, 5, 6, 7, 8),
   173  			},
   174  			res: newListPostings(4, 5),
   175  		},
   176  		{
   177  			in: []Postings{
   178  				newListPostings(1, 2, 3, 4, 9, 10),
   179  				newListPostings(1, 4, 5, 6, 7, 8, 10, 11),
   180  			},
   181  			res: newListPostings(1, 4, 10),
   182  		},
   183  		{
   184  			in: []Postings{
   185  				newListPostings(1),
   186  				newListPostings(0, 1),
   187  			},
   188  			res: newListPostings(1),
   189  		},
   190  		{
   191  			in: []Postings{
   192  				newListPostings(1),
   193  			},
   194  			res: newListPostings(1),
   195  		},
   196  		{
   197  			in: []Postings{
   198  				newListPostings(1),
   199  				newListPostings(),
   200  			},
   201  			res: newListPostings(),
   202  		},
   203  		{
   204  			in: []Postings{
   205  				newListPostings(),
   206  				newListPostings(),
   207  			},
   208  			res: newListPostings(),
   209  		},
   210  	}
   211  
   212  	for _, c := range cases {
   213  		t.Run("", func(t *testing.T) {
   214  			if c.res == nil {
   215  				t.Fatal("intersect result expectancy cannot be nil")
   216  			}
   217  
   218  			expected, err := ExpandPostings(c.res)
   219  			require.NoError(t, err)
   220  
   221  			i := Intersect(c.in...)
   222  
   223  			if c.res == EmptyPostings() {
   224  				require.Equal(t, EmptyPostings(), i)
   225  				return
   226  			}
   227  
   228  			if i == EmptyPostings() {
   229  				t.Fatal("intersect unexpected result: EmptyPostings sentinel")
   230  			}
   231  
   232  			res, err := ExpandPostings(i)
   233  			require.NoError(t, err)
   234  			require.Equal(t, expected, res)
   235  		})
   236  	}
   237  }
   238  
   239  func TestMultiIntersect(t *testing.T) {
   240  	cases := []struct {
   241  		p   [][]storage.SeriesRef
   242  		res []storage.SeriesRef
   243  	}{
   244  		{
   245  			p: [][]storage.SeriesRef{
   246  				{1, 2, 3, 4, 5, 6, 1000, 1001},
   247  				{2, 4, 5, 6, 7, 8, 999, 1001},
   248  				{1, 2, 5, 6, 7, 8, 1001, 1200},
   249  			},
   250  			res: []storage.SeriesRef{2, 5, 6, 1001},
   251  		},
   252  		// One of the reproducible cases for:
   253  		// https://github.com/prometheus/prometheus/issues/2616
   254  		// The initialisation of intersectPostings was moving the iterator forward
   255  		// prematurely making us miss some postings.
   256  		{
   257  			p: [][]storage.SeriesRef{
   258  				{1, 2},
   259  				{1, 2},
   260  				{1, 2},
   261  				{2},
   262  			},
   263  			res: []storage.SeriesRef{2},
   264  		},
   265  	}
   266  
   267  	for _, c := range cases {
   268  		ps := make([]Postings, 0, len(c.p))
   269  		for _, postings := range c.p {
   270  			ps = append(ps, newListPostings(postings...))
   271  		}
   272  
   273  		res, err := ExpandPostings(Intersect(ps...))
   274  
   275  		require.NoError(t, err)
   276  		require.Equal(t, c.res, res)
   277  	}
   278  }
   279  
   280  func BenchmarkIntersect(t *testing.B) {
   281  	t.Run("LongPostings1", func(bench *testing.B) {
   282  		var a, b, c, d []storage.SeriesRef
   283  
   284  		for i := 0; i < 10000000; i += 2 {
   285  			a = append(a, storage.SeriesRef(i))
   286  		}
   287  		for i := 5000000; i < 5000100; i += 4 {
   288  			b = append(b, storage.SeriesRef(i))
   289  		}
   290  		for i := 5090000; i < 5090600; i += 4 {
   291  			b = append(b, storage.SeriesRef(i))
   292  		}
   293  		for i := 4990000; i < 5100000; i++ {
   294  			c = append(c, storage.SeriesRef(i))
   295  		}
   296  		for i := 4000000; i < 6000000; i++ {
   297  			d = append(d, storage.SeriesRef(i))
   298  		}
   299  
   300  		i1 := newListPostings(a...)
   301  		i2 := newListPostings(b...)
   302  		i3 := newListPostings(c...)
   303  		i4 := newListPostings(d...)
   304  
   305  		bench.ResetTimer()
   306  		bench.ReportAllocs()
   307  		for i := 0; i < bench.N; i++ {
   308  			if _, err := ExpandPostings(Intersect(i1, i2, i3, i4)); err != nil {
   309  				bench.Fatal(err)
   310  			}
   311  		}
   312  	})
   313  
   314  	t.Run("LongPostings2", func(bench *testing.B) {
   315  		var a, b, c, d []storage.SeriesRef
   316  
   317  		for i := 0; i < 12500000; i++ {
   318  			a = append(a, storage.SeriesRef(i))
   319  		}
   320  		for i := 7500000; i < 12500000; i++ {
   321  			b = append(b, storage.SeriesRef(i))
   322  		}
   323  		for i := 9000000; i < 20000000; i++ {
   324  			c = append(c, storage.SeriesRef(i))
   325  		}
   326  		for i := 10000000; i < 12000000; i++ {
   327  			d = append(d, storage.SeriesRef(i))
   328  		}
   329  
   330  		i1 := newListPostings(a...)
   331  		i2 := newListPostings(b...)
   332  		i3 := newListPostings(c...)
   333  		i4 := newListPostings(d...)
   334  
   335  		bench.ResetTimer()
   336  		bench.ReportAllocs()
   337  		for i := 0; i < bench.N; i++ {
   338  			if _, err := ExpandPostings(Intersect(i1, i2, i3, i4)); err != nil {
   339  				bench.Fatal(err)
   340  			}
   341  		}
   342  	})
   343  
   344  	// Many matchers(k >> n).
   345  	t.Run("ManyPostings", func(bench *testing.B) {
   346  		var its []Postings
   347  
   348  		// 100000 matchers(k=100000).
   349  		for i := 0; i < 100000; i++ {
   350  			var temp []storage.SeriesRef
   351  			for j := storage.SeriesRef(1); j < 100; j++ {
   352  				temp = append(temp, j)
   353  			}
   354  			its = append(its, newListPostings(temp...))
   355  		}
   356  
   357  		bench.ResetTimer()
   358  		bench.ReportAllocs()
   359  		for i := 0; i < bench.N; i++ {
   360  			if _, err := ExpandPostings(Intersect(its...)); err != nil {
   361  				bench.Fatal(err)
   362  			}
   363  		}
   364  	})
   365  }
   366  
   367  func TestMultiMerge(t *testing.T) {
   368  	i1 := newListPostings(1, 2, 3, 4, 5, 6, 1000, 1001)
   369  	i2 := newListPostings(2, 4, 5, 6, 7, 8, 999, 1001)
   370  	i3 := newListPostings(1, 2, 5, 6, 7, 8, 1001, 1200)
   371  
   372  	res, err := ExpandPostings(Merge(i1, i2, i3))
   373  	require.NoError(t, err)
   374  	require.Equal(t, []storage.SeriesRef{1, 2, 3, 4, 5, 6, 7, 8, 999, 1000, 1001, 1200}, res)
   375  }
   376  
   377  func TestMergedPostings(t *testing.T) {
   378  	cases := []struct {
   379  		in []Postings
   380  
   381  		res Postings
   382  	}{
   383  		{
   384  			in:  []Postings{},
   385  			res: EmptyPostings(),
   386  		},
   387  		{
   388  			in: []Postings{
   389  				newListPostings(),
   390  				newListPostings(),
   391  			},
   392  			res: EmptyPostings(),
   393  		},
   394  		{
   395  			in: []Postings{
   396  				newListPostings(),
   397  			},
   398  			res: newListPostings(),
   399  		},
   400  		{
   401  			in: []Postings{
   402  				EmptyPostings(),
   403  				EmptyPostings(),
   404  				EmptyPostings(),
   405  				EmptyPostings(),
   406  			},
   407  			res: EmptyPostings(),
   408  		},
   409  		{
   410  			in: []Postings{
   411  				newListPostings(1, 2, 3, 4, 5),
   412  				newListPostings(6, 7, 8, 9, 10),
   413  			},
   414  			res: newListPostings(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
   415  		},
   416  		{
   417  			in: []Postings{
   418  				newListPostings(1, 2, 3, 4, 5),
   419  				newListPostings(4, 5, 6, 7, 8),
   420  			},
   421  			res: newListPostings(1, 2, 3, 4, 5, 6, 7, 8),
   422  		},
   423  		{
   424  			in: []Postings{
   425  				newListPostings(1, 2, 3, 4, 9, 10),
   426  				newListPostings(1, 4, 5, 6, 7, 8, 10, 11),
   427  			},
   428  			res: newListPostings(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   429  		},
   430  		{
   431  			in: []Postings{
   432  				newListPostings(1, 2, 3, 4, 9, 10),
   433  				EmptyPostings(),
   434  				newListPostings(1, 4, 5, 6, 7, 8, 10, 11),
   435  			},
   436  			res: newListPostings(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   437  		},
   438  		{
   439  			in: []Postings{
   440  				newListPostings(1, 2),
   441  				newListPostings(),
   442  			},
   443  			res: newListPostings(1, 2),
   444  		},
   445  		{
   446  			in: []Postings{
   447  				newListPostings(1, 2),
   448  				EmptyPostings(),
   449  			},
   450  			res: newListPostings(1, 2),
   451  		},
   452  	}
   453  
   454  	for _, c := range cases {
   455  		t.Run("", func(t *testing.T) {
   456  			if c.res == nil {
   457  				t.Fatal("merge result expectancy cannot be nil")
   458  			}
   459  
   460  			expected, err := ExpandPostings(c.res)
   461  			require.NoError(t, err)
   462  
   463  			m := Merge(c.in...)
   464  
   465  			if c.res == EmptyPostings() {
   466  				require.Equal(t, EmptyPostings(), m)
   467  				return
   468  			}
   469  
   470  			if m == EmptyPostings() {
   471  				t.Fatal("merge unexpected result: EmptyPostings sentinel")
   472  			}
   473  
   474  			res, err := ExpandPostings(m)
   475  			require.NoError(t, err)
   476  			require.Equal(t, expected, res)
   477  		})
   478  	}
   479  }
   480  
   481  func TestMergedPostingsSeek(t *testing.T) {
   482  	cases := []struct {
   483  		a, b []storage.SeriesRef
   484  
   485  		seek    storage.SeriesRef
   486  		success bool
   487  		res     []storage.SeriesRef
   488  	}{
   489  		{
   490  			a: []storage.SeriesRef{2, 3, 4, 5},
   491  			b: []storage.SeriesRef{6, 7, 8, 9, 10},
   492  
   493  			seek:    1,
   494  			success: true,
   495  			res:     []storage.SeriesRef{2, 3, 4, 5, 6, 7, 8, 9, 10},
   496  		},
   497  		{
   498  			a: []storage.SeriesRef{1, 2, 3, 4, 5},
   499  			b: []storage.SeriesRef{6, 7, 8, 9, 10},
   500  
   501  			seek:    2,
   502  			success: true,
   503  			res:     []storage.SeriesRef{2, 3, 4, 5, 6, 7, 8, 9, 10},
   504  		},
   505  		{
   506  			a: []storage.SeriesRef{1, 2, 3, 4, 5},
   507  			b: []storage.SeriesRef{4, 5, 6, 7, 8},
   508  
   509  			seek:    9,
   510  			success: false,
   511  			res:     nil,
   512  		},
   513  		{
   514  			a: []storage.SeriesRef{1, 2, 3, 4, 9, 10},
   515  			b: []storage.SeriesRef{1, 4, 5, 6, 7, 8, 10, 11},
   516  
   517  			seek:    10,
   518  			success: true,
   519  			res:     []storage.SeriesRef{10, 11},
   520  		},
   521  	}
   522  
   523  	for _, c := range cases {
   524  		a := newListPostings(c.a...)
   525  		b := newListPostings(c.b...)
   526  
   527  		p := Merge(a, b)
   528  
   529  		require.Equal(t, c.success, p.Seek(c.seek))
   530  
   531  		// After Seek(), At() should be called.
   532  		if c.success {
   533  			start := p.At()
   534  			lst, err := ExpandPostings(p)
   535  			require.NoError(t, err)
   536  
   537  			lst = append([]storage.SeriesRef{start}, lst...)
   538  			require.Equal(t, c.res, lst)
   539  		}
   540  	}
   541  }
   542  
   543  func TestRemovedPostings(t *testing.T) {
   544  	cases := []struct {
   545  		a, b []storage.SeriesRef
   546  		res  []storage.SeriesRef
   547  	}{
   548  		{
   549  			a:   nil,
   550  			b:   nil,
   551  			res: []storage.SeriesRef(nil),
   552  		},
   553  		{
   554  			a:   []storage.SeriesRef{1, 2, 3, 4},
   555  			b:   nil,
   556  			res: []storage.SeriesRef{1, 2, 3, 4},
   557  		},
   558  		{
   559  			a:   nil,
   560  			b:   []storage.SeriesRef{1, 2, 3, 4},
   561  			res: []storage.SeriesRef(nil),
   562  		},
   563  		{
   564  			a:   []storage.SeriesRef{1, 2, 3, 4, 5},
   565  			b:   []storage.SeriesRef{6, 7, 8, 9, 10},
   566  			res: []storage.SeriesRef{1, 2, 3, 4, 5},
   567  		},
   568  		{
   569  			a:   []storage.SeriesRef{1, 2, 3, 4, 5},
   570  			b:   []storage.SeriesRef{4, 5, 6, 7, 8},
   571  			res: []storage.SeriesRef{1, 2, 3},
   572  		},
   573  		{
   574  			a:   []storage.SeriesRef{1, 2, 3, 4, 9, 10},
   575  			b:   []storage.SeriesRef{1, 4, 5, 6, 7, 8, 10, 11},
   576  			res: []storage.SeriesRef{2, 3, 9},
   577  		},
   578  		{
   579  			a:   []storage.SeriesRef{1, 2, 3, 4, 9, 10},
   580  			b:   []storage.SeriesRef{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
   581  			res: []storage.SeriesRef(nil),
   582  		},
   583  	}
   584  
   585  	for _, c := range cases {
   586  		a := newListPostings(c.a...)
   587  		b := newListPostings(c.b...)
   588  
   589  		res, err := ExpandPostings(newRemovedPostings(a, b))
   590  		require.NoError(t, err)
   591  		require.Equal(t, c.res, res)
   592  	}
   593  }
   594  
   595  func TestRemovedNextStackoverflow(t *testing.T) {
   596  	var full []storage.SeriesRef
   597  	var remove []storage.SeriesRef
   598  
   599  	var i storage.SeriesRef
   600  	for i = 0; i < 1e7; i++ {
   601  		full = append(full, i)
   602  		remove = append(remove, i)
   603  	}
   604  
   605  	flp := newListPostings(full...)
   606  	rlp := newListPostings(remove...)
   607  	rp := newRemovedPostings(flp, rlp)
   608  	gotElem := false
   609  	for rp.Next() {
   610  		gotElem = true
   611  	}
   612  
   613  	require.NoError(t, rp.Err())
   614  	require.False(t, gotElem)
   615  }
   616  
   617  func TestRemovedPostingsSeek(t *testing.T) {
   618  	cases := []struct {
   619  		a, b []storage.SeriesRef
   620  
   621  		seek    storage.SeriesRef
   622  		success bool
   623  		res     []storage.SeriesRef
   624  	}{
   625  		{
   626  			a: []storage.SeriesRef{2, 3, 4, 5},
   627  			b: []storage.SeriesRef{6, 7, 8, 9, 10},
   628  
   629  			seek:    1,
   630  			success: true,
   631  			res:     []storage.SeriesRef{2, 3, 4, 5},
   632  		},
   633  		{
   634  			a: []storage.SeriesRef{1, 2, 3, 4, 5},
   635  			b: []storage.SeriesRef{6, 7, 8, 9, 10},
   636  
   637  			seek:    2,
   638  			success: true,
   639  			res:     []storage.SeriesRef{2, 3, 4, 5},
   640  		},
   641  		{
   642  			a: []storage.SeriesRef{1, 2, 3, 4, 5},
   643  			b: []storage.SeriesRef{4, 5, 6, 7, 8},
   644  
   645  			seek:    9,
   646  			success: false,
   647  			res:     nil,
   648  		},
   649  		{
   650  			a: []storage.SeriesRef{1, 2, 3, 4, 9, 10},
   651  			b: []storage.SeriesRef{1, 4, 5, 6, 7, 8, 10, 11},
   652  
   653  			seek:    10,
   654  			success: false,
   655  			res:     nil,
   656  		},
   657  		{
   658  			a: []storage.SeriesRef{1, 2, 3, 4, 9, 10},
   659  			b: []storage.SeriesRef{1, 4, 5, 6, 7, 8, 11},
   660  
   661  			seek:    4,
   662  			success: true,
   663  			res:     []storage.SeriesRef{9, 10},
   664  		},
   665  		{
   666  			a: []storage.SeriesRef{1, 2, 3, 4, 9, 10},
   667  			b: []storage.SeriesRef{1, 4, 5, 6, 7, 8, 11},
   668  
   669  			seek:    5,
   670  			success: true,
   671  			res:     []storage.SeriesRef{9, 10},
   672  		},
   673  		{
   674  			a: []storage.SeriesRef{1, 2, 3, 4, 9, 10},
   675  			b: []storage.SeriesRef{1, 4, 5, 6, 7, 8, 11},
   676  
   677  			seek:    10,
   678  			success: true,
   679  			res:     []storage.SeriesRef{10},
   680  		},
   681  	}
   682  
   683  	for _, c := range cases {
   684  		a := newListPostings(c.a...)
   685  		b := newListPostings(c.b...)
   686  
   687  		p := newRemovedPostings(a, b)
   688  
   689  		require.Equal(t, c.success, p.Seek(c.seek))
   690  
   691  		// After Seek(), At() should be called.
   692  		if c.success {
   693  			start := p.At()
   694  			lst, err := ExpandPostings(p)
   695  			require.NoError(t, err)
   696  
   697  			lst = append([]storage.SeriesRef{start}, lst...)
   698  			require.Equal(t, c.res, lst)
   699  		}
   700  	}
   701  }
   702  
   703  func TestBigEndian(t *testing.T) {
   704  	num := 1000
   705  	// mock a list as postings
   706  	ls := make([]uint32, num)
   707  	ls[0] = 2
   708  	for i := 1; i < num; i++ {
   709  		ls[i] = ls[i-1] + uint32(rand.Int31n(25)) + 2
   710  	}
   711  
   712  	beLst := make([]byte, num*4)
   713  	for i := 0; i < num; i++ {
   714  		b := beLst[i*4 : i*4+4]
   715  		binary.BigEndian.PutUint32(b, ls[i])
   716  	}
   717  
   718  	t.Run("Iteration", func(t *testing.T) {
   719  		bep := newBigEndianPostings(beLst)
   720  		for i := 0; i < num; i++ {
   721  			require.True(t, bep.Next())
   722  			require.Equal(t, storage.SeriesRef(ls[i]), bep.At())
   723  		}
   724  
   725  		require.False(t, bep.Next())
   726  		require.NoError(t, bep.Err())
   727  	})
   728  
   729  	t.Run("Seek", func(t *testing.T) {
   730  		table := []struct {
   731  			seek  uint32
   732  			val   uint32
   733  			found bool
   734  		}{
   735  			{
   736  				ls[0] - 1, ls[0], true,
   737  			},
   738  			{
   739  				ls[4], ls[4], true,
   740  			},
   741  			{
   742  				ls[500] - 1, ls[500], true,
   743  			},
   744  			{
   745  				ls[600] + 1, ls[601], true,
   746  			},
   747  			{
   748  				ls[600] + 1, ls[601], true,
   749  			},
   750  			{
   751  				ls[600] + 1, ls[601], true,
   752  			},
   753  			{
   754  				ls[0], ls[601], true,
   755  			},
   756  			{
   757  				ls[600], ls[601], true,
   758  			},
   759  			{
   760  				ls[999], ls[999], true,
   761  			},
   762  			{
   763  				ls[999] + 10, ls[999], false,
   764  			},
   765  		}
   766  
   767  		bep := newBigEndianPostings(beLst)
   768  
   769  		for _, v := range table {
   770  			require.Equal(t, v.found, bep.Seek(storage.SeriesRef(v.seek)))
   771  			require.Equal(t, storage.SeriesRef(v.val), bep.At())
   772  			require.NoError(t, bep.Err())
   773  		}
   774  	})
   775  }
   776  
   777  func TestIntersectWithMerge(t *testing.T) {
   778  	// One of the reproducible cases for:
   779  	// https://github.com/prometheus/prometheus/issues/2616
   780  	a := newListPostings(21, 22, 23, 24, 25, 30)
   781  
   782  	b := Merge(
   783  		newListPostings(10, 20, 30),
   784  		newListPostings(15, 26, 30),
   785  	)
   786  
   787  	p := Intersect(a, b)
   788  	res, err := ExpandPostings(p)
   789  
   790  	require.NoError(t, err)
   791  	require.Equal(t, []storage.SeriesRef{30}, res)
   792  }
   793  
   794  func TestWithoutPostings(t *testing.T) {
   795  	cases := []struct {
   796  		base Postings
   797  		drop Postings
   798  
   799  		res Postings
   800  	}{
   801  		{
   802  			base: EmptyPostings(),
   803  			drop: EmptyPostings(),
   804  
   805  			res: EmptyPostings(),
   806  		},
   807  		{
   808  			base: EmptyPostings(),
   809  			drop: newListPostings(1, 2),
   810  
   811  			res: EmptyPostings(),
   812  		},
   813  		{
   814  			base: newListPostings(1, 2),
   815  			drop: EmptyPostings(),
   816  
   817  			res: newListPostings(1, 2),
   818  		},
   819  		{
   820  			base: newListPostings(),
   821  			drop: newListPostings(),
   822  
   823  			res: newListPostings(),
   824  		},
   825  		{
   826  			base: newListPostings(1, 2, 3),
   827  			drop: newListPostings(),
   828  
   829  			res: newListPostings(1, 2, 3),
   830  		},
   831  		{
   832  			base: newListPostings(1, 2, 3),
   833  			drop: newListPostings(4, 5, 6),
   834  
   835  			res: newListPostings(1, 2, 3),
   836  		},
   837  		{
   838  			base: newListPostings(1, 2, 3),
   839  			drop: newListPostings(3, 4, 5),
   840  
   841  			res: newListPostings(1, 2),
   842  		},
   843  	}
   844  
   845  	for _, c := range cases {
   846  		t.Run("", func(t *testing.T) {
   847  			if c.res == nil {
   848  				t.Fatal("without result expectancy cannot be nil")
   849  			}
   850  
   851  			expected, err := ExpandPostings(c.res)
   852  			require.NoError(t, err)
   853  
   854  			w := Without(c.base, c.drop)
   855  
   856  			if c.res == EmptyPostings() {
   857  				require.Equal(t, EmptyPostings(), w)
   858  				return
   859  			}
   860  
   861  			if w == EmptyPostings() {
   862  				t.Fatal("without unexpected result: EmptyPostings sentinel")
   863  			}
   864  
   865  			res, err := ExpandPostings(w)
   866  			require.NoError(t, err)
   867  			require.Equal(t, expected, res)
   868  		})
   869  	}
   870  }
   871  
   872  func BenchmarkPostings_Stats(b *testing.B) {
   873  	p := NewMemPostings()
   874  
   875  	var seriesID storage.SeriesRef
   876  
   877  	createPostingsLabelValues := func(name, valuePrefix string, count int) {
   878  		for n := 1; n < count; n++ {
   879  			value := fmt.Sprintf("%s-%d", valuePrefix, n)
   880  			p.Add(seriesID, labels.FromStrings(name, value))
   881  			seriesID++
   882  		}
   883  	}
   884  	createPostingsLabelValues("__name__", "metrics_name_can_be_very_big_and_bad", 1e3)
   885  	for i := 0; i < 20; i++ {
   886  		createPostingsLabelValues(fmt.Sprintf("host-%d", i), "metrics_name_can_be_very_big_and_bad", 1e3)
   887  		createPostingsLabelValues(fmt.Sprintf("instance-%d", i), "10.0.IP.", 1e3)
   888  		createPostingsLabelValues(fmt.Sprintf("job-%d", i), "Small_Job_name", 1e3)
   889  		createPostingsLabelValues(fmt.Sprintf("err-%d", i), "avg_namespace-", 1e3)
   890  		createPostingsLabelValues(fmt.Sprintf("team-%d", i), "team-", 1e3)
   891  		createPostingsLabelValues(fmt.Sprintf("container_name-%d", i), "pod-", 1e3)
   892  		createPostingsLabelValues(fmt.Sprintf("cluster-%d", i), "newcluster-", 1e3)
   893  		createPostingsLabelValues(fmt.Sprintf("uid-%d", i), "123412312312312311-", 1e3)
   894  		createPostingsLabelValues(fmt.Sprintf("area-%d", i), "new_area_of_work-", 1e3)
   895  		createPostingsLabelValues(fmt.Sprintf("request_id-%d", i), "owner_name_work-", 1e3)
   896  	}
   897  	b.ResetTimer()
   898  	for n := 0; n < b.N; n++ {
   899  		p.Stats("__name__")
   900  	}
   901  }
   902  
   903  func TestMemPostings_Delete(t *testing.T) {
   904  	p := NewMemPostings()
   905  	p.Add(1, labels.FromStrings("lbl1", "a"))
   906  	p.Add(2, labels.FromStrings("lbl1", "b"))
   907  	p.Add(3, labels.FromStrings("lbl2", "a"))
   908  
   909  	before := p.Get(allPostingsKey.Name, allPostingsKey.Value)
   910  	p.Delete(map[storage.SeriesRef]struct{}{
   911  		2: {},
   912  	})
   913  	after := p.Get(allPostingsKey.Name, allPostingsKey.Value)
   914  
   915  	// Make sure postings gotten before the delete have the old data when
   916  	// iterated over.
   917  	expanded, err := ExpandPostings(before)
   918  	require.NoError(t, err)
   919  	require.Equal(t, []storage.SeriesRef{1, 2, 3}, expanded)
   920  
   921  	// Make sure postings gotten after the delete have the new data when
   922  	// iterated over.
   923  	expanded, err = ExpandPostings(after)
   924  	require.NoError(t, err)
   925  	require.Equal(t, []storage.SeriesRef{1, 3}, expanded)
   926  
   927  	deleted := p.Get("lbl1", "b")
   928  	expanded, err = ExpandPostings(deleted)
   929  	require.NoError(t, err)
   930  	require.Equal(t, 0, len(expanded), "expected empty postings, got %v", expanded)
   931  }
   932  
   933  func TestShardedPostings(t *testing.T) {
   934  	offsets := FingerprintOffsets{
   935  		{0, 0},
   936  		{5, 0b1 << 62},
   937  		{10, 0b1 << 63},
   938  		{15, 0b11 << 62},
   939  	}
   940  	shard := NewShard(0, 2)
   941  	var refs []storage.SeriesRef
   942  	for i := 0; i < 20; i++ {
   943  		refs = append(refs, storage.SeriesRef(i))
   944  	}
   945  	ps := newListPostings(refs...)
   946  	shardedPostings := NewShardedPostings(ps, shard, offsets)
   947  
   948  	for i := 0; i < 10; i++ {
   949  		require.Equal(t, true, shardedPostings.Next())
   950  		require.Equal(t, storage.SeriesRef(i), shardedPostings.At())
   951  	}
   952  	require.Equal(t, false, shardedPostings.Next())
   953  }