162 lines
5.0 KiB
Nim
162 lines
5.0 KiB
Nim
# nimbus-eth1
|
|
# Copyright (c) 2021 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.
|
|
|
|
## Rocks DB store data iterator
|
|
## ============================
|
|
##
|
|
{.push raises: [].}
|
|
|
|
import
|
|
std/sequtils,
|
|
eth/common,
|
|
rocksdb,
|
|
../init_common,
|
|
./rdb_desc
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Private helpers
|
|
# ------------------------------------------------------------------------------
|
|
|
|
func keyPfx(kData: cstring, kLen: csize_t): int =
|
|
if not kData.isNil and kLen == 1 + sizeof(uint64):
|
|
kData.toOpenArrayByte(0,0)[0].int
|
|
else:
|
|
-1
|
|
|
|
func keyXid(kData: cstring, kLen: csize_t): uint64 =
|
|
if not kData.isNil and kLen == 1 + sizeof(uint64):
|
|
return uint64.fromBytesBE kData.toOpenArrayByte(1,int(kLen)-1).toSeq
|
|
|
|
func valBlob(vData: cstring, vLen: csize_t): Blob =
|
|
if not vData.isNil and 0 < vLen:
|
|
return vData.toOpenArrayByte(0,int(vLen)-1).toSeq
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Private debugging helpers
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc pp(kd: cstring, kl: csize_t): string =
|
|
if kd.isNil: "n/a" else: $kd.keyXid(kl)
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Public iterators
|
|
# ------------------------------------------------------------------------------
|
|
|
|
iterator walk*(
|
|
rdb: RdbInst;
|
|
): tuple[n: int, pfx: StorageType, xid: uint64, data: Blob] =
|
|
## Walk over all key-value pairs of the database.
|
|
##
|
|
## Non-decodable entries are stepped over while the counter `n` of the
|
|
## yield record is still incremented.
|
|
let rit = rdb.store.db.rocksdb_create_iterator(rdb.store.readOptions)
|
|
defer: rit.rocksdb_iter_destroy()
|
|
|
|
rit.rocksdb_iter_seek_to_first()
|
|
var count = 0
|
|
|
|
while rit.rocksdb_iter_valid() != 0:
|
|
var kLen: csize_t
|
|
let kData = rit.rocksdb_iter_key(addr kLen)
|
|
|
|
let pfx = kData.keyPfx(kLen)
|
|
if 0 <= pfx:
|
|
if high(StorageType).ord < pfx:
|
|
break
|
|
|
|
let xid = kData.keyXid(kLen)
|
|
if 0 < xid:
|
|
var vLen: csize_t
|
|
let vData = rit.rocksdb_iter_value(addr vLen)
|
|
|
|
let val = vData.valBlob(vLen)
|
|
if 0 < val.len:
|
|
yield (count, pfx.StorageType, xid, val)
|
|
|
|
# Update Iterator (might overwrite kData/vdata)
|
|
rit.rocksdb_iter_next()
|
|
count.inc
|
|
# End while
|
|
|
|
|
|
iterator walk*(
|
|
rdb: RdbInst;
|
|
pfx: StorageType;
|
|
): tuple[n: int, xid: uint64, data: Blob] =
|
|
## Walk over key-value pairs of the table referted to by the argument `pfx`
|
|
## whic must be different from `Oops` and `AdmPfx`.
|
|
##
|
|
## Non-decodable entries are stepped over while the counter `n` of the
|
|
## yield record is still incremented.
|
|
##
|
|
block walkBody:
|
|
if pfx in {Oops, AdmPfx}:
|
|
# Unsupported
|
|
break walkBody
|
|
|
|
let rit = rdb.store.db.rocksdb_create_iterator(rdb.store.readOptions)
|
|
defer: rit.rocksdb_iter_destroy()
|
|
|
|
var
|
|
count = 0
|
|
kLen: csize_t
|
|
kData: cstring
|
|
|
|
# Seek for `VertexID(1)` and subsequent entries if that fails. There should
|
|
# always be a `VertexID(1)` entry unless the sub-table is empty. There is
|
|
# no such control for the filter table in which case there is a blind guess
|
|
# (in case `rocksdb_iter_seek()` does not search `ge` for some reason.)
|
|
let keyOne = 1u64.toRdbKey pfx
|
|
|
|
# It is not clear what happens when the `key` does not exist. The guess
|
|
# is that the interation will proceed at the next key position.
|
|
#
|
|
# Comment from GO port at
|
|
# //github.com/DanielMorsing/rocksdb/blob/master/iterator.go:
|
|
#
|
|
# Seek moves the iterator the position of the key given or, if the key
|
|
# doesn't exist, the next key that does exist in the database. If the key
|
|
# doesn't exist, and there is no next key, the Iterator becomes invalid.
|
|
#
|
|
kData = cast[cstring](unsafeAddr keyOne[0])
|
|
kLen = sizeof(keyOne).csize_t
|
|
rit.rocksdb_iter_seek(kData, kLen)
|
|
if rit.rocksdb_iter_valid() == 0:
|
|
break walkBody
|
|
|
|
# Fetch sub-table data
|
|
while true:
|
|
kData = rit.rocksdb_iter_key(addr kLen)
|
|
if pfx.ord != kData.keyPfx kLen:
|
|
break walkBody # done
|
|
|
|
let xid = kData.keyXid(kLen)
|
|
if 0 < xid:
|
|
# Fetch value data
|
|
var vLen: csize_t
|
|
let vData = rit.rocksdb_iter_value(addr vLen)
|
|
|
|
let val = vData.valBlob(vLen)
|
|
if 0 < val.len:
|
|
yield (count, xid, val)
|
|
|
|
# Update Iterator
|
|
rit.rocksdb_iter_next()
|
|
if rit.rocksdb_iter_valid() == 0:
|
|
break walkBody
|
|
|
|
count.inc
|
|
# End while
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|