nimbus-eth1/nimbus/db/core_db/backend/aristo_db/handlers_kvt.nim

267 lines
6.9 KiB
Nim

# Nimbus
# Copyright (c) 2023-2024 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.
{.push raises: [].}
import
chronicles,
eth/common,
results,
../../../kvt as use_kvt,
../../base,
../../base/base_desc,
./common_desc
type
KvtBaseRef* = ref object
parent: CoreDbRef ## Opaque top level descriptor
kdb: KvtDbRef ## Shared key-value table
api*: KvtApiRef ## Api functions can be re-directed
cache: KvtCoreDbKvtRef ## Shared transaction table wrapper
KvtCoreDbKvtRef = ref object of CoreDbKvtRef
base: KvtBaseRef ## Local base descriptor
kvt: KvtDbRef ## In most cases different from `base.kdb`
AristoCoreDbKvtBE* = ref object of CoreDbKvtBackendRef
kdb*: KvtDbRef
logScope:
topics = "kvt-hdl"
# ------------------------------------------------------------------------------
# Private helpers
# ------------------------------------------------------------------------------
func toError(
e: KvtError;
base: KvtBaseRef;
info: string;
error = Unspecified;
): CoreDbErrorRef =
base.parent.bless(error, AristoCoreDbError(
ctx: info,
isAristo: false,
kErr: e))
func toRc[T](
rc: Result[T,KvtError];
base: KvtBaseRef;
info: string;
error = Unspecified;
): CoreDbRc[T] =
if rc.isOk:
when T is void:
return ok()
else:
return ok(rc.value)
err rc.error.toError(base, info, error)
# ------------------------------------------------------------------------------
# Private `kvt` call back functions
# ------------------------------------------------------------------------------
proc kvtMethods(cKvt: KvtCoreDbKvtRef): CoreDbKvtFns =
## Key-value database table handlers
proc kvtBackend(
cKvt:KvtCoreDbKvtRef;
): CoreDbKvtBackendRef =
cKvt.base.parent.bless AristoCoreDbKvtBE(kdb: cKvt.kvt)
proc kvtForget(
cKvt: KvtCoreDbKvtRef;
info: static[string];
): CoreDbRc[void] =
let
base = cKvt.base
kvt = cKvt.kvt
if kvt != base.kdb:
let rc = base.api.forget(kvt)
# There is not much that can be done in case of a `forget()` error.
# So unmark it anyway.
cKvt.kvt = KvtDbRef(nil)
if rc.isErr:
return err(rc.error.toError(base, info))
ok()
proc kvtGet(
cKvt: KvtCoreDbKvtRef;
k: openArray[byte];
info: static[string];
): CoreDbRc[Blob] =
let rc = cKvt.base.api.get(cKvt.kvt, k)
if rc.isOk:
ok(rc.value)
elif rc.error == GetNotFound:
err(rc.error.toError(cKvt.base, info, KvtNotFound))
else:
rc.toRc(cKvt.base, info)
proc kvtLen(
cKvt: KvtCoreDbKvtRef;
k: openArray[byte];
info: static[string];
): CoreDbRc[int] =
let rc = cKvt.base.api.len(cKvt.kvt, k)
if rc.isOk:
ok(rc.value)
elif rc.error == GetNotFound:
err(rc.error.toError(cKvt.base, info, KvtNotFound))
else:
rc.toRc(cKvt.base, info)
proc kvtPut(
cKvt: KvtCoreDbKvtRef;
k: openArray[byte];
v: openArray[byte];
info: static[string];
): CoreDbRc[void] =
let rc = cKvt.base.api.put(cKvt.kvt, k, v)
if rc.isOk:
ok()
else:
err(rc.error.toError(cKvt.base, info))
proc kvtDel(
cKvt: KvtCoreDbKvtRef;
k: openArray[byte];
info: static[string];
): CoreDbRc[void] =
let rc = cKvt.base.api.del(cKvt.kvt, k)
if rc.isOk:
ok()
else:
err(rc.error.toError(cKvt.base, info))
proc kvtHasKey(
cKvt: KvtCoreDbKvtRef;
k: openArray[byte];
info: static[string];
): CoreDbRc[bool] =
let rc = cKvt.base.api.hasKey(cKvt.kvt, k)
if rc.isOk:
ok(rc.value)
else:
err(rc.error.toError(cKvt.base, info))
CoreDbKvtFns(
backendFn: proc(): CoreDbKvtBackendRef =
cKvt.kvtBackend(),
getFn: proc(k: openArray[byte]): CoreDbRc[Blob] =
cKvt.kvtGet(k, "getFn()"),
lenFn: proc(k: openArray[byte]): CoreDbRc[int] =
cKvt.kvtLen(k, "lenFn()"),
delFn: proc(k: openArray[byte]): CoreDbRc[void] =
cKvt.kvtDel(k, "delFn()"),
putFn: proc(k: openArray[byte]; v: openArray[byte]): CoreDbRc[void] =
cKvt.kvtPut(k, v, "putFn()"),
hasKeyFn: proc(k: openArray[byte]): CoreDbRc[bool] =
cKvt.kvtHasKey(k, "hasKeyFn()"),
forgetFn: proc(): CoreDbRc[void] =
cKvt.kvtForget("forgetFn()"))
# ------------------------------------------------------------------------------
# Public handlers and helpers
# ------------------------------------------------------------------------------
func toVoidRc*[T](
rc: Result[T,KvtError];
base: KvtBaseRef;
info: string;
error = Unspecified;
): CoreDbRc[void] =
if rc.isErr:
return err(rc.error.toError(base, info, error))
ok()
# ---------------------
func to*(dsc: CoreDbKvtRef; T: type KvtDbRef): T =
KvtCoreDbKvtRef(dsc).kvt
func txTop*(
base: KvtBaseRef;
info: static[string];
): CoreDbRc[KvtTxRef] =
base.api.txTop(base.kdb).toRc(base, info)
proc txBegin*(
base: KvtBaseRef;
info: static[string];
): KvtTxRef =
let rc = base.api.txBegin(base.kdb)
if rc.isErr:
raiseAssert info & ": " & $rc.error
rc.value
proc persistent*(
base: KvtBaseRef;
info: static[string];
): CoreDbRc[void] =
let
api = base.api
kvt = base.kdb
rc = api.persist(kvt)
if rc.isOk:
ok()
elif api.level(kvt) != 0:
err(rc.error.toError(base, info, TxPending))
elif rc.error == TxPersistDelayed:
# This is OK: Piggybacking on `Aristo` backend
ok()
else:
err(rc.error.toError(base, info))
# ------------------------------------------------------------------------------
# Public constructors and related
# ------------------------------------------------------------------------------
proc newKvtHandler*(
base: KvtBaseRef;
info: static[string];
): CoreDbRc[CoreDbKvtRef] =
ok(base.cache)
proc destroy*(base: KvtBaseRef; eradicate: bool) =
base.api.finish(base.kdb, eradicate) # Close descriptor
func init*(T: type KvtBaseRef; db: CoreDbRef; kdb: KvtDbRef): T =
result = T(
parent: db,
api: KvtApiRef.init(),
kdb: kdb)
# Preallocated shared descriptor
let dsc = KvtCoreDbKvtRef(
base: result,
kvt: kdb)
dsc.methods = dsc.kvtMethods()
result.cache = db.bless dsc
when CoreDbEnableApiProfiling:
let profApi = KvtApiProfRef.init(result.api, kdb.backend)
result.api = profApi
result.kdb.backend = profApi.be
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------