2023-12-19 12:39:23 +00:00
|
|
|
# nimbus-eth1
|
Core db update storage root management for sub tries (#1964)
* Aristo: Re-phrase `LayerDelta` and `LayerFinal` as object references
why:
Avoids copying in some cases
* Fix copyright header
* Aristo: Verify `leafTie.root` function argument for `merge()` proc
why:
Zero root will lead to inconsistent DB entry
* Aristo: Update failure condition for hash labels compiler `hashify()`
why:
Node need not be rejected as long as links are on the schedule. In
that case, `redo[]` is to become `wff.base[]` at a later stage.
This amends an earlier fix, part of #1952 by also testing against
the target nodes of the `wff.base[]` sets.
* Aristo: Add storage root glue record to `hashify()` schedule
why:
An account leaf node might refer to a non-resolvable storage root ID.
Storage root node chains will end up at the storage root. So the link
`storage-root->account-leaf` needs an extra item in the schedule.
* Aristo: fix error code returned by `fetchPayload()`
details:
Final error code is implied by the error code form the `hikeUp()`
function.
* CoreDb: Discard `createOk` argument in API `getRoot()` function
why:
Not needed for the legacy DB. For the `Arsto` DB, a lazy approach is
implemented where a stprage root node is created on-the-fly.
* CoreDb: Prevent `$$` logging in some cases
why:
Logging the function `$$` is not useful when it is used for internal
use, i.e. retrieving an an error text for logging.
* CoreDb: Add `tryHashFn()` to API for pretty printing
why:
Pretty printing must not change the hashification status for the
`Aristo` DB. So there is an independent API wrapper for getting the
node hash which never updated the hashes.
* CoreDb: Discard `update` argument in API `hash()` function
why:
When calling the API function `hash()`, the latest state is always
wanted. For a version that uses the current state as-is without checking,
the function `tryHash()` was added to the backend.
* CoreDb: Update opaque vertex ID objects for the `Aristo` backend
why:
For `Aristo`, vID objects encapsulate a numeric `VertexID`
referencing a vertex (rather than a node hash as used on the
legacy backend.) For storage sub-tries, there might be no initial
vertex known when the descriptor is created. So opaque vertex ID
objects are supported without a valid `VertexID` which will be
initalised on-the-fly when the first item is merged.
* CoreDb: Add pretty printer for opaque vertex ID objects
* Cosmetics, printing profiling data
* CoreDb: Fix segfault in `Aristo` backend when creating MPT descriptor
why:
Missing initialisation error
* CoreDb: Allow MPT to inherit shared context on `Aristo` backend
why:
Creates descriptors with different storage roots for the same
shared `Aristo` DB descriptor.
* Cosmetics, update diagnostic message items for `Aristo` backend
* Fix Copyright year
2024-01-11 19:11:38 +00:00
|
|
|
# Copyright (c) 2023-2024 Status Research & Development GmbH
|
2023-12-19 12:39:23 +00:00
|
|
|
# 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.
|
|
|
|
|
|
|
|
{.push raises: [].}
|
|
|
|
|
|
|
|
import
|
2024-07-18 07:13:56 +00:00
|
|
|
std/[enumerate, sequtils, sets, tables],
|
2023-12-19 12:39:23 +00:00
|
|
|
eth/common,
|
|
|
|
results,
|
|
|
|
./aristo_desc
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Private functions
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
2024-07-04 13:46:52 +00:00
|
|
|
func dup(sTab: Table[RootedVertexID,VertexRef]): Table[RootedVertexID,VertexRef] =
|
2023-12-19 12:39:23 +00:00
|
|
|
## Explicit dup for `VertexRef` values
|
|
|
|
for (k,v) in sTab.pairs:
|
|
|
|
result[k] = v.dup
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Public getters: lazy value lookup for read only versions
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
2024-06-04 15:05:13 +00:00
|
|
|
func vTop*(db: AristoDbRef): VertexID =
|
|
|
|
db.top.delta.vTop
|
2023-12-19 12:39:23 +00:00
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Public getters/helpers
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
func nLayersVtx*(db: AristoDbRef): int =
|
2024-02-22 08:24:58 +00:00
|
|
|
## Number of vertex ID/vertex entries on the cache layers. This is an upper
|
|
|
|
## bound for the number of effective vertex ID mappings held on the cache
|
|
|
|
## layers as there might be duplicate entries for the same vertex ID on
|
|
|
|
## different layers.
|
2024-02-14 19:11:59 +00:00
|
|
|
##
|
2023-12-19 12:39:23 +00:00
|
|
|
db.stack.mapIt(it.delta.sTab.len).foldl(a + b, db.top.delta.sTab.len)
|
|
|
|
|
2024-02-14 19:11:59 +00:00
|
|
|
func nLayersKey*(db: AristoDbRef): int =
|
2024-02-22 08:24:58 +00:00
|
|
|
## Number of vertex ID/key entries on the cache layers. This is an upper
|
|
|
|
## bound for the number of effective vertex ID mappingss held on the cache
|
|
|
|
## layers as there might be duplicate entries for the same vertex ID on
|
2024-02-14 19:11:59 +00:00
|
|
|
## different layers.
|
|
|
|
##
|
2024-02-22 08:24:58 +00:00
|
|
|
db.stack.mapIt(it.delta.kMap.len).foldl(a + b, db.top.delta.kMap.len)
|
2023-12-19 12:39:23 +00:00
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
2024-02-22 08:24:58 +00:00
|
|
|
# Public functions: getter variants
|
2023-12-19 12:39:23 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
2024-07-18 07:13:56 +00:00
|
|
|
func layersGetVtx*(db: AristoDbRef; rvid: RootedVertexID): Opt[(VertexRef, int)] =
|
2023-12-19 12:39:23 +00:00
|
|
|
## Find a vertex on the cache layers. An `ok()` result might contain a
|
|
|
|
## `nil` vertex if it is stored on the cache that way.
|
|
|
|
##
|
2024-07-04 13:46:52 +00:00
|
|
|
db.top.delta.sTab.withValue(rvid, item):
|
2024-07-18 07:13:56 +00:00
|
|
|
return Opt.some((item[], 0))
|
2023-12-19 12:39:23 +00:00
|
|
|
|
2024-07-18 07:13:56 +00:00
|
|
|
for i, w in enumerate(db.rstack):
|
2024-07-04 13:46:52 +00:00
|
|
|
w.delta.sTab.withValue(rvid, item):
|
2024-07-18 07:13:56 +00:00
|
|
|
return Opt.some((item[], i + 1))
|
2023-12-19 12:39:23 +00:00
|
|
|
|
2024-07-18 07:13:56 +00:00
|
|
|
Opt.none((VertexRef, int))
|
2023-12-19 12:39:23 +00:00
|
|
|
|
2024-07-04 13:46:52 +00:00
|
|
|
func layersGetVtxOrVoid*(db: AristoDbRef; rvid: RootedVertexID): VertexRef =
|
2023-12-19 12:39:23 +00:00
|
|
|
## Simplified version of `layersGetVtx()`
|
2024-07-18 07:13:56 +00:00
|
|
|
db.layersGetVtx(rvid).valueOr((VertexRef(nil), 0))[0]
|
2023-12-19 12:39:23 +00:00
|
|
|
|
|
|
|
|
2024-07-18 07:13:56 +00:00
|
|
|
func layersGetKey*(db: AristoDbRef; rvid: RootedVertexID): Opt[(HashKey, int)] =
|
2024-02-14 19:11:59 +00:00
|
|
|
## Find a hash key on the cache layers. An `ok()` result might contain a void
|
|
|
|
## hash key if it is stored on the cache that way.
|
2023-12-19 12:39:23 +00:00
|
|
|
##
|
2024-07-04 13:46:52 +00:00
|
|
|
db.top.delta.kMap.withValue(rvid, item):
|
2024-07-18 07:13:56 +00:00
|
|
|
return Opt.some((item[], 0))
|
2023-12-19 12:39:23 +00:00
|
|
|
|
2024-07-18 07:13:56 +00:00
|
|
|
for i, w in enumerate(db.rstack):
|
2024-07-04 13:46:52 +00:00
|
|
|
w.delta.kMap.withValue(rvid, item):
|
2024-07-18 07:13:56 +00:00
|
|
|
return ok((item[], i + 1))
|
2023-12-19 12:39:23 +00:00
|
|
|
|
2024-07-18 07:13:56 +00:00
|
|
|
Opt.none((HashKey, int))
|
2023-12-19 12:39:23 +00:00
|
|
|
|
2024-07-04 13:46:52 +00:00
|
|
|
func layersGetKeyOrVoid*(db: AristoDbRef; rvid: RootedVertexID): HashKey =
|
2024-06-19 12:40:00 +00:00
|
|
|
## Simplified version of `layersGetKey()`
|
2024-07-18 07:13:56 +00:00
|
|
|
(db.layersGetKey(rvid).valueOr (VOID_HASH_KEY, 0))[0]
|
2023-12-19 12:39:23 +00:00
|
|
|
|
2024-07-14 10:02:05 +00:00
|
|
|
func layersGetAccLeaf*(db: AristoDbRef; accPath: Hash256): Opt[VertexRef] =
|
|
|
|
db.top.delta.accLeaves.withValue(accPath, item):
|
2024-07-03 15:58:25 +00:00
|
|
|
return Opt.some(item[])
|
|
|
|
|
|
|
|
for w in db.rstack:
|
2024-07-14 10:02:05 +00:00
|
|
|
w.delta.accLeaves.withValue(accPath, item):
|
2024-07-03 15:58:25 +00:00
|
|
|
return Opt.some(item[])
|
|
|
|
|
2024-07-14 10:02:05 +00:00
|
|
|
Opt.none(VertexRef)
|
2024-07-12 13:08:26 +00:00
|
|
|
|
2024-07-14 17:12:10 +00:00
|
|
|
func layersGetStoLeaf*(db: AristoDbRef; mixPath: Hash256): Opt[VertexRef] =
|
|
|
|
db.top.delta.stoLeaves.withValue(mixPath, item):
|
|
|
|
return Opt.some(item[])
|
|
|
|
|
|
|
|
for w in db.rstack:
|
|
|
|
w.delta.stoLeaves.withValue(mixPath, item):
|
|
|
|
return Opt.some(item[])
|
|
|
|
|
|
|
|
Opt.none(VertexRef)
|
2024-07-03 15:58:25 +00:00
|
|
|
|
2023-12-19 12:39:23 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
2024-02-22 08:24:58 +00:00
|
|
|
# Public functions: setter variants
|
2023-12-19 12:39:23 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
2024-05-25 19:01:28 +00:00
|
|
|
func layersPutVtx*(
|
2024-02-22 08:24:58 +00:00
|
|
|
db: AristoDbRef;
|
2024-07-04 13:46:52 +00:00
|
|
|
rvid: RootedVertexID;
|
2024-02-22 08:24:58 +00:00
|
|
|
vtx: VertexRef;
|
|
|
|
) =
|
2023-12-19 12:39:23 +00:00
|
|
|
## Store a (potentally empty) vertex on the top layer
|
2024-07-04 13:46:52 +00:00
|
|
|
db.top.delta.sTab[rvid] = vtx
|
2023-12-19 12:39:23 +00:00
|
|
|
|
2024-05-25 19:01:28 +00:00
|
|
|
func layersResVtx*(
|
2024-02-22 08:24:58 +00:00
|
|
|
db: AristoDbRef;
|
2024-07-04 13:46:52 +00:00
|
|
|
rvid: RootedVertexID;
|
2024-02-22 08:24:58 +00:00
|
|
|
) =
|
2023-12-19 12:39:23 +00:00
|
|
|
## Shortcut for `db.layersPutVtx(vid, VertexRef(nil))`. It is sort of the
|
|
|
|
## equivalent of a delete function.
|
2024-07-04 13:46:52 +00:00
|
|
|
db.layersPutVtx(rvid, VertexRef(nil))
|
2023-12-19 12:39:23 +00:00
|
|
|
|
|
|
|
|
2024-05-25 19:01:28 +00:00
|
|
|
func layersPutKey*(
|
2024-02-22 08:24:58 +00:00
|
|
|
db: AristoDbRef;
|
2024-07-04 13:46:52 +00:00
|
|
|
rvid: RootedVertexID;
|
2024-02-22 08:24:58 +00:00
|
|
|
key: HashKey;
|
|
|
|
) =
|
2024-02-14 19:11:59 +00:00
|
|
|
## Store a (potentally void) hash key on the top layer
|
2024-07-04 13:46:52 +00:00
|
|
|
db.top.delta.kMap[rvid] = key
|
2024-02-22 08:24:58 +00:00
|
|
|
|
|
|
|
|
2024-07-04 13:46:52 +00:00
|
|
|
func layersResKey*(db: AristoDbRef; rvid: RootedVertexID) =
|
2024-02-14 19:11:59 +00:00
|
|
|
## Shortcut for `db.layersPutKey(vid, VOID_HASH_KEY)`. It is sort of the
|
2023-12-19 12:39:23 +00:00
|
|
|
## equivalent of a delete function.
|
2024-07-04 13:46:52 +00:00
|
|
|
db.layersPutKey(rvid, VOID_HASH_KEY)
|
|
|
|
|
|
|
|
proc layersUpdateVtx*(
|
|
|
|
db: AristoDbRef; # Database, top layer
|
|
|
|
rvid: RootedVertexID;
|
|
|
|
vtx: VertexRef; # Vertex to add
|
|
|
|
) =
|
|
|
|
## Update a vertex at `rvid` and reset its associated key entry
|
|
|
|
db.layersPutVtx(rvid, vtx)
|
|
|
|
db.layersResKey(rvid)
|
|
|
|
|
2024-02-22 08:24:58 +00:00
|
|
|
|
2024-07-14 17:12:10 +00:00
|
|
|
func layersPutAccLeaf*(db: AristoDbRef; accPath: Hash256; leafVtx: VertexRef) =
|
|
|
|
db.top.delta.accLeaves[accPath] = leafVtx
|
|
|
|
|
|
|
|
func layersPutStoLeaf*(db: AristoDbRef; mixPath: Hash256; leafVtx: VertexRef) =
|
|
|
|
db.top.delta.stoLeaves[mixPath] = leafVtx
|
2024-07-03 15:58:25 +00:00
|
|
|
|
2023-12-19 12:39:23 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Public functions
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
2024-05-25 19:01:28 +00:00
|
|
|
func layersMergeOnto*(src: LayerRef; trg: var LayerObj) =
|
2023-12-19 12:39:23 +00:00
|
|
|
## Merges the argument `src` into the argument `trg` and returns `trg`. For
|
|
|
|
## the result layer, the `txUid` value set to `0`.
|
2023-12-20 16:19:00 +00:00
|
|
|
##
|
2023-12-19 12:39:23 +00:00
|
|
|
trg.txUid = 0
|
|
|
|
|
|
|
|
for (vid,vtx) in src.delta.sTab.pairs:
|
|
|
|
trg.delta.sTab[vid] = vtx
|
2024-02-14 19:11:59 +00:00
|
|
|
for (vid,key) in src.delta.kMap.pairs:
|
|
|
|
trg.delta.kMap[vid] = key
|
2024-06-04 15:05:13 +00:00
|
|
|
trg.delta.vTop = src.delta.vTop
|
2024-07-14 17:12:10 +00:00
|
|
|
for (accPath,leafVtx) in src.delta.accLeaves.pairs:
|
|
|
|
trg.delta.accLeaves[accPath] = leafVtx
|
|
|
|
for (mixPath,leafVtx) in src.delta.stoLeaves.pairs:
|
|
|
|
trg.delta.stoLeaves[mixPath] = leafVtx
|
2023-12-19 12:39:23 +00:00
|
|
|
|
2023-12-20 16:19:00 +00:00
|
|
|
func layersCc*(db: AristoDbRef; level = high(int)): LayerRef =
|
2023-12-19 12:39:23 +00:00
|
|
|
## Provide a collapsed copy of layers up to a particular transaction level.
|
|
|
|
## If the `level` argument is too large, the maximum transaction level is
|
|
|
|
## returned. For the result layer, the `txUid` value set to `0`.
|
2023-12-20 16:19:00 +00:00
|
|
|
##
|
|
|
|
let layers = if db.stack.len <= level: db.stack & @[db.top]
|
|
|
|
else: db.stack[0 .. level]
|
|
|
|
|
|
|
|
# Set up initial layer (bottom layer)
|
|
|
|
result = LayerRef(
|
Core db update storage root management for sub tries (#1964)
* Aristo: Re-phrase `LayerDelta` and `LayerFinal` as object references
why:
Avoids copying in some cases
* Fix copyright header
* Aristo: Verify `leafTie.root` function argument for `merge()` proc
why:
Zero root will lead to inconsistent DB entry
* Aristo: Update failure condition for hash labels compiler `hashify()`
why:
Node need not be rejected as long as links are on the schedule. In
that case, `redo[]` is to become `wff.base[]` at a later stage.
This amends an earlier fix, part of #1952 by also testing against
the target nodes of the `wff.base[]` sets.
* Aristo: Add storage root glue record to `hashify()` schedule
why:
An account leaf node might refer to a non-resolvable storage root ID.
Storage root node chains will end up at the storage root. So the link
`storage-root->account-leaf` needs an extra item in the schedule.
* Aristo: fix error code returned by `fetchPayload()`
details:
Final error code is implied by the error code form the `hikeUp()`
function.
* CoreDb: Discard `createOk` argument in API `getRoot()` function
why:
Not needed for the legacy DB. For the `Arsto` DB, a lazy approach is
implemented where a stprage root node is created on-the-fly.
* CoreDb: Prevent `$$` logging in some cases
why:
Logging the function `$$` is not useful when it is used for internal
use, i.e. retrieving an an error text for logging.
* CoreDb: Add `tryHashFn()` to API for pretty printing
why:
Pretty printing must not change the hashification status for the
`Aristo` DB. So there is an independent API wrapper for getting the
node hash which never updated the hashes.
* CoreDb: Discard `update` argument in API `hash()` function
why:
When calling the API function `hash()`, the latest state is always
wanted. For a version that uses the current state as-is without checking,
the function `tryHash()` was added to the backend.
* CoreDb: Update opaque vertex ID objects for the `Aristo` backend
why:
For `Aristo`, vID objects encapsulate a numeric `VertexID`
referencing a vertex (rather than a node hash as used on the
legacy backend.) For storage sub-tries, there might be no initial
vertex known when the descriptor is created. So opaque vertex ID
objects are supported without a valid `VertexID` which will be
initalised on-the-fly when the first item is merged.
* CoreDb: Add pretty printer for opaque vertex ID objects
* Cosmetics, printing profiling data
* CoreDb: Fix segfault in `Aristo` backend when creating MPT descriptor
why:
Missing initialisation error
* CoreDb: Allow MPT to inherit shared context on `Aristo` backend
why:
Creates descriptors with different storage roots for the same
shared `Aristo` DB descriptor.
* Cosmetics, update diagnostic message items for `Aristo` backend
* Fix Copyright year
2024-01-11 19:11:38 +00:00
|
|
|
delta: LayerDeltaRef(
|
2023-12-20 16:19:00 +00:00
|
|
|
sTab: layers[0].delta.sTab.dup, # explicit dup for ref values
|
2024-06-03 20:10:35 +00:00
|
|
|
kMap: layers[0].delta.kMap,
|
2024-07-03 15:58:25 +00:00
|
|
|
vTop: layers[^1].delta.vTop,
|
2024-07-14 10:02:05 +00:00
|
|
|
accLeaves: layers[0].delta.accLeaves,
|
2024-07-14 17:12:10 +00:00
|
|
|
stoLeaves: layers[0].delta.stoLeaves,
|
2024-07-03 15:58:25 +00:00
|
|
|
))
|
2023-12-20 16:19:00 +00:00
|
|
|
|
|
|
|
# Consecutively merge other layers on top
|
|
|
|
for n in 1 ..< layers.len:
|
|
|
|
for (vid,vtx) in layers[n].delta.sTab.pairs:
|
|
|
|
result.delta.sTab[vid] = vtx
|
2024-02-14 19:11:59 +00:00
|
|
|
for (vid,key) in layers[n].delta.kMap.pairs:
|
|
|
|
result.delta.kMap[vid] = key
|
2024-07-14 17:12:10 +00:00
|
|
|
for (accPath,vtx) in layers[n].delta.accLeaves.pairs:
|
|
|
|
result.delta.accLeaves[accPath] = vtx
|
|
|
|
for (mixPath,vtx) in layers[n].delta.stoLeaves.pairs:
|
|
|
|
result.delta.stoLeaves[mixPath] = vtx
|
2023-12-20 16:19:00 +00:00
|
|
|
|
2023-12-19 12:39:23 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Public iterators
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
iterator layersWalkVtx*(
|
|
|
|
db: AristoDbRef;
|
|
|
|
seen: var HashSet[VertexID];
|
2024-07-04 13:46:52 +00:00
|
|
|
): tuple[rvid: RootedVertexID, vtx: VertexRef] =
|
2023-12-19 12:39:23 +00:00
|
|
|
## Walk over all `(VertexID,VertexRef)` pairs on the cache layers. Note that
|
|
|
|
## entries are unsorted.
|
|
|
|
##
|
|
|
|
## The argument `seen` collects a set of all visited vertex IDs including
|
|
|
|
## the one with a zero vertex which are othewise skipped by the iterator.
|
|
|
|
## The `seen` argument must not be modified while the iterator is active.
|
|
|
|
##
|
2024-07-04 13:46:52 +00:00
|
|
|
for (rvid,vtx) in db.top.delta.sTab.pairs:
|
|
|
|
yield (rvid,vtx)
|
|
|
|
seen.incl rvid.vid
|
2023-12-19 12:39:23 +00:00
|
|
|
|
2024-05-23 15:37:51 +00:00
|
|
|
for w in db.rstack:
|
2024-07-04 13:46:52 +00:00
|
|
|
for (rvid,vtx) in w.delta.sTab.pairs:
|
|
|
|
if rvid.vid notin seen:
|
|
|
|
yield (rvid,vtx)
|
|
|
|
seen.incl rvid.vid
|
2023-12-19 12:39:23 +00:00
|
|
|
|
|
|
|
iterator layersWalkVtx*(
|
|
|
|
db: AristoDbRef;
|
2024-07-04 13:46:52 +00:00
|
|
|
): tuple[rvid: RootedVertexID, vtx: VertexRef] =
|
2023-12-19 12:39:23 +00:00
|
|
|
## Variant of `layersWalkVtx()`.
|
|
|
|
var seen: HashSet[VertexID]
|
2024-07-04 13:46:52 +00:00
|
|
|
for (rvid,vtx) in db.layersWalkVtx seen:
|
|
|
|
yield (rvid,vtx)
|
2023-12-19 12:39:23 +00:00
|
|
|
|
|
|
|
|
2024-02-14 19:11:59 +00:00
|
|
|
iterator layersWalkKey*(
|
2023-12-19 12:39:23 +00:00
|
|
|
db: AristoDbRef;
|
2024-07-04 13:46:52 +00:00
|
|
|
): tuple[rvid: RootedVertexID, key: HashKey] =
|
2024-02-14 19:11:59 +00:00
|
|
|
## Walk over all `(VertexID,HashKey)` pairs on the cache layers. Note that
|
2023-12-19 12:39:23 +00:00
|
|
|
## entries are unsorted.
|
|
|
|
var seen: HashSet[VertexID]
|
2024-07-04 13:46:52 +00:00
|
|
|
for (rvid,key) in db.top.delta.kMap.pairs:
|
|
|
|
yield (rvid,key)
|
|
|
|
seen.incl rvid.vid
|
2023-12-19 12:39:23 +00:00
|
|
|
|
2024-05-23 15:37:51 +00:00
|
|
|
for w in db.rstack:
|
2024-07-04 13:46:52 +00:00
|
|
|
for (rvid,key) in w.delta.kMap.pairs:
|
|
|
|
if rvid.vid notin seen:
|
|
|
|
yield (rvid,key)
|
|
|
|
seen.incl rvid.vid
|
2023-12-19 12:39:23 +00:00
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# End
|
|
|
|
# ------------------------------------------------------------------------------
|