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  }