github.com/jimmyx0x/go-ethereum@v1.10.28/common/lru/basiclru_test.go (about)

     1  // Copyright 2022 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package lru
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"math/rand"
    23  	"testing"
    24  )
    25  
    26  // Some of these test cases were adapted
    27  // from https://github.com/hashicorp/golang-lru/blob/master/simplelru/lru_test.go
    28  
    29  func TestBasicLRU(t *testing.T) {
    30  	cache := NewBasicLRU[int, int](128)
    31  
    32  	for i := 0; i < 256; i++ {
    33  		cache.Add(i, i)
    34  	}
    35  	if cache.Len() != 128 {
    36  		t.Fatalf("bad len: %v", cache.Len())
    37  	}
    38  
    39  	// Check that Keys returns least-recent key first.
    40  	keys := cache.Keys()
    41  	if len(keys) != 128 {
    42  		t.Fatal("wrong Keys() length", len(keys))
    43  	}
    44  	for i, k := range keys {
    45  		v, ok := cache.Peek(k)
    46  		if !ok {
    47  			t.Fatalf("expected key %d be present", i)
    48  		}
    49  		if v != k {
    50  			t.Fatalf("expected %d == %d", k, v)
    51  		}
    52  		if v != i+128 {
    53  			t.Fatalf("wrong value at key %d: %d, want %d", i, v, i+128)
    54  		}
    55  	}
    56  
    57  	for i := 0; i < 128; i++ {
    58  		_, ok := cache.Get(i)
    59  		if ok {
    60  			t.Fatalf("%d should be evicted", i)
    61  		}
    62  	}
    63  	for i := 128; i < 256; i++ {
    64  		_, ok := cache.Get(i)
    65  		if !ok {
    66  			t.Fatalf("%d should not be evicted", i)
    67  		}
    68  	}
    69  
    70  	for i := 128; i < 192; i++ {
    71  		ok := cache.Remove(i)
    72  		if !ok {
    73  			t.Fatalf("%d should be in cache", i)
    74  		}
    75  		ok = cache.Remove(i)
    76  		if ok {
    77  			t.Fatalf("%d should not be in cache", i)
    78  		}
    79  		_, ok = cache.Get(i)
    80  		if ok {
    81  			t.Fatalf("%d should be deleted", i)
    82  		}
    83  	}
    84  
    85  	// Request item 192.
    86  	cache.Get(192)
    87  	// It should be the last item returned by Keys().
    88  	for i, k := range cache.Keys() {
    89  		if (i < 63 && k != i+193) || (i == 63 && k != 192) {
    90  			t.Fatalf("out of order key: %v", k)
    91  		}
    92  	}
    93  
    94  	cache.Purge()
    95  	if cache.Len() != 0 {
    96  		t.Fatalf("bad len: %v", cache.Len())
    97  	}
    98  	if _, ok := cache.Get(200); ok {
    99  		t.Fatalf("should contain nothing")
   100  	}
   101  }
   102  
   103  func TestBasicLRUAddExistingKey(t *testing.T) {
   104  	cache := NewBasicLRU[int, int](1)
   105  
   106  	cache.Add(1, 1)
   107  	cache.Add(1, 2)
   108  
   109  	v, _ := cache.Get(1)
   110  	if v != 2 {
   111  		t.Fatal("wrong value:", v)
   112  	}
   113  }
   114  
   115  // This test checks GetOldest and RemoveOldest.
   116  func TestBasicLRUGetOldest(t *testing.T) {
   117  	cache := NewBasicLRU[int, int](128)
   118  	for i := 0; i < 256; i++ {
   119  		cache.Add(i, i)
   120  	}
   121  
   122  	k, _, ok := cache.GetOldest()
   123  	if !ok {
   124  		t.Fatalf("missing")
   125  	}
   126  	if k != 128 {
   127  		t.Fatalf("bad: %v", k)
   128  	}
   129  
   130  	k, _, ok = cache.RemoveOldest()
   131  	if !ok {
   132  		t.Fatalf("missing")
   133  	}
   134  	if k != 128 {
   135  		t.Fatalf("bad: %v", k)
   136  	}
   137  
   138  	k, _, ok = cache.RemoveOldest()
   139  	if !ok {
   140  		t.Fatalf("missing oldest item")
   141  	}
   142  	if k != 129 {
   143  		t.Fatalf("wrong oldest item: %v", k)
   144  	}
   145  }
   146  
   147  // Test that Add returns true/false if an eviction occurred
   148  func TestBasicLRUAddReturnValue(t *testing.T) {
   149  	cache := NewBasicLRU[int, int](1)
   150  	if cache.Add(1, 1) {
   151  		t.Errorf("first add shouldn't have evicted")
   152  	}
   153  	if !cache.Add(2, 2) {
   154  		t.Errorf("second add should have evicted")
   155  	}
   156  }
   157  
   158  // This test verifies that Contains doesn't change item recency.
   159  func TestBasicLRUContains(t *testing.T) {
   160  	cache := NewBasicLRU[int, int](2)
   161  	cache.Add(1, 1)
   162  	cache.Add(2, 2)
   163  	if !cache.Contains(1) {
   164  		t.Errorf("1 should be in the cache")
   165  	}
   166  	cache.Add(3, 3)
   167  	if cache.Contains(1) {
   168  		t.Errorf("Contains should not have updated recency of 1")
   169  	}
   170  }
   171  
   172  func BenchmarkLRU(b *testing.B) {
   173  	var (
   174  		capacity = 1000
   175  		indexes  = make([]int, capacity*20)
   176  		keys     = make([]string, capacity)
   177  		values   = make([][]byte, capacity)
   178  	)
   179  	for i := range indexes {
   180  		indexes[i] = rand.Intn(capacity)
   181  	}
   182  	for i := range keys {
   183  		b := make([]byte, 32)
   184  		rand.Read(b)
   185  		keys[i] = string(b)
   186  		rand.Read(b)
   187  		values[i] = b
   188  	}
   189  
   190  	var sink []byte
   191  
   192  	b.Run("Add/BasicLRU", func(b *testing.B) {
   193  		cache := NewBasicLRU[int, int](capacity)
   194  		for i := 0; i < b.N; i++ {
   195  			cache.Add(i, i)
   196  		}
   197  	})
   198  	b.Run("Get/BasicLRU", func(b *testing.B) {
   199  		cache := NewBasicLRU[string, []byte](capacity)
   200  		for i := 0; i < capacity; i++ {
   201  			index := indexes[i]
   202  			cache.Add(keys[index], values[index])
   203  		}
   204  
   205  		b.ResetTimer()
   206  		for i := 0; i < b.N; i++ {
   207  			k := keys[indexes[i%len(indexes)]]
   208  			v, ok := cache.Get(k)
   209  			if ok {
   210  				sink = v
   211  			}
   212  		}
   213  	})
   214  
   215  	// // vs. github.com/hashicorp/golang-lru/simplelru
   216  	// b.Run("Add/simplelru.LRU", func(b *testing.B) {
   217  	//	cache, _ := simplelru.NewLRU(capacity, nil)
   218  	//	for i := 0; i < b.N; i++ {
   219  	//		cache.Add(i, i)
   220  	//	}
   221  	// })
   222  	// b.Run("Get/simplelru.LRU", func(b *testing.B) {
   223  	//	cache, _ := simplelru.NewLRU(capacity, nil)
   224  	//	for i := 0; i < capacity; i++ {
   225  	//		index := indexes[i]
   226  	//		cache.Add(keys[index], values[index])
   227  	//	}
   228  	//
   229  	//	b.ResetTimer()
   230  	//	for i := 0; i < b.N; i++ {
   231  	//		k := keys[indexes[i%len(indexes)]]
   232  	//		v, ok := cache.Get(k)
   233  	//		if ok {
   234  	//			sink = v.([]byte)
   235  	//		}
   236  	//	}
   237  	// })
   238  
   239  	fmt.Fprintln(io.Discard, sink)
   240  }