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 }