github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/data/cache/fastcache/fastcache_gen_test.go (about) 1 package fastcache 2 3 import ( 4 "bytes" 5 "strconv" 6 "testing" 7 ) 8 9 func TestGenerationOverflow(t *testing.T) { 10 c := New(1) // each bucket has 64 *1024 bytes capacity 11 12 // Initial generation is 1 13 genVal(t, c, 1) 14 15 // These two keys has to the same bucket (100), so we can push the 16 // generations up much faster. The keys and values are sized so that 17 // every time we push them into the cache they will completely fill the 18 // bucket 19 key1 := []byte(strconv.Itoa(26)) 20 bigVal1 := make([]byte, (32*1024)-(len(key1)+4)) 21 for i := range bigVal1 { 22 bigVal1[i] = 1 23 } 24 key2 := []byte(strconv.Itoa(8)) 25 bigVal2 := make([]byte, (32*1024)-(len(key2)+5)) 26 for i := range bigVal2 { 27 bigVal2[i] = 2 28 } 29 30 // Do some initial Set/Get demonstrate that this works 31 for i := 0; i < 10; i++ { 32 c.Set(key1, bigVal1) 33 c.Set(key2, bigVal2) 34 getVal(t, c, key1, bigVal1) 35 getVal(t, c, key2, bigVal2) 36 genVal(t, c, uint64(1+i)) 37 } 38 39 // This is a hack to simulate calling Set 2^24-3 times 40 // Actually doing this takes ~24 seconds, making the test slow 41 c.buckets[100].gen = (1 << 24) - 2 42 43 // c.buckets[100].gen == 16,777,215 44 // Set/Get still works 45 46 c.Set(key1, bigVal1) 47 c.Set(key2, bigVal2) 48 49 getVal(t, c, key1, bigVal1) 50 getVal(t, c, key2, bigVal2) 51 52 genVal(t, c, (1<<24)-1) 53 54 // After the next Set operations 55 // c.buckets[100].gen == 16,777,216 56 57 // This set creates an index where `idx | (b.gen << bucketSizeBits)` == 0 58 // The value is in the cache but is unreadable by Get 59 c.Set(key1, bigVal1) 60 61 // The Set above overflowed the bucket's generation. This means that 62 // key2 is still in the cache, but can't get read because key2 has a 63 // _very large_ generation value and appears to be from the future 64 getVal(t, c, key2, bigVal2) 65 66 // This Set creates an index where `(b.gen << bucketSizeBits)>>bucketSizeBits)==0` 67 // The value is in the cache but is unreadable by Get 68 c.Set(key2, bigVal2) 69 70 // Ensure generations are working as we expect 71 // NB: Here we skip the 2^24 generation, because the bucket carefully 72 // avoids `generation==0` 73 genVal(t, c, (1<<24)+1) 74 75 getVal(t, c, key1, bigVal1) 76 getVal(t, c, key2, bigVal2) 77 78 // Do it a few more times to show that this bucket is now unusable 79 for i := 0; i < 10; i++ { 80 c.Set(key1, bigVal1) 81 c.Set(key2, bigVal2) 82 getVal(t, c, key1, bigVal1) 83 getVal(t, c, key2, bigVal2) 84 genVal(t, c, uint64((1<<24)+2+i)) 85 } 86 } 87 88 func getVal(t *testing.T, c *Cache, key, expected []byte) { 89 t.Helper() 90 get := c.Get(nil, key) 91 if !bytes.Equal(get, expected) { 92 t.Errorf("Expected value (%v) was not returned from the cache, instead got %v", expected[:10], get) 93 } 94 } 95 96 func genVal(t *testing.T, c *Cache, expected uint64) { 97 t.Helper() 98 actual := c.buckets[100].gen 99 // Ensure generations are working as we expect 100 if actual != expected { 101 t.Fatalf("Expected generation to be %d found %d instead", expected, actual) 102 } 103 }