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