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  }