github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/cache/cache_test.go (about) 1 // Copyright 2014 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 // 11 // This code is based on: https://github.com/golang/groupcache/ 12 13 package cache 14 15 import ( 16 "bytes" 17 "reflect" 18 "testing" 19 20 "github.com/biogo/store/llrb" 21 _ "github.com/cockroachdb/cockroach/pkg/util/log" // for flags 22 ) 23 24 type testKey string 25 26 // Compare implements llrb.Comparable. 27 func (tk testKey) Compare(b llrb.Comparable) int { 28 return bytes.Compare([]byte(tk), []byte(b.(testKey))) 29 } 30 31 var getTests = []struct { 32 name string 33 keyToAdd testKey 34 keyToGet testKey 35 expectedOk bool 36 }{ 37 {"string_hit", "myKey", "myKey", true}, 38 {"string_miss", "myKey", "nonsense", false}, 39 } 40 41 func noEviction(size int, key, value interface{}) bool { 42 return false 43 } 44 45 func evictTwoOrMore(size int, key, value interface{}) bool { 46 return size > 1 47 } 48 49 func evictThreeOrMore(size int, key, value interface{}) bool { 50 return size > 2 51 } 52 53 func TestCacheGet(t *testing.T) { 54 for _, tt := range getTests { 55 mc := NewUnorderedCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 56 mc.Add(tt.keyToAdd, 1234) 57 val, ok := mc.Get(tt.keyToGet) 58 if ok != tt.expectedOk { 59 t.Fatalf("%s: cache hit = %v; want %v", tt.name, ok, !ok) 60 } else if ok && val != 1234 { 61 t.Fatalf("%s expected get to return 1234 but got %v", tt.name, val) 62 } 63 } 64 } 65 66 func TestCacheClear(t *testing.T) { 67 mc := NewUnorderedCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 68 mc.Add(testKey("a"), 1) 69 mc.Add(testKey("b"), 2) 70 mc.Clear() 71 if _, ok := mc.Get(testKey("a")); ok { 72 t.Error("expected cache cleared") 73 } 74 if _, ok := mc.Get(testKey("b")); ok { 75 t.Error("expected cache cleared") 76 } 77 mc.Add(testKey("a"), 1) 78 if _, ok := mc.Get(testKey("a")); !ok { 79 t.Error("expected reinsert to succeed") 80 } 81 } 82 83 func TestCacheDel(t *testing.T) { 84 mc := NewUnorderedCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 85 mc.Add(testKey("myKey"), 1234) 86 if val, ok := mc.Get(testKey("myKey")); !ok { 87 t.Fatal("TestDel returned no match") 88 } else if val != 1234 { 89 t.Fatalf("TestDel failed. Expected %d, got %v", 1234, val) 90 } 91 92 mc.Del(testKey("myKey")) 93 if _, ok := mc.Get(testKey("myKey")); ok { 94 t.Fatal("TestRemove returned a removed entry") 95 } 96 } 97 98 func TestCacheAddDelEntry(t *testing.T) { 99 mc := NewUnorderedCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 100 e := &Entry{Key: testKey("myKey"), Value: 1234} 101 mc.AddEntry(e) 102 if val, ok := mc.Get(testKey("myKey")); !ok { 103 t.Fatal("TestDel returned no match") 104 } else if val != 1234 { 105 t.Fatalf("TestDel failed. Expected %d, got %v", 1234, val) 106 } 107 108 mc.DelEntry(e) 109 if _, ok := mc.Get(testKey("myKey")); ok { 110 t.Fatal("TestRemove returned a removed entry") 111 } 112 } 113 114 func TestCacheEviction(t *testing.T) { 115 mc := NewUnorderedCache(Config{Policy: CacheLRU, ShouldEvict: evictTwoOrMore}) 116 // Insert two keys into cache which only holds 1. 117 mc.Add(testKey("a"), 1234) 118 val, ok := mc.Get(testKey("a")) 119 if !ok || val.(int) != 1234 { 120 t.Fatal("expected get to succeed with value 1234") 121 } 122 mc.Add(testKey("b"), 4321) 123 val, ok = mc.Get(testKey("b")) 124 if !ok || val.(int) != 4321 { 125 t.Fatal("expected get to succeed with value 4321") 126 } 127 // Verify eviction of first key. 128 if _, ok = mc.Get(testKey("a")); ok { 129 t.Fatal("unexpected success getting evicted key") 130 } 131 } 132 133 func TestCacheLRU(t *testing.T) { 134 mc := NewUnorderedCache(Config{Policy: CacheLRU, ShouldEvict: evictThreeOrMore}) 135 // Insert two keys into cache. 136 mc.Add(testKey("a"), 1) 137 mc.Add(testKey("b"), 2) 138 // Get "a" now to make it more recently used. 139 if _, ok := mc.Get(testKey("a")); !ok { 140 t.Fatal("failed to get key a") 141 } 142 // Add another entry to evict; should evict key "b". 143 mc.Add(testKey("c"), 3) 144 // Verify eviction of least recently used key "b". 145 if _, ok := mc.Get(testKey("b")); ok { 146 t.Fatal("unexpected success getting evicted key") 147 } 148 } 149 150 func TestCacheFIFO(t *testing.T) { 151 mc := NewUnorderedCache(Config{Policy: CacheFIFO, ShouldEvict: evictThreeOrMore}) 152 // Insert two keys into cache. 153 mc.Add(testKey("a"), 1) 154 mc.Add(testKey("b"), 2) 155 // Get "a" now to make it more recently used. 156 if _, ok := mc.Get(testKey("a")); !ok { 157 t.Fatal("failed to get key a") 158 } 159 // Add another entry to evict; should evict key "a" still, as that was first in. 160 mc.Add(testKey("c"), 3) 161 // Verify eviction of first key "a". 162 if _, ok := mc.Get(testKey("a")); ok { 163 t.Fatal("unexpected success getting evicted key") 164 } 165 } 166 167 func TestOrderedCache(t *testing.T) { 168 oc := NewOrderedCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 169 oc.Add(testKey("a"), 1) 170 oc.Add(testKey("b"), 2) 171 172 // Verify hit & miss. 173 if v, ok := oc.Get(testKey("a")); !ok || v.(int) != 1 { 174 t.Error("failed to fetch value for key \"a\"") 175 } 176 if _, ok := oc.Get(testKey("c")); ok { 177 t.Error("unexpected success fetching \"c\"") 178 } 179 180 // Try binary searches for ceil and floor to key direct. 181 if _, v, ok := oc.Ceil(testKey("a")); !ok || v.(int) != 1 { 182 t.Error("expected success fetching key directly") 183 } 184 if _, v, ok := oc.Floor(testKey("a")); !ok || v.(int) != 1 { 185 t.Error("expected success fetching key directly") 186 } 187 188 // Test ceil and floor operation with empty key. 189 if _, v, ok := oc.Ceil(testKey("")); !ok || v.(int) != 1 { 190 t.Error("expected fetch of key \"a\" for ceil of empty key") 191 } 192 if _, _, ok := oc.Floor(testKey("")); ok { 193 t.Error("unexpected success fetching floor of empty key") 194 } 195 196 // Test ceil and floor operation with midway key. 197 if _, v, ok := oc.Ceil(testKey("aa")); !ok || v.(int) != 2 { 198 t.Error("expected fetch of key \"b\" for ceil of midway key") 199 } 200 if _, v, ok := oc.Floor(testKey("aa")); !ok || v.(int) != 1 { 201 t.Error("expected fetch of key \"a\" for floor of midway key") 202 } 203 204 // Test ceil and floor operation with maximum key. 205 if _, _, ok := oc.Ceil(testKey("c")); ok { 206 t.Error("unexpected success fetching ceil of maximum key") 207 } 208 if _, v, ok := oc.Floor(testKey("c")); !ok || v.(int) != 2 { 209 t.Error("expected fetch of key \"b\" for floor of maximum key") 210 } 211 212 // Test do over entire cache. 213 expKeys, collectKeys := []string{"a", "b"}, []string{} 214 expVals, collectVals := []int{1, 2}, []int{} 215 collect := func(k, v interface{}) bool { 216 collectKeys = append(collectKeys, string(k.(testKey))) 217 collectVals = append(collectVals, v.(int)) 218 return false 219 } 220 221 oc.Do(collect) 222 if !reflect.DeepEqual(expKeys, collectKeys) { 223 t.Errorf("expected do to find keys %v, found %v", expKeys, collectKeys) 224 } 225 if !reflect.DeepEqual(expVals, collectVals) { 226 t.Errorf("expected do to find values %v, found %v", expVals, collectVals) 227 } 228 229 // Test doRange over range ["a","b"). 230 expKeys, collectKeys = []string{"a"}, []string{} 231 expVals, collectVals = []int{1}, []int{} 232 233 oc.DoRange(collect, testKey("a"), testKey("b")) 234 if !reflect.DeepEqual(expKeys, collectKeys) { 235 t.Errorf("expected do to find keys %v, found %v", expKeys, collectKeys) 236 } 237 if !reflect.DeepEqual(expVals, collectVals) { 238 t.Errorf("expected do to find values %v, found %v", expVals, collectVals) 239 } 240 } 241 242 func TestOrderedCacheClear(t *testing.T) { 243 oc := NewOrderedCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 244 oc.Add(testKey("a"), 1) 245 oc.Add(testKey("b"), 2) 246 oc.Clear() 247 if _, ok := oc.Get(testKey("a")); ok { 248 t.Error("expected cache cleared") 249 } 250 if _, ok := oc.Get(testKey("b")); ok { 251 t.Error("expected cache cleared") 252 } 253 oc.Add(testKey("a"), 1) 254 if _, ok := oc.Get(testKey("a")); !ok { 255 t.Error("expected reinsert to succeed") 256 } 257 } 258 259 func TestIntervalCache(t *testing.T) { 260 ic := NewIntervalCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 261 key1 := ic.NewKey([]byte("a"), []byte("b")) 262 key2 := ic.NewKey([]byte("a"), []byte("c")) 263 key3 := ic.NewKey([]byte("d"), []byte("d\x00")) 264 ic.Add(key1, 1) 265 ic.Add(key2, 2) 266 ic.Add(key3, 3) 267 268 // Verify hit & miss. 269 if v, ok := ic.Get(key1); !ok || v.(int) != 1 { 270 t.Error("failed to fetch value for key \"a\"-\"b\"") 271 } 272 if v, ok := ic.Get(key2); !ok || v.(int) != 2 { 273 t.Error("failed to fetch value for key \"a\"-\"c\"") 274 } 275 if v, ok := ic.Get(key3); !ok || v.(int) != 3 { 276 t.Error("failed to fetch value for key \"d\"") 277 } 278 if _, ok := ic.Get(ic.NewKey([]byte("a"), []byte("a\x00"))); ok { 279 t.Error("unexpected success fetching \"a\"") 280 } 281 282 // Verify replacement on adding identical key. 283 ic.Add(key1, 3) 284 if v, ok := ic.Get(key1); !ok || v.(int) != 3 { 285 t.Error("failed to fetch value for key \"a\"-\"b\"") 286 } 287 } 288 289 func TestIntervalCacheOverlap(t *testing.T) { 290 ic := NewIntervalCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 291 ic.Add(ic.NewKey([]byte("a"), []byte("c")), 1) 292 ic.Add(ic.NewKey([]byte("c"), []byte("e")), 2) 293 ic.Add(ic.NewKey([]byte("b"), []byte("g")), 3) 294 ic.Add(ic.NewKey([]byte("d"), []byte("e")), 4) 295 ic.Add(ic.NewKey([]byte("b"), []byte("d")), 5) 296 ic.Add(ic.NewKey([]byte("e"), []byte("g")), 6) 297 ic.Add(ic.NewKey([]byte("f"), []byte("i")), 7) 298 ic.Add(ic.NewKey([]byte("g"), []byte("i")), 8) 299 ic.Add(ic.NewKey([]byte("f"), []byte("h")), 9) 300 ic.Add(ic.NewKey([]byte("i"), []byte("j")), 10) 301 302 expValues := []interface{}{3, 2, 4, 6, 7, 9} 303 values := []interface{}{} 304 for _, o := range ic.GetOverlaps([]byte("d"), []byte("g")) { 305 values = append(values, o.Value) 306 } 307 if !reflect.DeepEqual(expValues, values) { 308 t.Errorf("expected overlap values %+v, got %+v", expValues, values) 309 } 310 } 311 312 func TestIntervalCacheClear(t *testing.T) { 313 ic := NewIntervalCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 314 key1 := ic.NewKey([]byte("a"), []byte("c")) 315 key2 := ic.NewKey([]byte("c"), []byte("e")) 316 ic.Add(key1, 1) 317 ic.Add(key2, 2) 318 ic.Clear() 319 if _, ok := ic.Get(key1); ok { 320 t.Error("expected cache cleared") 321 } 322 if _, ok := ic.Get(key2); ok { 323 t.Error("expected cache cleared") 324 } 325 if l := ic.Len(); l != 0 { 326 t.Errorf("expected cleared cache to have len 0, found %d", l) 327 } 328 ic.Add(key1, 1) 329 if _, ok := ic.Get(key1); !ok { 330 t.Error("expected reinsert to succeed") 331 } 332 } 333 334 func TestIntervalCacheClearWithAdjustedBounds(t *testing.T) { 335 ic := NewIntervalCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 336 entry1 := &Entry{Key: ic.NewKey([]byte("a"), []byte("bb")), Value: 1} 337 ic.AddEntry(entry1) 338 entry1.Key.(*IntervalKey).End = []byte("b") 339 entry2 := &Entry{Key: ic.NewKey([]byte("b"), []byte("e")), Value: 2} 340 ic.AddEntry(entry2) 341 entry2.Key.(*IntervalKey).End = []byte("c") 342 entry2Right := &Entry{Key: ic.NewKey([]byte("c\x00"), []byte("e")), Value: 3} 343 ic.AddEntry(entry2Right) 344 entry3 := &Entry{Key: ic.NewKey([]byte("c"), []byte("c\x00")), Value: 4} 345 ic.AddEntry(entry3) 346 ic.Clear() 347 if l := ic.Len(); l != 0 { 348 t.Errorf("expected cleared cache to have len 0, found %d", l) 349 } 350 } 351 352 func benchmarkCache(b *testing.B, c *baseCache, keys []interface{}) { 353 b.ResetTimer() 354 for i := 0; i < b.N; i++ { 355 for j := 0; j < len(keys); j++ { 356 c.Add(keys[j], j) 357 } 358 c.Clear() 359 } 360 } 361 362 func BenchmarkUnorderedCache(b *testing.B) { 363 mc := NewUnorderedCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 364 testKeys := []interface{}{ 365 testKey("a"), 366 testKey("b"), 367 testKey("c"), 368 testKey("d"), 369 testKey("e"), 370 } 371 benchmarkCache(b, &mc.baseCache, testKeys) 372 } 373 374 func BenchmarkOrderedCache(b *testing.B) { 375 oc := NewOrderedCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 376 testKeys := []interface{}{ 377 testKey("a"), 378 testKey("b"), 379 testKey("c"), 380 testKey("d"), 381 testKey("e"), 382 } 383 benchmarkCache(b, &oc.baseCache, testKeys) 384 } 385 386 func BenchmarkIntervalCache(b *testing.B) { 387 ic := NewIntervalCache(Config{Policy: CacheLRU, ShouldEvict: noEviction}) 388 testKeys := []interface{}{ 389 ic.NewKey([]byte("a"), []byte("c")), 390 ic.NewKey([]byte("b"), []byte("d")), 391 ic.NewKey([]byte("c"), []byte("e")), 392 ic.NewKey([]byte("d"), []byte("f")), 393 ic.NewKey([]byte("e"), []byte("g")), 394 } 395 benchmarkCache(b, &ic.baseCache, testKeys) 396 }