267 lines
6.9 KiB
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
|
|
# ------------------------------------------------------------------------------
|