mirror of
https://github.com/FlipsideCrypto/dcrd.git
synced 2026-02-06 10:56:47 +00:00
155 lines
4.6 KiB
Go
155 lines
4.6 KiB
Go
// Copyright (c) 2019 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package lru
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// TestCache ensures the LRU Cache behaves as expected including limiting,
|
|
// eviction of least-recently used entries, specific entry removal, and
|
|
// existence tests.
|
|
func TestCache(t *testing.T) {
|
|
// Create a bunch of fake nonces to use in testing the lru nonce code.
|
|
numNonces := 10
|
|
nonces := make([]uint64, 0, numNonces)
|
|
for i := 0; i < numNonces; i++ {
|
|
nonces = append(nonces, uint64(i))
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
limit int
|
|
}{
|
|
{name: "limit 0", limit: 0},
|
|
{name: "limit 1", limit: 1},
|
|
{name: "limit 5", limit: 5},
|
|
{name: "limit 7", limit: 7},
|
|
{name: "limit one less than available", limit: numNonces - 1},
|
|
{name: "limit all available", limit: numNonces},
|
|
}
|
|
|
|
testLoop:
|
|
for i, test := range tests {
|
|
// Create a new lru cache limited by the specified test limit and add
|
|
// all of the test vectors. This will cause eviction since there are
|
|
// more test items than the limits.
|
|
cache := NewCache(uint(test.limit))
|
|
for j := 0; j < numNonces; j++ {
|
|
cache.Add(nonces[j])
|
|
}
|
|
|
|
// Ensure the limited number of most recent entries in the list exist.
|
|
for j := numNonces - test.limit; j < numNonces; j++ {
|
|
if !cache.Contains(nonces[j]) {
|
|
t.Errorf("Contains #%d (%s) entry %d does not exist", i,
|
|
test.name, nonces[j])
|
|
continue testLoop
|
|
}
|
|
}
|
|
|
|
// Ensure the entries before the limited number of most recent entries
|
|
// in the list do not exist.
|
|
for j := 0; j < numNonces-test.limit; j++ {
|
|
if cache.Contains(nonces[j]) {
|
|
t.Errorf("Contains #%d (%s) entry %d exists", i, test.name,
|
|
nonces[j])
|
|
continue testLoop
|
|
}
|
|
}
|
|
|
|
// Access the entry that should currently be the least-recently used
|
|
// entry so it becomes the most-recently used entry, then force an
|
|
// eviction by adding an entry that doesn't exist and ensure the evicted
|
|
// entry is the new least-recently used entry.
|
|
//
|
|
// This check needs at least 2 entries.
|
|
if test.limit > 1 {
|
|
origLruIndex := numNonces - test.limit
|
|
_ = cache.Contains(nonces[origLruIndex])
|
|
|
|
cache.Add(uint64(numNonces) + 1)
|
|
|
|
// Ensure the original lru entry still exists since it was updated
|
|
// and should have become the lru entry.
|
|
if !cache.Contains(nonces[origLruIndex]) {
|
|
t.Errorf("Contains #%d (%s) entry %d does not exist", i, test.name,
|
|
nonces[origLruIndex])
|
|
continue testLoop
|
|
}
|
|
|
|
// Ensure the entry that should've become the new lru entry was
|
|
// evicted.
|
|
newLruIndex := origLruIndex + 1
|
|
if cache.Contains(nonces[newLruIndex]) {
|
|
t.Errorf("Contains #%d (%s) entry %d exists", i, test.name,
|
|
nonces[newLruIndex])
|
|
continue testLoop
|
|
}
|
|
}
|
|
|
|
// Add the entry that should currently be the least-recently used entry
|
|
// again so it becomes the most-recently used entry, then force an
|
|
// eviction by adding an entry that doesn't exist and ensure the evicted
|
|
// entry is the new least-recently used entry.
|
|
//
|
|
// This check needs at least 2 entries.
|
|
if test.limit > 1 {
|
|
origLruIndex := numNonces - test.limit
|
|
cache.Add(nonces[origLruIndex])
|
|
|
|
cache.Add(uint64(numNonces) + 2)
|
|
|
|
// Ensure the original lru entry still exists since it was updated
|
|
// and should've have become the lru entry.
|
|
if !cache.Contains(nonces[origLruIndex]) {
|
|
t.Errorf("Contains #%d (%s) entry %d does not exist", i, test.name,
|
|
nonces[origLruIndex])
|
|
continue testLoop
|
|
}
|
|
|
|
// Ensure the entry that should've become the new lru entry was
|
|
// evicted.
|
|
newLruIndex := origLruIndex + 1
|
|
if cache.Contains(nonces[newLruIndex]) {
|
|
t.Errorf("Contains #%d (%s) entry %d exists", i, test.name,
|
|
nonces[newLruIndex])
|
|
continue testLoop
|
|
}
|
|
}
|
|
|
|
// Delete all of the entries in the list, including those that don't
|
|
// exist in the cache, and ensure they no longer exist.
|
|
for j := 0; j < numNonces; j++ {
|
|
cache.Delete(nonces[j])
|
|
if cache.Contains(nonces[j]) {
|
|
t.Errorf("Delete #%d (%s) entry %d exists", i, test.name,
|
|
nonces[j])
|
|
continue testLoop
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// BenchmarkCache performs basic benchmarks on the least recently used cache
|
|
// handling.
|
|
func BenchmarkCache(b *testing.B) {
|
|
// Create a bunch of fake nonces to use in benchmarking the lru nonce code.
|
|
b.StopTimer()
|
|
numNonces := 100000
|
|
nonces := make([]uint64, 0, numNonces)
|
|
for i := 0; i < numNonces; i++ {
|
|
nonces = append(nonces, uint64(i))
|
|
}
|
|
b.StartTimer()
|
|
|
|
// Benchmark the add plus eviction code.
|
|
limit := uint(20000)
|
|
cache := NewCache(limit)
|
|
for i := 0; i < b.N; i++ {
|
|
cache.Add(nonces[i%numNonces])
|
|
}
|
|
}
|