mirror of https://github.com/status-im/nim-eth.git
discv5: migrate to minilru (#741)
As it happens, the two share the exact same interface (even the test suite removed in this PR passes) - `minilru` has an edge on efficiency however, avoiding the doubly linked list node allocations etc
This commit is contained in:
parent
5ce3c4557f
commit
84664b0fc0
|
@ -19,7 +19,8 @@ requires "nim >= 1.6.0",
|
||||||
"confutils",
|
"confutils",
|
||||||
"testutils",
|
"testutils",
|
||||||
"unittest2",
|
"unittest2",
|
||||||
"results"
|
"results",
|
||||||
|
"minilru"
|
||||||
|
|
||||||
let nimc = getEnv("NIMC", "nim") # Which nim compiler to use
|
let nimc = getEnv("NIMC", "nim") # Which nim compiler to use
|
||||||
let lang = getEnv("NIMLANG", "c") # Which backend (c/cpp/js)
|
let lang = getEnv("NIMLANG", "c") # Which backend (c/cpp/js)
|
||||||
|
|
|
@ -6,46 +6,9 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
{.deprecated: "Use minilru directly".}
|
||||||
|
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import std/[tables, lists], results
|
import minilru
|
||||||
|
export minilru
|
||||||
export results
|
|
||||||
|
|
||||||
type
|
|
||||||
LRUCache*[K, V] = object of RootObj
|
|
||||||
list: DoublyLinkedList[(K, V)] # Head is MRU k:v and tail is LRU k:v
|
|
||||||
table: Table[K, DoublyLinkedNode[(K, V)]] # DoublyLinkedNode is already ref
|
|
||||||
capacity: int
|
|
||||||
|
|
||||||
func init*[K, V](T: type LRUCache[K, V], capacity: int): LRUCache[K, V] =
|
|
||||||
LRUCache[K, V](capacity: capacity) # Table and list init is done default
|
|
||||||
|
|
||||||
func get*[K, V](lru: var LRUCache[K, V], key: K): Opt[V] =
|
|
||||||
let node = lru.table.getOrDefault(key, nil)
|
|
||||||
if node.isNil:
|
|
||||||
return Opt.none(V)
|
|
||||||
|
|
||||||
lru.list.remove(node)
|
|
||||||
lru.list.prepend(node)
|
|
||||||
return Opt.some(node.value[1])
|
|
||||||
|
|
||||||
func put*[K, V](lru: var LRUCache[K, V], key: K, value: V) =
|
|
||||||
let node = lru.table.getOrDefault(key, nil)
|
|
||||||
if not node.isNil:
|
|
||||||
lru.list.remove(node)
|
|
||||||
else:
|
|
||||||
if lru.table.len >= lru.capacity:
|
|
||||||
lru.table.del(lru.list.tail.value[0])
|
|
||||||
lru.list.remove(lru.list.tail)
|
|
||||||
|
|
||||||
lru.list.prepend((key, value))
|
|
||||||
lru.table[key] = lru.list.head
|
|
||||||
|
|
||||||
func del*[K, V](lru: var LRUCache[K, V], key: K) =
|
|
||||||
var node: DoublyLinkedNode[(K, V)]
|
|
||||||
if lru.table.pop(key, node):
|
|
||||||
lru.list.remove(node)
|
|
||||||
|
|
||||||
func len*[K, V](lru: LRUCache[K, V]): int =
|
|
||||||
lru.table.len
|
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
import
|
import
|
||||||
std/net,
|
std/net,
|
||||||
stint, stew/endians2,
|
stint, stew/endians2,
|
||||||
node, lru
|
./node, minilru
|
||||||
|
|
||||||
export lru
|
export minilru
|
||||||
|
|
||||||
const
|
const
|
||||||
aesKeySize* = 128 div 8
|
aesKeySize* = 128 div 8
|
||||||
|
@ -28,7 +28,7 @@ type
|
||||||
AesKey* = array[aesKeySize, byte]
|
AesKey* = array[aesKeySize, byte]
|
||||||
SessionKey* = array[keySize, byte]
|
SessionKey* = array[keySize, byte]
|
||||||
SessionValue* = array[sizeof(AesKey) + sizeof(AesKey), byte]
|
SessionValue* = array[sizeof(AesKey) + sizeof(AesKey), byte]
|
||||||
Sessions* = LRUCache[SessionKey, SessionValue]
|
Sessions* = LruCache[SessionKey, SessionValue]
|
||||||
|
|
||||||
func makeKey(id: NodeId, address: Address): SessionKey =
|
func makeKey(id: NodeId, address: Address): SessionKey =
|
||||||
var pos = 0
|
var pos = 0
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import
|
import
|
||||||
./test_enr,
|
./test_enr,
|
||||||
./test_hkdf,
|
./test_hkdf,
|
||||||
./test_lru,
|
|
||||||
./test_ip_vote,
|
./test_ip_vote,
|
||||||
./test_routing_table,
|
./test_routing_table,
|
||||||
./test_discoveryv5_encoding,
|
./test_discoveryv5_encoding,
|
||||||
|
|
|
@ -1,134 +0,0 @@
|
||||||
{.used.}
|
|
||||||
|
|
||||||
import
|
|
||||||
std/options,
|
|
||||||
unittest2,
|
|
||||||
../../eth/p2p/discoveryv5/lru
|
|
||||||
|
|
||||||
suite "LRUCache":
|
|
||||||
const
|
|
||||||
capacity = 10
|
|
||||||
target = 4
|
|
||||||
test "LRU value gets removed":
|
|
||||||
var lru = LRUCache[int, int].init(capacity = capacity)
|
|
||||||
|
|
||||||
# Fully fill the LRU
|
|
||||||
for i in 0..<capacity:
|
|
||||||
lru.put(i, i) # new key, so new put
|
|
||||||
|
|
||||||
# Get value for each key
|
|
||||||
for i in 0..<capacity:
|
|
||||||
let val = lru.get(i)
|
|
||||||
check:
|
|
||||||
val.isSome()
|
|
||||||
val.get() == i
|
|
||||||
|
|
||||||
check lru.len() == capacity
|
|
||||||
|
|
||||||
# Add one new key
|
|
||||||
lru.put(capacity, 0)
|
|
||||||
# Oldest one should be gone
|
|
||||||
check:
|
|
||||||
lru.len() == capacity
|
|
||||||
lru.get(0).isNone()
|
|
||||||
lru.get(capacity).isSome()
|
|
||||||
|
|
||||||
test "LRU renew oldest by get":
|
|
||||||
var lru = LRUCache[int, int].init(capacity = capacity)
|
|
||||||
|
|
||||||
for i in 0..<capacity:
|
|
||||||
lru.put(i, i)
|
|
||||||
|
|
||||||
var val = lru.get(0)
|
|
||||||
check:
|
|
||||||
val.isSome
|
|
||||||
val.get() == 0
|
|
||||||
|
|
||||||
lru.put(capacity, 0)
|
|
||||||
|
|
||||||
val = lru.get(0)
|
|
||||||
check:
|
|
||||||
lru.len() == capacity
|
|
||||||
val.isSome()
|
|
||||||
val.get() == 0
|
|
||||||
|
|
||||||
test "LRU renew oldest by put":
|
|
||||||
var lru = LRUCache[int, int].init(capacity = capacity)
|
|
||||||
|
|
||||||
for i in 0..<capacity:
|
|
||||||
lru.put(i, i)
|
|
||||||
|
|
||||||
lru.put(0, 1)
|
|
||||||
check lru.len() == capacity
|
|
||||||
|
|
||||||
lru.put(capacity, 0)
|
|
||||||
|
|
||||||
let val = lru.get(0)
|
|
||||||
check:
|
|
||||||
lru.len() == capacity
|
|
||||||
val.isSome()
|
|
||||||
val.get() == 1
|
|
||||||
|
|
||||||
test "LRU renew by put":
|
|
||||||
var lru = LRUCache[int, int].init(capacity = capacity)
|
|
||||||
|
|
||||||
for i in 0..<capacity:
|
|
||||||
lru.put(i, i)
|
|
||||||
|
|
||||||
lru.put(target, 1)
|
|
||||||
check lru.len() == capacity
|
|
||||||
|
|
||||||
lru.put(capacity, 0)
|
|
||||||
|
|
||||||
let val = lru.get(target)
|
|
||||||
check:
|
|
||||||
lru.len() == capacity
|
|
||||||
val.isSome()
|
|
||||||
val.get() == 1
|
|
||||||
|
|
||||||
test "LRU renew by get":
|
|
||||||
var lru = LRUCache[int, int].init(capacity = capacity)
|
|
||||||
|
|
||||||
for i in 0..<capacity:
|
|
||||||
lru.put(i, i)
|
|
||||||
|
|
||||||
var val = lru.get(target)
|
|
||||||
check:
|
|
||||||
val.isSome
|
|
||||||
val.get() == target
|
|
||||||
|
|
||||||
lru.put(capacity, 0)
|
|
||||||
|
|
||||||
val = lru.get(target)
|
|
||||||
check:
|
|
||||||
lru.len() == capacity
|
|
||||||
val.isSome()
|
|
||||||
val.get() == target
|
|
||||||
|
|
||||||
test "LRU delete oldest and add":
|
|
||||||
var lru = LRUCache[int, int].init(capacity = capacity)
|
|
||||||
|
|
||||||
for i in 0..<capacity:
|
|
||||||
lru.put(i, i)
|
|
||||||
|
|
||||||
lru.del(0)
|
|
||||||
check lru.len == capacity - 1
|
|
||||||
|
|
||||||
lru.put(0, 1)
|
|
||||||
check lru.len == capacity
|
|
||||||
|
|
||||||
lru.put(capacity, 0)
|
|
||||||
|
|
||||||
let val = lru.get(0)
|
|
||||||
check:
|
|
||||||
lru.len() == capacity
|
|
||||||
val.isSome()
|
|
||||||
val.get() == 1
|
|
||||||
test "LRU delete not existing":
|
|
||||||
var lru = LRUCache[int, int].init(capacity = capacity)
|
|
||||||
|
|
||||||
for i in 0..<capacity:
|
|
||||||
lru.put(i, i)
|
|
||||||
|
|
||||||
lru.del(capacity)
|
|
||||||
check lru.len == capacity
|
|
Loading…
Reference in New Issue