github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/services/cache/lru_striped_test.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package cache 5 6 import ( 7 "fmt" 8 "hash/maphash" 9 "testing" 10 11 "github.com/cespare/xxhash/v2" 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 15 "github.com/masterhung0112/hk_server/v5/model" 16 ) 17 18 func makeLRUPredictibleTestData(num int) [][2]string { 19 kv := make([][2]string, num) 20 for i := 0; i < len(kv); i++ { 21 kv[i] = [2]string{ 22 fmt.Sprintf("%d-key-%d", i, i), 23 fmt.Sprintf("%d-val-%d", i, i), 24 } 25 } 26 return kv 27 } 28 29 func TestNewLRUStriped(t *testing.T) { 30 scache, err := NewLRUStriped(LRUOptions{StripedBuckets: 3, Size: 20}) 31 require.NoError(t, err) 32 33 cache := scache.(LRUStriped) 34 35 require.Len(t, cache.buckets, 3) 36 assert.Equal(t, 8, cache.buckets[0].size) 37 assert.Equal(t, 8, cache.buckets[1].size) 38 assert.Equal(t, 8, cache.buckets[2].size) 39 } 40 41 func TestLRUStripedKeyDistribution(t *testing.T) { 42 dataset := makeLRUPredictibleTestData(100) 43 44 scache, err := NewLRUStriped(LRUOptions{StripedBuckets: 4, Size: len(dataset)}) 45 require.NoError(t, err) 46 cache := scache.(LRUStriped) 47 for _, kv := range dataset { 48 require.NoError(t, cache.Set(kv[0], kv[1])) 49 var out string 50 require.NoError(t, cache.Get(kv[0], &out)) 51 require.Equal(t, kv[1], out) 52 } 53 54 require.Len(t, cache.buckets, 4) 55 acc := 0 56 for i := 0; i < 4; i++ { 57 clen, err := cache.buckets[i].Len() 58 acc += clen 59 assert.NoError(t, err) 60 assert.GreaterOrEqual(t, clen, len(dataset)/2/4, "at least 50%/nbuckets of all keys in each bucket") 61 } 62 // because of the limited size of each bucket and the nature of our data, 63 // we may have around 10% of our keys evicted in this scenario. removing 1% because we cannot predict 64 // accurately what is happening with random data. 65 assert.GreaterOrEqual(t, acc, len(dataset)-(len(dataset)*1.0/100.0)) 66 } 67 68 func TestLRUStriped_Size(t *testing.T) { 69 scache, err := NewLRUStriped(LRUOptions{StripedBuckets: 2, Size: 128}) 70 require.NoError(t, err) 71 cache := scache.(LRUStriped) 72 acc := 0 73 for _, bucket := range cache.buckets { 74 acc += bucket.size 75 } 76 assert.Equal(t, 128+13+1, acc) // +10% +modulo padding 77 } 78 79 func TestLRUStriped_HashKey(t *testing.T) { 80 scache, err := NewLRUStriped(LRUOptions{StripedBuckets: 2, Size: 128}) 81 require.NoError(t, err) 82 cache := scache.(LRUStriped) 83 first := cache.hashkeyMapHash("key") 84 cache.hashkeyMapHash("other_key_to_ensure_that_result_it’s_not_dependent_on_previous_input") 85 second := cache.hashkeyMapHash("key") 86 require.Equal(t, first, second) 87 } 88 89 func TestLRUStriped_Get(t *testing.T) { 90 cache, err := NewLRUStriped(LRUOptions{StripedBuckets: 4, Size: 128}) 91 require.NoError(t, err) 92 var out string 93 require.Equal(t, ErrKeyNotFound, cache.Get("key", &out)) 94 require.Zero(t, out) 95 96 require.NoError(t, cache.Set("key", "value")) 97 require.NoError(t, cache.Get("key", &out)) 98 require.Equal(t, "value", out) 99 } 100 101 var hashSink uint64 102 103 func BenchmarkSum64(b *testing.B) { 104 cases := []string{ 105 "1", 106 "22", 107 "333", 108 model.NewId(), 109 model.NewId() + model.NewId(), 110 } 111 112 for _, case_ := range cases { 113 b.Run(fmt.Sprintf("maphash_string_len_%d", len(case_)), func(b *testing.B) { 114 seed := maphash.MakeSeed() 115 b.ResetTimer() 116 for i := 0; i < b.N; i++ { 117 var h maphash.Hash 118 h.SetSeed(seed) 119 h.WriteString(case_) // documentation and code says it never fails 120 hashSink = h.Sum64() 121 } 122 }) 123 b.Run(fmt.Sprintf("xxhash_string_len_%d", len(case_)), func(b *testing.B) { 124 for i := 0; i < b.N; i++ { 125 hashSink = xxhash.Sum64String(case_) 126 } 127 }) 128 } 129 }