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  }