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