github.com/phuslu/lru@v1.0.16-0.20240421170520-46288a2fd47c/bytes_cache_test.go (about) 1 package lru 2 3 import ( 4 "fmt" 5 "math/rand" 6 "testing" 7 ) 8 9 func TestBytesCacheDefaultkey(t *testing.T) { 10 cache := NewBytesCache(1, 1) 11 var k []byte 12 var i = []byte("42") 13 14 if prev, replaced := cache.Set(k, i); replaced { 15 t.Fatalf("value %v should not be replaced", prev) 16 } 17 18 if v, ok := cache.Get(k); !ok || b2s(v) != b2s(i) { 19 t.Fatalf("bad returned value: %v != %v", v, i) 20 } 21 } 22 23 func TestBytesCacheGetSet(t *testing.T) { 24 cache := NewBytesCache(1, 128) 25 26 if v, ok := cache.Get([]byte("5")); ok { 27 t.Fatalf("bad returned value: %v", v) 28 } 29 30 if _, replaced := cache.Set([]byte("5"), []byte("10")); replaced { 31 t.Fatal("should not have replaced") 32 } 33 34 if v, ok := cache.Get([]byte("5")); !ok || b2s(v) != "10" { 35 t.Fatalf("bad returned value: %v != %v", v, 10) 36 } 37 38 if v, replaced := cache.Set([]byte("5"), []byte("9")); b2s(v) != "10" || !replaced { 39 t.Fatal("old value should be evicted") 40 } 41 42 if v, replaced := cache.Set([]byte("5"), []byte("9")); b2s(v) != "9" || !replaced { 43 t.Fatal("old value should be evicted") 44 } 45 46 if v, ok := cache.Get([]byte("5")); !ok || b2s(v) != "9" { 47 t.Fatalf("bad returned value: %v != %v", v, 10) 48 } 49 } 50 51 func TestBytesCacheSetIfAbsent(t *testing.T) { 52 cache := NewBytesCache(1, 128) 53 54 cache.Set([]byte("5"), []byte("5")) 55 56 if _, replaced := cache.SetIfAbsent([]byte("5"), []byte("10")); replaced { 57 t.Fatal("should not have replaced") 58 } 59 60 if v, ok := cache.Get([]byte("5")); !ok || b2s(v) != "5" { 61 t.Fatalf("bad returned value: %v = %v", v, []byte("5")) 62 } 63 64 cache.Delete([]byte("5")) 65 66 if _, replaced := cache.SetIfAbsent([]byte("5"), []byte("10")); replaced { 67 t.Fatal("should not have replaced") 68 } 69 70 if v, ok := cache.Get([]byte("5")); !ok || b2s(v) != "10" { 71 t.Fatalf("bad returned value: %v = %v", v, 10) 72 } 73 74 cache.Delete([]byte("5")) 75 76 if _, replaced := cache.SetIfAbsent([]byte("5"), []byte("10")); replaced { 77 t.Fatal("should not have replaced") 78 } 79 80 if v, ok := cache.Get([]byte("5")); !ok || b2s(v) != "10" { 81 t.Fatalf("bad returned value: %v = %v", v, 10) 82 } 83 } 84 85 func TestBytesCacheEviction(t *testing.T) { 86 cache := NewBytesCache(128, 256) 87 if cache.mask+1 != uint32(cap(cache.shards)) { 88 t.Fatalf("bad shard mask: %v", cache.mask) 89 } 90 91 cache = NewBytesCache(1, 256) 92 93 evictedCounter := 0 94 for i := 0; i < 512; i++ { 95 if v, _ := cache.Set([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i))); v != nil { 96 evictedCounter++ 97 } 98 } 99 100 if cache.Len() != 256 { 101 t.Fatalf("bad len: %v", cache.Len()) 102 } 103 104 if evictedCounter != 256 { 105 t.Fatalf("bad evicted count: %v", evictedCounter) 106 } 107 108 for i := 0; i < 256; i++ { 109 if v, ok := cache.Get([]byte(fmt.Sprint(i))); ok || len(v) != 0 { 110 t.Fatalf("key %v value %v should be evicted", i, v) 111 } 112 } 113 114 for i := 256; i < 512; i++ { 115 if v, ok := cache.Get([]byte(fmt.Sprint(i))); !ok { 116 t.Fatalf("key %v value %v should not be evicted", i, v) 117 } 118 } 119 120 for i := 256; i < 384; i++ { 121 cache.Delete([]byte(fmt.Sprint(i))) 122 if v, ok := cache.Get([]byte(fmt.Sprint(i))); ok { 123 t.Fatalf("old key %v value %v should be deleted", i, v) 124 } 125 } 126 127 for i := 384; i < 512; i++ { 128 if v, ok := cache.Get([]byte(fmt.Sprint(i))); !ok || len(v) == 0 { 129 t.Fatalf("old key %v value %v should not be deleted", i, v) 130 } 131 } 132 133 if got, want := cache.Len(), 128; got != want { 134 t.Fatalf("curent cache length %v should be %v", got, want) 135 } 136 137 cache.Set([]byte("400"), []byte("400")) 138 139 if got, want := len(cache.AppendKeys(nil)), 128; got != want { 140 t.Fatalf("curent cache keys length %v should be %v", got, want) 141 } 142 } 143 144 func TestBytesCachePeek(t *testing.T) { 145 cache := NewBytesCache(1, 64) 146 147 cache.Set([]byte("10"), []byte("10")) 148 cache.Set([]byte("20"), []byte("20")) 149 if v, ok := cache.Peek([]byte("10")); !ok || b2s(v) != "10" { 150 t.Errorf("10 should be set to 10: %v", v) 151 } 152 153 if v, ok := cache.Peek([]byte("20")); !ok || b2s(v) != "20" { 154 t.Errorf("20 should be set to 20: %v,", v) 155 } 156 157 if v, ok := cache.Peek([]byte("30")); ok || len(v) != 0 { 158 t.Errorf("30 should be set to nil: %v,", v) 159 } 160 161 for k := 3; k < 1024; k++ { 162 cache.Set([]byte(fmt.Sprint(k)), []byte(fmt.Sprint(k))) 163 } 164 if v, ok := cache.Peek([]byte("10")); ok || b2s(v) == "10" { 165 t.Errorf("%v should not have updated recent-ness of 10", v) 166 } 167 if v, ok := cache.Peek([]byte("30")); ok || len(v) != 0 { 168 t.Errorf("%v should have updated recent-ness of 30", v) 169 } 170 } 171 172 func TestBytesCacheStats(t *testing.T) { 173 cache := NewBytesCache(1, 256) 174 175 cache.Set([]byte("a"), []byte("1")) 176 cache.Set([]byte("b"), []byte("2")) 177 cache.Set([]byte("c"), []byte("3")) 178 cache.Set([]byte("d"), []byte("3")) 179 180 stats := cache.Stats() 181 if got, want := stats.EntriesCount, uint64(4); got != want { 182 t.Fatalf("cache entries should be %v: %v", want, got) 183 } 184 if got, want := stats.GetCalls, uint64(0); got != want { 185 t.Fatalf("cache get calls should be %v: %v", want, got) 186 } 187 if got, want := stats.SetCalls, uint64(4); got != want { 188 t.Fatalf("cache set calls should be %v: %v", want, got) 189 } 190 if got, want := stats.Misses, uint64(0); got != want { 191 t.Fatalf("cache misses should be %v: %v", want, got) 192 } 193 194 cache.Get([]byte("a")) 195 cache.Get([]byte("b")) 196 cache.Get([]byte("x")) 197 cache.Get([]byte("y")) 198 cache.Get([]byte("z")) 199 cache.Set([]byte("c"), []byte("13")) 200 201 stats = cache.Stats() 202 if got, want := stats.EntriesCount, uint64(4); got != want { 203 t.Fatalf("cache entries should be %v: %v", want, got) 204 } 205 if got, want := stats.GetCalls, uint64(5); got != want { 206 t.Fatalf("cache get calls should be %v: %v", want, got) 207 } 208 if got, want := stats.SetCalls, uint64(5); got != want { 209 t.Fatalf("cache set calls should be %v: %v", want, got) 210 } 211 if got, want := stats.Misses, uint64(3); got != want { 212 t.Fatalf("cache misses should be %v: %v", want, got) 213 } 214 } 215 216 func BenchmarkBytesCacheRand(b *testing.B) { 217 cache := NewBytesCache(1, 8192) 218 219 trace := make([]int64, b.N*2) 220 for i := 0; i < b.N*2; i++ { 221 trace[i] = rand.Int63() % 32768 222 } 223 224 b.ReportAllocs() 225 b.ResetTimer() 226 227 var hit, miss int 228 for i := 0; i < 2*b.N; i++ { 229 if i%2 == 0 { 230 cache.Set([]byte(fmt.Sprint(trace[i])), []byte(fmt.Sprint(trace[i]))) 231 } else { 232 if _, ok := cache.Get([]byte(fmt.Sprint(trace[i]))); ok { 233 hit++ 234 } else { 235 miss++ 236 } 237 } 238 } 239 b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(hit+miss)) 240 } 241 242 func BenchmarkBytesCacheFreq(b *testing.B) { 243 cache := NewBytesCache(1, 8192) 244 245 trace := make([]int64, b.N*2) 246 for i := 0; i < b.N*2; i++ { 247 if i%2 == 0 { 248 trace[i] = rand.Int63() % 16384 249 } else { 250 trace[i] = rand.Int63() % 32768 251 } 252 } 253 254 b.ReportAllocs() 255 b.ResetTimer() 256 257 for i := 0; i < b.N; i++ { 258 cache.Set([]byte(fmt.Sprint(trace[i])), []byte(fmt.Sprint(trace[i]))) 259 } 260 var hit, miss int 261 for i := 0; i < b.N; i++ { 262 if _, ok := cache.Get([]byte(fmt.Sprint(trace[i]))); ok { 263 hit++ 264 } else { 265 miss++ 266 } 267 } 268 b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(hit+miss)) 269 }