github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/ingester/index/index_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/util" 15 ) 16 17 func Test_GetShards(t *testing.T) { 18 for _, tt := range []struct { 19 total uint32 20 shard *astmapper.ShardAnnotation 21 expected []uint32 22 }{ 23 // equal factors 24 {16, &astmapper.ShardAnnotation{Shard: 0, Of: 16}, []uint32{0}}, 25 {16, &astmapper.ShardAnnotation{Shard: 4, Of: 16}, []uint32{4}}, 26 {16, &astmapper.ShardAnnotation{Shard: 15, Of: 16}, []uint32{15}}, 27 28 // idx factor a larger multiple of schema factor 29 {32, &astmapper.ShardAnnotation{Shard: 0, Of: 16}, []uint32{0, 16}}, 30 {32, &astmapper.ShardAnnotation{Shard: 4, Of: 16}, []uint32{4, 20}}, 31 {32, &astmapper.ShardAnnotation{Shard: 15, Of: 16}, []uint32{15, 31}}, 32 {64, &astmapper.ShardAnnotation{Shard: 15, Of: 16}, []uint32{15, 31, 47, 63}}, 33 } { 34 tt := tt 35 t.Run(tt.shard.String()+fmt.Sprintf("_total_%d", tt.total), func(t *testing.T) { 36 ii := NewWithShards(tt.total) 37 res := ii.getShards(tt.shard) 38 resInt := []uint32{} 39 for _, r := range res { 40 resInt = append(resInt, r.shard) 41 } 42 require.Equal(t, tt.expected, resInt) 43 }) 44 } 45 } 46 47 func Test_ValidateShards(t *testing.T) { 48 ii := NewWithShards(32) 49 require.NoError(t, ii.validateShard(&astmapper.ShardAnnotation{Shard: 1, Of: 16})) 50 } 51 52 var ( 53 result uint32 54 lbs = []logproto.LabelAdapter{ 55 {Name: "foo", Value: "bar"}, 56 } 57 buf = make([]byte, 0, 1024) 58 ) 59 60 func BenchmarkHash(b *testing.B) { 61 b.Run("sha256", func(b *testing.B) { 62 for n := 0; n < b.N; n++ { 63 result = labelsSeriesIDHash(logproto.FromLabelAdaptersToLabels(lbs)) % 16 64 } 65 }) 66 b.Run("xxash", func(b *testing.B) { 67 for n := 0; n < b.N; n++ { 68 var fp uint64 69 fp, buf = logproto.FromLabelAdaptersToLabels(lbs).HashWithoutLabels(buf, []string(nil)...) 70 result = util.HashFP(model.Fingerprint(fp)) % 16 71 } 72 }) 73 } 74 75 func TestDeleteAddLoopkup(t *testing.T) { 76 index := NewWithShards(DefaultIndexShards) 77 lbs := []logproto.LabelAdapter{ 78 {Name: "foo", Value: "foo"}, 79 {Name: "bar", Value: "bar"}, 80 {Name: "buzz", Value: "buzz"}, 81 } 82 sort.Sort(logproto.FromLabelAdaptersToLabels(lbs)) 83 84 require.Equal(t, uint32(26), labelsSeriesIDHash(logproto.FromLabelAdaptersToLabels(lbs))%32) 85 // make sure we consistent 86 require.Equal(t, uint32(26), labelsSeriesIDHash(logproto.FromLabelAdaptersToLabels(lbs))%32) 87 index.Add(lbs, model.Fingerprint((logproto.FromLabelAdaptersToLabels(lbs).Hash()))) 88 index.Delete(logproto.FromLabelAdaptersToLabels(lbs), model.Fingerprint(logproto.FromLabelAdaptersToLabels(lbs).Hash())) 89 ids, err := index.Lookup([]*labels.Matcher{ 90 labels.MustNewMatcher(labels.MatchEqual, "foo", "foo"), 91 }, nil) 92 require.NoError(t, err) 93 require.Len(t, ids, 0) 94 } 95 96 func Test_hash_mapping(t *testing.T) { 97 lbs := labels.Labels{ 98 labels.Label{Name: "compose_project", Value: "loki-boltdb-storage-s3"}, 99 labels.Label{Name: "compose_service", Value: "ingester-2"}, 100 labels.Label{Name: "container_name", Value: "loki-boltdb-storage-s3_ingester-2_1"}, 101 labels.Label{Name: "filename", Value: "/var/log/docker/790fef4c6a587c3b386fe85c07e03f3a1613f4929ca3abaa4880e14caadb5ad1/json.log"}, 102 labels.Label{Name: "host", Value: "docker-desktop"}, 103 labels.Label{Name: "source", Value: "stderr"}, 104 } 105 106 for _, shard := range []uint32{16, 32, 64, 128} { 107 t.Run(fmt.Sprintf("%d", shard), func(t *testing.T) { 108 ii := NewWithShards(shard) 109 ii.Add(logproto.FromLabelsToLabelAdapters(lbs), 1) 110 111 res, err := ii.Lookup([]*labels.Matcher{{Type: labels.MatchEqual, Name: "compose_project", Value: "loki-boltdb-storage-s3"}}, &astmapper.ShardAnnotation{Shard: int(labelsSeriesIDHash(lbs) % 16), Of: 16}) 112 require.NoError(t, err) 113 require.Len(t, res, 1) 114 require.Equal(t, model.Fingerprint(1), res[0]) 115 }) 116 } 117 } 118 119 func Test_NoMatcherLookup(t *testing.T) { 120 lbs := labels.Labels{ 121 labels.Label{Name: "foo", Value: "bar"}, 122 labels.Label{Name: "hi", Value: "hello"}, 123 } 124 // with no shard param 125 ii := NewWithShards(16) 126 ii.Add(logproto.FromLabelsToLabelAdapters(lbs), 1) 127 ids, err := ii.Lookup(nil, nil) 128 require.Nil(t, err) 129 require.Equal(t, model.Fingerprint(1), ids[0]) 130 131 // with shard param 132 ii = NewWithShards(16) 133 ii.Add(logproto.FromLabelsToLabelAdapters(lbs), 1) 134 ids, err = ii.Lookup(nil, &astmapper.ShardAnnotation{Shard: int(labelsSeriesIDHash(lbs) % 16), Of: 16}) 135 require.Nil(t, err) 136 require.Equal(t, model.Fingerprint(1), ids[0]) 137 } 138 139 func Test_ConsistentMapping(t *testing.T) { 140 a := NewWithShards(16) 141 b := NewWithShards(32) 142 143 for i := 0; i < 100; i++ { 144 lbs := labels.Labels{ 145 labels.Label{Name: "foo", Value: "bar"}, 146 labels.Label{Name: "hi", Value: fmt.Sprint(i)}, 147 } 148 a.Add(logproto.FromLabelsToLabelAdapters(lbs), model.Fingerprint(i)) 149 b.Add(logproto.FromLabelsToLabelAdapters(lbs), model.Fingerprint(i)) 150 } 151 152 shardMax := 8 153 for i := 0; i < shardMax; i++ { 154 shard := &astmapper.ShardAnnotation{ 155 Shard: i, 156 Of: shardMax, 157 } 158 159 aIDs, err := a.Lookup([]*labels.Matcher{ 160 labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), 161 }, shard) 162 require.Nil(t, err) 163 164 bIDs, err := b.Lookup([]*labels.Matcher{ 165 labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), 166 }, shard) 167 require.Nil(t, err) 168 169 sorter := func(xs []model.Fingerprint) { 170 sort.Slice(xs, func(i, j int) bool { 171 return xs[i] < xs[j] 172 }) 173 } 174 sorter(aIDs) 175 sorter(bIDs) 176 177 require.Equal(t, aIDs, bIDs, "incorrect shard mapping for shard %v", shard) 178 } 179 180 }