github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/ingester/index/bitprefix_test.go (about)

     1  package index
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"testing"
     7  
     8  	"github.com/prometheus/common/model"
     9  	"github.com/prometheus/prometheus/model/labels"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/grafana/loki/pkg/logproto"
    13  	"github.com/grafana/loki/pkg/querier/astmapper"
    14  	"github.com/grafana/loki/pkg/storage/stores/tsdb/index"
    15  )
    16  
    17  func Test_BitPrefixGetShards(t *testing.T) {
    18  	for _, tt := range []struct {
    19  		total    uint32
    20  		filter   bool
    21  		shard    *astmapper.ShardAnnotation
    22  		expected []uint32
    23  	}{
    24  		// equal factors
    25  		{16, false, &astmapper.ShardAnnotation{Shard: 0, Of: 16}, []uint32{0}},
    26  		{16, false, &astmapper.ShardAnnotation{Shard: 4, Of: 16}, []uint32{4}},
    27  		{16, false, &astmapper.ShardAnnotation{Shard: 15, Of: 16}, []uint32{15}},
    28  
    29  		// idx factor a larger factor of 2
    30  		{32, false, &astmapper.ShardAnnotation{Shard: 0, Of: 16}, []uint32{0, 1}},
    31  		{32, false, &astmapper.ShardAnnotation{Shard: 4, Of: 16}, []uint32{8, 9}},
    32  		{32, false, &astmapper.ShardAnnotation{Shard: 15, Of: 16}, []uint32{30, 31}},
    33  		{64, false, &astmapper.ShardAnnotation{Shard: 15, Of: 16}, []uint32{60, 61, 62, 63}},
    34  
    35  		// // idx factor a smaller factor of 2
    36  		{8, true, &astmapper.ShardAnnotation{Shard: 0, Of: 16}, []uint32{0}},
    37  		{8, true, &astmapper.ShardAnnotation{Shard: 4, Of: 16}, []uint32{2}},
    38  		{8, true, &astmapper.ShardAnnotation{Shard: 15, Of: 16}, []uint32{7}},
    39  	} {
    40  		tt := tt
    41  		t.Run(tt.shard.String()+fmt.Sprintf("_total_%d", tt.total), func(t *testing.T) {
    42  			ii, err := NewBitPrefixWithShards(tt.total)
    43  			require.Nil(t, err)
    44  			res, filter := ii.getShards(tt.shard)
    45  			resInt := []uint32{}
    46  			for _, r := range res {
    47  				resInt = append(resInt, r.shard)
    48  			}
    49  			require.Equal(t, tt.filter, filter)
    50  			require.Equal(t, tt.expected, resInt)
    51  		})
    52  	}
    53  }
    54  
    55  func Test_BitPrefixValidateShards(t *testing.T) {
    56  	ii, err := NewBitPrefixWithShards(32)
    57  	require.Nil(t, err)
    58  	require.NoError(t, ii.validateShard(&astmapper.ShardAnnotation{Shard: 1, Of: 16}))
    59  	require.Error(t, ii.validateShard(&astmapper.ShardAnnotation{Shard: 1, Of: 15}))
    60  }
    61  
    62  func Test_BitPrefixCreation(t *testing.T) {
    63  	// non factor of 2 shard factor
    64  	_, err := NewBitPrefixWithShards(6)
    65  	require.Error(t, err)
    66  
    67  	// valid shard factor
    68  	_, err = NewBitPrefixWithShards(4)
    69  	require.Nil(t, err)
    70  }
    71  
    72  func Test_BitPrefixDeleteAddLoopkup(t *testing.T) {
    73  	index, err := NewBitPrefixWithShards(DefaultIndexShards)
    74  	require.Nil(t, err)
    75  	lbs := []logproto.LabelAdapter{
    76  		{Name: "foo", Value: "foo"},
    77  		{Name: "bar", Value: "bar"},
    78  		{Name: "buzz", Value: "buzz"},
    79  	}
    80  	sort.Sort(logproto.FromLabelAdaptersToLabels(lbs))
    81  
    82  	index.Add(lbs, model.Fingerprint((logproto.FromLabelAdaptersToLabels(lbs).Hash())))
    83  	index.Delete(logproto.FromLabelAdaptersToLabels(lbs), model.Fingerprint(logproto.FromLabelAdaptersToLabels(lbs).Hash()))
    84  	ids, err := index.Lookup([]*labels.Matcher{
    85  		labels.MustNewMatcher(labels.MatchEqual, "foo", "foo"),
    86  	}, nil)
    87  	require.NoError(t, err)
    88  	require.Len(t, ids, 0)
    89  }
    90  
    91  func Test_BitPrefix_hash_mapping(t *testing.T) {
    92  	lbs := labels.Labels{
    93  		labels.Label{Name: "compose_project", Value: "loki-boltdb-storage-s3"},
    94  		labels.Label{Name: "compose_service", Value: "ingester-2"},
    95  		labels.Label{Name: "container_name", Value: "loki-boltdb-storage-s3_ingester-2_1"},
    96  		labels.Label{Name: "filename", Value: "/var/log/docker/790fef4c6a587c3b386fe85c07e03f3a1613f4929ca3abaa4880e14caadb5ad1/json.log"},
    97  		labels.Label{Name: "host", Value: "docker-desktop"},
    98  		labels.Label{Name: "source", Value: "stderr"},
    99  	}
   100  
   101  	// for _, shard := range []uint32{2, 4, 8, 16, 32, 64, 128} {
   102  	for _, shard := range []uint32{2} {
   103  		t.Run(fmt.Sprintf("%d", shard), func(t *testing.T) {
   104  			ii, err := NewBitPrefixWithShards(shard)
   105  			require.Nil(t, err)
   106  
   107  			requestedFactor := 16
   108  
   109  			fp := model.Fingerprint(lbs.Hash())
   110  			ii.Add(logproto.FromLabelsToLabelAdapters(lbs), fp)
   111  
   112  			requiredBits := index.NewShard(0, uint32(requestedFactor)).RequiredBits()
   113  			expShard := uint32(lbs.Hash() >> (64 - requiredBits))
   114  
   115  			res, err := ii.Lookup(
   116  				[]*labels.Matcher{{Type: labels.MatchEqual,
   117  					Name:  "compose_project",
   118  					Value: "loki-boltdb-storage-s3"}},
   119  				&astmapper.ShardAnnotation{
   120  					Shard: int(expShard),
   121  					Of:    requestedFactor,
   122  				},
   123  			)
   124  			require.NoError(t, err)
   125  			require.Len(t, res, 1)
   126  			require.Equal(t, fp, res[0])
   127  		})
   128  	}
   129  }
   130  
   131  func Test_BitPrefixNoMatcherLookup(t *testing.T) {
   132  	lbs := labels.Labels{
   133  		labels.Label{Name: "foo", Value: "bar"},
   134  		labels.Label{Name: "hi", Value: "hello"},
   135  	}
   136  	// with no shard param
   137  	ii, err := NewBitPrefixWithShards(16)
   138  	require.Nil(t, err)
   139  	fp := model.Fingerprint(lbs.Hash())
   140  	ii.Add(logproto.FromLabelsToLabelAdapters(lbs), fp)
   141  	ids, err := ii.Lookup(nil, nil)
   142  	require.Nil(t, err)
   143  	require.Equal(t, fp, ids[0])
   144  
   145  	// with shard param
   146  	ii, err = NewBitPrefixWithShards(16)
   147  	require.Nil(t, err)
   148  	expShard := uint32(fp >> (64 - index.NewShard(0, 16).RequiredBits()))
   149  	ii.Add(logproto.FromLabelsToLabelAdapters(lbs), fp)
   150  	ids, err = ii.Lookup(nil, &astmapper.ShardAnnotation{Shard: int(expShard), Of: 16})
   151  	require.Nil(t, err)
   152  	require.Equal(t, fp, ids[0])
   153  }
   154  
   155  func Test_BitPrefixConsistentMapping(t *testing.T) {
   156  	a, err := NewBitPrefixWithShards(16)
   157  	require.Nil(t, err)
   158  	b, err := NewBitPrefixWithShards(32)
   159  	require.Nil(t, err)
   160  
   161  	for i := 0; i < 100; i++ {
   162  		lbs := labels.Labels{
   163  			labels.Label{Name: "foo", Value: "bar"},
   164  			labels.Label{Name: "hi", Value: fmt.Sprint(i)},
   165  		}
   166  
   167  		fp := model.Fingerprint(lbs.Hash())
   168  		a.Add(logproto.FromLabelsToLabelAdapters(lbs), fp)
   169  		b.Add(logproto.FromLabelsToLabelAdapters(lbs), fp)
   170  	}
   171  
   172  	shardMax := 8
   173  	for i := 0; i < shardMax; i++ {
   174  		shard := &astmapper.ShardAnnotation{
   175  			Shard: i,
   176  			Of:    shardMax,
   177  		}
   178  
   179  		aIDs, err := a.Lookup([]*labels.Matcher{
   180  			labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"),
   181  		}, shard)
   182  		require.Nil(t, err)
   183  
   184  		bIDs, err := b.Lookup([]*labels.Matcher{
   185  			labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"),
   186  		}, shard)
   187  		require.Nil(t, err)
   188  
   189  		sorter := func(xs []model.Fingerprint) {
   190  			sort.Slice(xs, func(i, j int) bool {
   191  				return xs[i] < xs[j]
   192  			})
   193  		}
   194  		sorter(aIDs)
   195  		sorter(bIDs)
   196  
   197  		require.Equal(t, aIDs, bIDs, "incorrect shard mapping for shard %v", shard)
   198  	}
   199  
   200  }