github.com/theQRL/go-zond@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 // Test that Peek doesn't update recent-ness 174 func TestBasicLRUPeek(t *testing.T) { 175 cache := NewBasicLRU[int, int](2) 176 cache.Add(1, 1) 177 cache.Add(2, 2) 178 if v, ok := cache.Peek(1); !ok || v != 1 { 179 t.Errorf("1 should be set to 1") 180 } 181 cache.Add(3, 3) 182 if cache.Contains(1) { 183 t.Errorf("should not have updated recent-ness of 1") 184 } 185 } 186 187 func BenchmarkLRU(b *testing.B) { 188 var ( 189 capacity = 1000 190 indexes = make([]int, capacity*20) 191 keys = make([]string, capacity) 192 values = make([][]byte, capacity) 193 ) 194 for i := range indexes { 195 indexes[i] = rand.Intn(capacity) 196 } 197 for i := range keys { 198 b := make([]byte, 32) 199 crand.Read(b) 200 keys[i] = string(b) 201 crand.Read(b) 202 values[i] = b 203 } 204 205 var sink []byte 206 207 b.Run("Add/BasicLRU", func(b *testing.B) { 208 cache := NewBasicLRU[int, int](capacity) 209 for i := 0; i < b.N; i++ { 210 cache.Add(i, i) 211 } 212 }) 213 b.Run("Get/BasicLRU", func(b *testing.B) { 214 cache := NewBasicLRU[string, []byte](capacity) 215 for i := 0; i < capacity; i++ { 216 index := indexes[i] 217 cache.Add(keys[index], values[index]) 218 } 219 220 b.ResetTimer() 221 for i := 0; i < b.N; i++ { 222 k := keys[indexes[i%len(indexes)]] 223 v, ok := cache.Get(k) 224 if ok { 225 sink = v 226 } 227 } 228 }) 229 230 // // vs. github.com/hashicorp/golang-lru/simplelru 231 // b.Run("Add/simplelru.LRU", func(b *testing.B) { 232 // cache, _ := simplelru.NewLRU(capacity, nil) 233 // for i := 0; i < b.N; i++ { 234 // cache.Add(i, i) 235 // } 236 // }) 237 // b.Run("Get/simplelru.LRU", func(b *testing.B) { 238 // cache, _ := simplelru.NewLRU(capacity, nil) 239 // for i := 0; i < capacity; i++ { 240 // index := indexes[i] 241 // cache.Add(keys[index], values[index]) 242 // } 243 // 244 // b.ResetTimer() 245 // for i := 0; i < b.N; i++ { 246 // k := keys[indexes[i%len(indexes)]] 247 // v, ok := cache.Get(k) 248 // if ok { 249 // sink = v.([]byte) 250 // } 251 // } 252 // }) 253 254 fmt.Fprintln(io.Discard, sink) 255 }