nimbus-eth1/tests/test_lru_cache.nim

230 lines
5.5 KiB
Nim
Raw Normal View History

# Nimbus
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
../nimbus/utils/lru_cache,
eth/rlp,
strformat,
tables,
unittest2
const
cacheLimit = 10
keyList = [
185, 208, 53, 54, 196, 189, 187, 117, 94, 29, 6, 173, 207, 45, 31,
208, 127, 106, 117, 49, 40, 171, 6, 94, 84, 60, 125, 87, 168, 183,
200, 155, 34, 27, 67, 107, 108, 223, 249, 4, 113, 9, 205, 100, 77,
224, 19, 196, 14, 83, 145, 154, 95, 56, 236, 97, 115, 140, 134, 97,
153, 167, 23, 17, 182, 116, 253, 32, 108, 148, 135, 169, 178, 124, 147,
231, 236, 174, 211, 247, 22, 118, 144, 224, 68, 124, 200, 92, 63, 183,
56, 107, 45, 180, 113, 233, 59, 246, 29, 212, 172, 161, 183, 207, 189,
56, 198, 130, 62, 28, 53, 122]
# Debugging output
proc say(noisy = false; pfx = "***"; args: varargs[string, `$`]) =
if noisy:
var outText = pfx & " "
for a in args.items:
outText &= a
echo outText
# Privy access to LRU internals
proc maxItems[T,K,V,E](cache: var LruCache[T,K,V,E]): int =
cache.specs[0]
proc first[T,K,V,E](cache: var LruCache[T,K,V,E]): K =
cache.specs[1]
proc last[T,K,V,E](cache: var LruCache[T,K,V,E]): K =
cache.specs[2]
proc tab[T,K,V,E](cache: var LruCache[T,K,V,E]): Table[K,LruItem[K,V]] =
cache.specs[3]
proc verifyLinks[T,K,V,E](lru: var LruCache[T,K,V,E]) =
var key = lru.first
if lru.tab.len == 1:
doAssert lru.tab.hasKey(key)
doAssert key == lru.last
elif 1 < lru.tab.len:
# forward links
for n in 1 ..< lru.tab.len:
var curKey = key
key = lru.tab[curKey].nxt
if lru.tab[key].prv != curKey:
echo &"({n}): lru.tab[{key}].prv == {lru.tab[key].prv} exp {curKey}"
doAssert lru.tab[key].prv == curKey
doAssert key == lru.last
# backward links
for n in 1 ..< lru.tab.len:
var curKey = key
key = lru.tab[curKey].prv
if lru.tab[key].nxt != curKey:
echo &"({n}): lru.tab[{key}].nxt == {lru.tab[key].nxt} exp {curKey}"
doAssert lru.tab[key].nxt == curKey
doAssert key == lru.first
proc toKeyList[T,K,V,E](lru: var LruCache[T,K,V,E]): seq[K] =
lru.verifyLinks
if 0 < lru.tab.len:
var key = lru.first
while key != lru.last:
result.add key
key = lru.tab[key].nxt
result.add lru.last
proc toValueList[T,K,V,E](lru: var LruCache[T,K,V,E]): seq[V] =
lru.verifyLinks
if 0 < lru.tab.len:
var key = lru.first
while key != lru.last:
result.add lru.tab[key].value
key = lru.tab[key].nxt
result.add lru.tab[lru.last].value
proc createTestCache: LruCache[int,int,string,int] =
var
getKey: LruKey[int,int] =
proc(x: int): int = x
getValue: LruValue[int,string,int] =
proc(x: int): Result[string,int] = ok($x)
cache: LruCache[int,int,string,int]
# Create LRU cache
cache.initLruCache(getKey, getValue, cacheLimit)
result = cache
proc filledTestCache(noisy: bool): LruCache[int,int,string,int] =
var
cache = createTestCache()
lastQ: seq[int]
for w in keyList:
var
key = w mod 13
reSched = cache.tab.hasKey(key)
value = cache.getLruItem(key)
queue = cache.toKeyList
values = cache.toValueList
# verfy key/value pairs
for n in 0 ..< queue.len:
doAssert $queue[n] == $values[n]
if reSched:
noisy.say ">>>", &"rotate {value} => {queue}"
else:
noisy.say "+++", &"append {value} => {queue}"
result = cache
# ---
proc doFillUpTest(noisy: bool) =
discard filledTestCache(noisy)
proc doDeepCopyTest(noisy: bool) =
proc say(a: varargs[string]) =
say(noisy = noisy, args = a)
var
c1 = filledTestCache(false)
c2 = c1
doAssert c1 == c2
discard c1.getLruItem(77)
say &"c1Specs: {c1.maxItems} {c1.first} {c1.last} ..."
say &"c2Specs: {c2.maxItems} {c2.first} {c2.last} ..."
doAssert c1 != c2
doAssert c1.tab != c2.tab
proc doSerialiserTest(noisy: bool) =
proc say(a: varargs[string]) =
say(noisy = noisy, args = a)
var
c1 = filledTestCache(false)
s1 = rlp.encode(c1.data)
c2 = createTestCache()
say &"serialised[{s1.len}]: {s1}"
c2.clearLruCache
doAssert c1 != c2
c2.data = s1.decode(type c2.data)
doAssert c1 == c2
say &"c2Specs: {c2.maxItems} {c2.first} {c2.last} ..."
doAssert s1 == rlp.encode(c2.data)
proc doSerialiseSingleEntry(noisy: bool) =
proc say(a: varargs[string]) =
say(noisy = noisy, args = a)
var
c1 = createTestCache()
value = c1.getLruItem(77)
queue = c1.toKeyList
values = c1.toValueList
say &"c1: append {value} => {queue}"
var
s1 = rlp.encode(c1.data)
c2 = createTestCache()
say &"serialised[{s1.len}]: {s1}"
c2.clearLruCache
doAssert c1 != c2
c2.data = s1.decode(type c2.data)
doAssert c1 == c2
say &"c2Specs: {c2.maxItems} {c2.first} {c2.last} ..."
doAssert s1 == rlp.encode(c2.data)
proc lruCacheMain*(noisy = defined(debug)) =
suite "LRU Cache":
test "Fill Up":
doFillUpTest(noisy)
test "Deep Copy Semantics":
doDeepCopyTest(noisy)
test "Rlp Serialise & Load":
doSerialiserTest(noisy)
test "Rlp Single Entry Test":
doSerialiseSingleEntry(noisy)
when isMainModule:
lruCacheMain()
# End