Aristo use rocksdb cf instead of key pfx (#2332)

* Use RocksDb column families instead of a prefixed single column

why:
  Better performance

* Use structural objects `VertexRef` and `HashKey` in LRU cache for RocksDb

why:
  Avoids repeated de/serialisation
This commit is contained in:
Jordan Hrycaj 2024-06-10 12:04:22 +00:00 committed by GitHub
parent c72d6aa5d6
commit a347291413
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 251 additions and 245 deletions

View File

@ -318,8 +318,8 @@ data, for RLP encoded or for unstructured data as defined below.
where each bitmask(2)-word array entry defines the length of where each bitmask(2)-word array entry defines the length of
the preceeding data fields: the preceeding data fields:
00 -- field is missing 00 -- field is missing
01 -- field lengthh is 8 bytes 01 -- field length is 8 bytes
10 -- field lengthh is 32 bytes 10 -- field length is 32 bytes
Apparently, entries 0 and and 2 of the *4 x bitmask(2)* word array cannot have Apparently, entries 0 and and 2 of the *4 x bitmask(2)* word array cannot have
the two bit value *10* as they refer to the nonce and the storage ID data the two bit value *10* as they refer to the nonce and the storage ID data

View File

@ -130,10 +130,6 @@ proc checkBE*[T: RdbBackendRef|MemBackendRef|VoidBackendRef](
# been deleted. # been deleted.
for vid in max(topVidBe + 1, VertexID(LEAST_FREE_VID)) .. vidTuvBe: for vid in max(topVidBe + 1, VertexID(LEAST_FREE_VID)) .. vidTuvBe:
if db.getVtxBE(vid).isOk or db.getKeyBE(vid).isOk: if db.getVtxBE(vid).isOk or db.getKeyBE(vid).isOk:
echo ">>>",
" topVidBe=", topVidBe,
" vidTuvBe=", vidTuvBe,
" vid=", vid
return err((vid,CheckBeGarbledVTop)) return err((vid,CheckBeGarbledVTop))
# Check layer cache against backend # Check layer cache against backend
@ -195,10 +191,6 @@ proc checkBE*[T: RdbBackendRef|MemBackendRef|VoidBackendRef](
for vid in max(db.vTop + 1, VertexID(LEAST_FREE_VID)) .. topVidCache: for vid in max(db.vTop + 1, VertexID(LEAST_FREE_VID)) .. topVidCache:
if db.layersGetVtxOrVoid(vid).isValid or if db.layersGetVtxOrVoid(vid).isValid or
db.layersGetKeyOrVoid(vid).isValid: db.layersGetKeyOrVoid(vid).isValid:
echo ">>>",
" topVidCache=", topVidCache,
" vTop=", db.vTop,
" vid=", vid
return err((db.vTop,CheckBeCacheGarbledVTop)) return err((db.vTop,CheckBeCacheGarbledVTop))
ok() ok()

View File

@ -241,11 +241,16 @@ type
# RocksDB backend # RocksDB backend
RdbBeCantCreateDataDir RdbBeCantCreateDataDir
RdbBeCantCreateTmpDir RdbBeCantCreateTmpDir
RdbBeDriverDelError RdbBeDriverDelAdmError
RdbBeDriverGetError RdbBeDriverDelKeyError
RdbBeDriverDelVtxError
RdbBeDriverGetAdmError
RdbBeDriverGetKeyError
RdbBeDriverGetVtxError
RdbBeDriverGuestError RdbBeDriverGuestError
RdbBeDriverInitError RdbBeDriverPutAdmError
RdbBeDriverPutError RdbBeDriverPutVtxError
RdbBeDriverPutKeyError
RdbBeDriverWriteError RdbBeDriverWriteError
RdbGuestInstanceUnsupported RdbGuestInstanceUnsupported
RdbHashKeyExpected RdbHashKeyExpected

View File

@ -79,14 +79,13 @@ proc getVtxFn(db: RdbBackendRef): GetVtxFn =
proc(vid: VertexID): Result[VertexRef,AristoError] = proc(vid: VertexID): Result[VertexRef,AristoError] =
# Fetch serialised data record # Fetch serialised data record
let data = db.rdb.getVtx(vid.uint64).valueOr: let vtx = db.rdb.getVtx(vid).valueOr:
when extraTraceMessages: when extraTraceMessages:
trace logTxt "getVtxFn() failed", vid, error=error[0], info=error[1] trace logTxt "getVtxFn() failed", vid, error=error[0], info=error[1]
return err(error[0]) return err(error[0])
# Decode data record if vtx.isValid:
if 0 < data.len: return ok(vtx)
return data.deblobify VertexRef
err(GetVtxNotFound) err(GetVtxNotFound)
@ -95,16 +94,13 @@ proc getKeyFn(db: RdbBackendRef): GetKeyFn =
proc(vid: VertexID): Result[HashKey,AristoError] = proc(vid: VertexID): Result[HashKey,AristoError] =
# Fetch serialised data record # Fetch serialised data record
let data = db.rdb.getKey(vid.uint64).valueOr: let key = db.rdb.getKey(vid).valueOr:
when extraTraceMessages: when extraTraceMessages:
trace logTxt "getKeyFn: failed", vid, error=error[0], info=error[1] trace logTxt "getKeyFn: failed", vid, error=error[0], info=error[1]
return err(error[0]) return err(error[0])
# Decode data record if key.isValid:
if 0 < data.len: return ok(key)
let lid = HashKey.fromBytes(data).valueOr:
return err(RdbHashKeyExpected)
return ok lid
err(GetKeyNotFound) err(GetKeyNotFound)
@ -113,7 +109,7 @@ proc getTuvFn(db: RdbBackendRef): GetTuvFn =
proc(): Result[VertexID,AristoError]= proc(): Result[VertexID,AristoError]=
# Fetch serialised data record. # Fetch serialised data record.
let data = db.rdb.getByPfx(AdmPfx, AdmTabIdTuv.uint64).valueOr: let data = db.rdb.getAdm(AdmTabIdTuv).valueOr:
when extraTraceMessages: when extraTraceMessages:
trace logTxt "getTuvFn: failed", error=error[0], info=error[1] trace logTxt "getTuvFn: failed", error=error[0], info=error[1]
return err(error[0]) return err(error[0])
@ -123,14 +119,14 @@ proc getTuvFn(db: RdbBackendRef): GetTuvFn =
return ok VertexID(0) return ok VertexID(0)
# Decode data record # Decode data record
data.deblobify VertexID result = data.deblobify VertexID
proc getLstFn(db: RdbBackendRef): GetLstFn = proc getLstFn(db: RdbBackendRef): GetLstFn =
result = result =
proc(): Result[SavedState,AristoError]= proc(): Result[SavedState,AristoError]=
# Fetch serialised data record. # Fetch serialised data record.
let data = db.rdb.getByPfx(AdmPfx, AdmTabIdLst.uint64).valueOr: let data = db.rdb.getAdm(AdmTabIdLst).valueOr:
when extraTraceMessages: when extraTraceMessages:
trace logTxt "getLstFn: failed", error=error[0], info=error[1] trace logTxt "getLstFn: failed", error=error[0], info=error[1]
return err(error[0]) return err(error[0])
@ -151,27 +147,10 @@ proc putVtxFn(db: RdbBackendRef): PutVtxFn =
proc(hdl: PutHdlRef; vrps: openArray[(VertexID,VertexRef)]) = proc(hdl: PutHdlRef; vrps: openArray[(VertexID,VertexRef)]) =
let hdl = hdl.getSession db let hdl = hdl.getSession db
if hdl.error.isNil: if hdl.error.isNil:
db.rdb.putVtx(vrps).isOkOr:
# Collect batch session arguments
var batch: seq[(uint64,Blob)]
for (vid,vtx) in vrps:
if vtx.isValid:
let rc = vtx.blobify()
if rc.isErr:
hdl.error = TypedPutHdlErrRef( hdl.error = TypedPutHdlErrRef(
pfx: VtxPfx, pfx: VtxPfx,
vid: vid, vid: error[0],
code: rc.error)
return
batch.add (vid.uint64, rc.value)
else:
batch.add (vid.uint64, EmptyBlob)
# Stash batch session data via LRU cache
db.rdb.putVtx(batch).isOkOr:
hdl.error = TypedPutHdlErrRef(
pfx: VtxPfx,
vid: VertexID(error[0]),
code: error[1], code: error[1],
info: error[2]) info: error[2])
@ -180,20 +159,10 @@ proc putKeyFn(db: RdbBackendRef): PutKeyFn =
proc(hdl: PutHdlRef; vkps: openArray[(VertexID,HashKey)]) = proc(hdl: PutHdlRef; vkps: openArray[(VertexID,HashKey)]) =
let hdl = hdl.getSession db let hdl = hdl.getSession db
if hdl.error.isNil: if hdl.error.isNil:
db.rdb.putKey(vkps).isOkOr:
# Collect batch session arguments
var batch: seq[(uint64,Blob)]
for (vid,key) in vkps:
if key.isValid:
batch.add (vid.uint64, @(key.data))
else:
batch.add (vid.uint64, EmptyBlob)
# Stash batch session data via LRU cache
db.rdb.putKey(batch).isOkOr:
hdl.error = TypedPutHdlErrRef( hdl.error = TypedPutHdlErrRef(
pfx: KeyPfx, pfx: KeyPfx,
vid: VertexID(error[0]), vid: error[0],
code: error[1], code: error[1],
info: error[2]) info: error[2])
@ -203,12 +172,14 @@ proc putTuvFn(db: RdbBackendRef): PutTuvFn =
let hdl = hdl.getSession db let hdl = hdl.getSession db
if hdl.error.isNil: if hdl.error.isNil:
if vs.isValid: if vs.isValid:
db.rdb.putByPfx(AdmPfx, @[(AdmTabIdTuv.uint64, vs.blobify)]).isOkOr: db.rdb.putAdm(AdmTabIdTuv, vs.blobify).isOkOr:
hdl.error = TypedPutHdlErrRef( hdl.error = TypedPutHdlErrRef(
pfx: AdmPfx, pfx: AdmPfx,
aid: AdmTabIdTuv, aid: AdmTabIdTuv,
code: error[1], code: error[1],
info: error[2]) info: error[2])
return
proc putLstFn(db: RdbBackendRef): PutLstFn = proc putLstFn(db: RdbBackendRef): PutLstFn =
result = result =
@ -221,7 +192,7 @@ proc putLstFn(db: RdbBackendRef): PutLstFn =
aid: AdmTabIdLst, aid: AdmTabIdLst,
code: error) code: error)
return return
db.rdb.putByPfx(AdmPfx, @[(AdmTabIdLst.uint64, data)]).isOkOr: db.rdb.putAdm(AdmTabIdLst, data).isOkOr:
hdl.error = TypedPutHdlErrRef( hdl.error = TypedPutHdlErrRef(
pfx: AdmPfx, pfx: AdmPfx,
aid: AdmTabIdLst, aid: AdmTabIdLst,
@ -243,6 +214,7 @@ proc putEndFn(db: RdbBackendRef): PutEndFn =
pfx=AdmPfx, aid=hdl.error.aid.uint64, error=hdl.error.code pfx=AdmPfx, aid=hdl.error.aid.uint64, error=hdl.error.code
of Oops: trace logTxt "putEndFn: oops", of Oops: trace logTxt "putEndFn: oops",
error=hdl.error.code error=hdl.error.code
db.rdb.rollback()
return err(hdl.error.code) return err(hdl.error.code)
# Commit session # Commit session
@ -317,28 +289,32 @@ iterator walk*(
): tuple[pfx: StorageType, xid: uint64, data: Blob] = ): tuple[pfx: StorageType, xid: uint64, data: Blob] =
## Walk over all key-value pairs of the database. ## Walk over all key-value pairs of the database.
## ##
## Non-decodable entries are stepped over while the counter `n` of the ## Non-decodable entries are ignored
## yield record is still incremented. ##
for w in be.rdb.walk: for (xid, data) in be.rdb.walkAdm:
yield w yield (AdmPfx, xid, data)
for (vid, data) in be.rdb.walkVtx:
yield (VtxPfx, vid, data)
for (vid, data) in be.rdb.walkKey:
yield (KeyPfx, vid, data)
iterator walkVtx*( iterator walkVtx*(
be: RdbBackendRef; be: RdbBackendRef;
): tuple[vid: VertexID, vtx: VertexRef] = ): tuple[vid: VertexID, vtx: VertexRef] =
## Variant of `walk()` iteration over the vertex sub-table. ## Variant of `walk()` iteration over the vertex sub-table.
for (xid, data) in be.rdb.walk VtxPfx: for (vid, data) in be.rdb.walkVtx:
let rc = data.deblobify VertexRef let rc = data.deblobify VertexRef
if rc.isOk: if rc.isOk:
yield (VertexID(xid), rc.value) yield (VertexID(vid), rc.value)
iterator walkKey*( iterator walkKey*(
be: RdbBackendRef; be: RdbBackendRef;
): tuple[vid: VertexID, key: HashKey] = ): tuple[vid: VertexID, key: HashKey] =
## Variant of `walk()` iteration over the Markle hash sub-table. ## Variant of `walk()` iteration over the Markle hash sub-table.
for (xid, data) in be.rdb.walk KeyPfx: for (vid, data) in be.rdb.walkKey:
let lid = HashKey.fromBytes(data).valueOr: let lid = HashKey.fromBytes(data).valueOr:
continue continue
yield (VertexID(xid), lid) yield (VertexID(vid), lid)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# End # End

View File

@ -23,10 +23,12 @@ import
type type
RdbInst* = object RdbInst* = object
store*: ColFamilyReadWrite ## Rocks DB database handler admCol*: ColFamilyReadWrite ## Admin column family handler
vtxCol*: ColFamilyReadWrite ## Vertex column family handler
keyCol*: ColFamilyReadWrite ## Hash key column family handler
session*: WriteBatchRef ## For batched `put()` session*: WriteBatchRef ## For batched `put()`
rdKeyLru*: KeyedQueue[RdbKey,Blob] ## Read cache rdKeyLru*: KeyedQueue[VertexID,HashKey] ## Read cache
rdVtxLru*: KeyedQueue[RdbKey,Blob] ## Read cache rdVtxLru*: KeyedQueue[VertexID,VertexRef] ## Read cache
basePath*: string ## Database directory basePath*: string ## Database directory
noFq*: bool ## No filter queues available noFq*: bool ## No filter queues available
@ -35,15 +37,21 @@ type
# Alien interface # Alien interface
RdbGuest* = enum RdbGuest* = enum
## The guest CF was worth a try, but there are better solutions and this
## item will be removed in future.
GuestFamily0 = "Guest0" ## Guest family (e.g. for Kvt) GuestFamily0 = "Guest0" ## Guest family (e.g. for Kvt)
GuestFamily1 = "Guest1" ## Ditto GuestFamily1 = "Guest1" ## Ditto
GuestFamily2 = "Guest2" ## Ditto GuestFamily2 = "Guest2" ## Ditto
RdbGuestDbRef* = ref object of GuestDbRef RdbGuestDbRef* = ref object of GuestDbRef
## The guest CF was worth a try, but there are better solutions and this
## item will be removed in future.
guestDb*: ColFamilyReadWrite ## Pigiback feature references guestDb*: ColFamilyReadWrite ## Pigiback feature references
const const
AristoFamily* = "Aristo" ## RocksDB column family AdmCF* = "AdmAri" ## Admin column family name
VtxCF* = "VtxAri" ## Vertex column family name
KeyCF* = "KeyAri" ## Hash key column family name
BaseFolder* = "nimbus" ## Same as for Legacy DB BaseFolder* = "nimbus" ## Same as for Legacy DB
DataFolder* = "aristo" ## Legacy DB has "data" DataFolder* = "aristo" ## Legacy DB has "data"
RdKeyLruMaxSize* = 4096 ## Max size of read cache for keys RdKeyLruMaxSize* = 4096 ## Max size of read cache for keys
@ -56,6 +64,9 @@ const
template logTxt*(info: static[string]): static[string] = template logTxt*(info: static[string]): static[string] =
"RocksDB/" & info "RocksDB/" & info
template baseDb*(rdb: RdbInst): RocksDbReadWriteRef =
rdb.admCol.db
func baseDir*(rdb: RdbInst): string = func baseDir*(rdb: RdbInst): string =
rdb.basePath / BaseFolder rdb.basePath / BaseFolder
@ -63,10 +74,12 @@ func baseDir*(rdb: RdbInst): string =
func dataDir*(rdb: RdbInst): string = func dataDir*(rdb: RdbInst): string =
rdb.baseDir / DataFolder rdb.baseDir / DataFolder
func toRdbKey*(id: uint64; pfx: StorageType): RdbKey =
let idKey = id.toBytesBE template toOpenArray*(xid: AdminTabID): openArray[byte] =
result[0] = pfx.ord.byte xid.uint64.toBytesBE.toOpenArray(0,7)
copyMem(addr result[1], unsafeAddr idKey, sizeof idKey)
template toOpenArray*(vid: VertexID): openArray[byte] =
vid.uint64.toBytesBE.toOpenArray(0,7)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# End # End

View File

@ -18,7 +18,7 @@ import
rocksdb, rocksdb,
results, results,
stew/keyed_queue, stew/keyed_queue,
../../aristo_desc, ../../[aristo_blobify, aristo_desc],
../init_common, ../init_common,
./rdb_desc ./rdb_desc
@ -33,15 +33,19 @@ when extraTraceMessages:
logScope: logScope:
topics = "aristo-rocksdb" topics = "aristo-rocksdb"
proc getImpl(rdb: RdbInst; key: RdbKey): Result[Blob,(AristoError,string)] = # ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
proc getAdm*(rdb: RdbInst; xid: AdminTabID): Result[Blob,(AristoError,string)] =
var res: Blob var res: Blob
let onData = proc(data: openArray[byte]) = let onData = proc(data: openArray[byte]) =
res = @data res = @data
let gotData = rdb.store.get(key, onData).valueOr: let gotData = rdb.admCol.get(xid.toOpenArray, onData).valueOr:
const errSym = RdbBeDriverGetError const errSym = RdbBeDriverGetAdmError
when extraTraceMessages: when extraTraceMessages:
trace logTxt "get", pfx=key[0], error=errSym, info=error trace logTxt "getAdm", xid, error=errSym, info=error
return err((errSym,error)) return err((errSym,error))
# Correct result if needed # Correct result if needed
@ -49,46 +53,68 @@ proc getImpl(rdb: RdbInst; key: RdbKey): Result[Blob,(AristoError,string)] =
res = EmptyBlob res = EmptyBlob
ok move(res) ok move(res)
# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
proc getByPfx*( proc getKey*(
rdb: RdbInst; rdb: var RdbInst;
pfx: StorageType; vid: VertexID;
xid: uint64, ): Result[HashKey,(AristoError,string)] =
): Result[Blob,(AristoError,string)] =
rdb.getImpl(xid.toRdbKey pfx)
proc getKey*(rdb: var RdbInst; xid: uint64): Result[Blob,(AristoError,string)] =
# Try LRU cache first # Try LRU cache first
let var rc = rdb.rdKeyLru.lruFetch(vid)
key = xid.toRdbKey KeyPfx
var
rc = rdb.rdKeyLru.lruFetch(key)
if rc.isOK: if rc.isOK:
return ok(move(rc.value)) return ok(move(rc.value))
# Otherwise fetch from backend database # Otherwise fetch from backend database
let res = ? rdb.getImpl(key) var res: Blob
let onData = proc(data: openArray[byte]) =
res = @data
let gotData = rdb.keyCol.get(vid.toOpenArray, onData).valueOr:
const errSym = RdbBeDriverGetKeyError
when extraTraceMessages:
trace logTxt "getKey", vid, error=errSym, info=error
return err((errSym,error))
# Correct result if needed
let key = block:
if gotData:
HashKey.fromBytes(res).valueOr:
return err((RdbHashKeyExpected,""))
else:
VOID_HASH_KEY
# Update cache and return # Update cache and return
ok rdb.rdKeyLru.lruAppend(key, res, RdKeyLruMaxSize) ok rdb.rdKeyLru.lruAppend(vid, key, RdKeyLruMaxSize)
proc getVtx*(rdb: var RdbInst; xid: uint64): Result[Blob,(AristoError,string)] =
proc getVtx*(
rdb: var RdbInst;
vid: VertexID;
): Result[VertexRef,(AristoError,string)] =
# Try LRU cache first # Try LRU cache first
let var rc = rdb.rdVtxLru.lruFetch(vid)
key = xid.toRdbKey VtxPfx
var
rc = rdb.rdVtxLru.lruFetch(key)
if rc.isOK: if rc.isOK:
return ok(move(rc.value)) return ok(move(rc.value))
# Otherwise fetch from backend database # Otherwise fetch from backend database
let res = ? rdb.getImpl(key) var res: Blob
let onData = proc(data: openArray[byte]) =
res = @data
let gotData = rdb.vtxCol.get(vid.toOpenArray, onData).valueOr:
const errSym = RdbBeDriverGetVtxError
when extraTraceMessages:
trace logTxt "getVtx", vid, error=errSym, info=error
return err((errSym,error))
var vtx = VertexRef(nil)
if gotData:
let rc = res.deblobify VertexRef
if rc.isErr:
return err((rc.error,""))
vtx = rc.value
# Update cache and return # Update cache and return
ok rdb.rdVtxLru.lruAppend(key, res, RdVtxLruMaxSize) ok rdb.rdVtxLru.lruAppend(vid, vtx, RdVtxLruMaxSize)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# End # End

View File

@ -21,17 +21,6 @@ import
./rdb_desc, ./rdb_desc,
../../../opts ../../../opts
const
extraTraceMessages = false
## Enable additional logging noise
when extraTraceMessages:
import
chronicles
logScope:
topics = "aristo-rocksdb"
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public constructor # Public constructor
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -43,11 +32,12 @@ proc init*(
): Result[void,(AristoError,string)] = ): Result[void,(AristoError,string)] =
## Constructor c ode inspired by `RocksStoreRef.init()` from ## Constructor c ode inspired by `RocksStoreRef.init()` from
## kvstore_rocksdb.nim ## kvstore_rocksdb.nim
const initFailed = "RocksDB/init() failed"
rdb.basePath = basePath rdb.basePath = basePath
let let
dataDir = rdb.dataDir dataDir = rdb.dataDir
try: try:
dataDir.createDir dataDir.createDir
except OSError, IOError: except OSError, IOError:
@ -60,7 +50,9 @@ proc init*(
cfOpts.setWriteBufferSize(opts.writeBufferSize) cfOpts.setWriteBufferSize(opts.writeBufferSize)
let let
cfs = @[initColFamilyDescriptor(AristoFamily, cfOpts)] & cfs = @[initColFamilyDescriptor(AdmCF, cfOpts),
initColFamilyDescriptor(VtxCF, cfOpts),
initColFamilyDescriptor(KeyCF, cfOpts)] &
RdbGuest.mapIt(initColFamilyDescriptor($it, cfOpts)) RdbGuest.mapIt(initColFamilyDescriptor($it, cfOpts))
dbOpts = defaultDbOptions() dbOpts = defaultDbOptions()
@ -77,17 +69,15 @@ proc init*(
# Reserve a family corner for `Aristo` on the database # Reserve a family corner for `Aristo` on the database
let baseDb = openRocksDb(dataDir, dbOpts, columnFamilies=cfs).valueOr: let baseDb = openRocksDb(dataDir, dbOpts, columnFamilies=cfs).valueOr:
let errSym = RdbBeDriverInitError raiseAssert initFailed & " cannot create base descriptor: " & error
when extraTraceMessages:
trace logTxt "init failed", dataDir, openMax, error=errSym, info=error
return err((errSym, error))
# Initialise `Aristo` family # Initialise column handlers (this stores implicitely `baseDb`)
rdb.store = baseDb.withColFamily(AristoFamily).valueOr: rdb.admCol = baseDb.withColFamily(AdmCF).valueOr:
let errSym = RdbBeDriverInitError raiseAssert initFailed & " cannot initialise AdmCF descriptor: " & error
when extraTraceMessages: rdb.vtxCol = baseDb.withColFamily(VtxCF).valueOr:
trace logTxt "init failed", dataDir, openMax, error=errSym, info=error raiseAssert initFailed & " cannot initialise VtxCF descriptor: " & error
return err((errSym, error)) rdb.keyCol = baseDb.withColFamily(KeyCF).valueOr:
raiseAssert initFailed & " cannot initialise KeyCF descriptor: " & error
ok() ok()
@ -95,16 +85,17 @@ proc initGuestDb*(
rdb: RdbInst; rdb: RdbInst;
instance: int; instance: int;
): Result[RootRef,(AristoError,string)] = ): Result[RootRef,(AristoError,string)] =
# Initialise `Guest` family ## Initialise `Guest` family
##
## Thus was a worth a try, but there are better solutions and this item
## will be removed in future.
##
if high(RdbGuest).ord < instance: if high(RdbGuest).ord < instance:
return err((RdbGuestInstanceUnsupported,"")) return err((RdbGuestInstanceUnsupported,""))
let let
guestSym = $RdbGuest(instance) guestSym = $RdbGuest(instance)
guestDb = rdb.store.db.withColFamily(guestSym).valueOr: guestDb = rdb.baseDb.withColFamily(guestSym).valueOr:
let errSym = RdbBeDriverGuestError raiseAssert "RocksDb/initGuestDb() failed: " & error
when extraTraceMessages:
trace logTxt "guestDb failed", error=errSym, info=error
return err((errSym, error))
ok RdbGuestDbRef( ok RdbGuestDbRef(
beKind: BackendRocksDB, beKind: BackendRocksDB,
@ -113,7 +104,7 @@ proc initGuestDb*(
proc destroy*(rdb: var RdbInst; flush: bool) = proc destroy*(rdb: var RdbInst; flush: bool) =
## Destructor ## Destructor
rdb.store.db.close() rdb.baseDb.close()
if flush: if flush:
try: try:

View File

@ -17,8 +17,8 @@ import
eth/common, eth/common,
rocksdb, rocksdb,
results, results,
stew/[endians2, keyed_queue], stew/keyed_queue,
../../aristo_desc, ../../[aristo_blobify, aristo_desc],
../init_common, ../init_common,
./rdb_desc ./rdb_desc
@ -40,37 +40,13 @@ proc disposeSession(rdb: var RdbInst) =
rdb.session.close() rdb.session.close()
rdb.session = WriteBatchRef(nil) rdb.session = WriteBatchRef(nil)
proc putImpl(
dsc: WriteBatchRef;
name: string;
key: RdbKey;
val: Blob;
): Result[void,(uint64,AristoError,string)] =
if val.len == 0:
dsc.delete(key, name).isOkOr:
const errSym = RdbBeDriverDelError
let xid = uint64.fromBytesBE key[1 .. 8]
when extraTraceMessages:
trace logTxt "del",
pfx=StorageType(key[0]), xid, error=errSym, info=error
return err((xid,errSym,error))
else:
dsc.put(key, val, name).isOkOr:
const errSym = RdbBeDriverPutError
let xid = uint64.fromBytesBE key[1 .. 8]
when extraTraceMessages:
trace logTxt "put",
pfx=StorageType(key[0]), xid, error=errSym, info=error
return err((xid,errSym,error))
ok()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public functions # Public functions
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc begin*(rdb: var RdbInst) = proc begin*(rdb: var RdbInst) =
if rdb.session.isNil: if rdb.session.isNil:
rdb.session = rdb.store.openWriteBatch() rdb.session = rdb.baseDb.openWriteBatch()
proc rollback*(rdb: var RdbInst) = proc rollback*(rdb: var RdbInst) =
if not rdb.session.isClosed(): if not rdb.session.isClosed():
@ -81,62 +57,103 @@ proc rollback*(rdb: var RdbInst) =
proc commit*(rdb: var RdbInst): Result[void,(AristoError,string)] = proc commit*(rdb: var RdbInst): Result[void,(AristoError,string)] =
if not rdb.session.isClosed(): if not rdb.session.isClosed():
defer: rdb.disposeSession() defer: rdb.disposeSession()
rdb.store.write(rdb.session).isOkOr: rdb.baseDb.write(rdb.session).isOkOr:
const errSym = RdbBeDriverWriteError const errSym = RdbBeDriverWriteError
when extraTraceMessages: when extraTraceMessages:
trace logTxt "commit", error=errSym, info=error trace logTxt "commit", error=errSym, info=error
return err((errSym,error)) return err((errSym,error))
ok() ok()
proc putByPfx*(
proc putAdm*(
rdb: var RdbInst; rdb: var RdbInst;
pfx: StorageType; xid: AdminTabID;
data: openArray[(uint64,Blob)]; data: Blob;
): Result[void,(uint64,AristoError,string)] = ): Result[void,(AdminTabID,AristoError,string)] =
let let dsc = rdb.session
dsc = rdb.session if data.len == 0:
name = rdb.store.name dsc.delete(xid.toOpenArray, AdmCF).isOkOr:
for (xid,val) in data: const errSym = RdbBeDriverDelAdmError
dsc.putImpl(name, xid.toRdbKey pfx, val).isOkOr: when extraTraceMessages:
return err(error) trace logTxt "putAdm()", xid, error=errSym, info=error
return err((xid,errSym,error))
else:
dsc.put(xid.toOpenArray, data, AdmCF).isOkOr:
const errSym = RdbBeDriverPutAdmError
when extraTraceMessages:
trace logTxt "putAdm()", xid, error=errSym, info=error
return err((xid,errSym,error))
ok() ok()
proc putKey*( proc putKey*(
rdb: var RdbInst; rdb: var RdbInst;
data: openArray[(uint64,Blob)]; data: openArray[(VertexID,HashKey)];
): Result[void,(uint64,AristoError,string)] = ): Result[void,(VertexID,AristoError,string)] =
let let dsc = rdb.session
dsc = rdb.session for (vid,key) in data:
name = rdb.store.name
for (xid,val) in data: if key.isValid:
let key = xid.toRdbKey KeyPfx dsc.put(vid.toOpenArray, key.data, KeyCF).isOkOr:
# Caller must `rollback()` which will flush the `rdKeyLru` cache
const errSym = RdbBeDriverPutKeyError
when extraTraceMessages:
trace logTxt "putKey()", vid, error=errSym, info=error
return err((vid,errSym,error))
# Update cache # Update cache
if not rdb.rdKeyLru.lruUpdate(key, val): if not rdb.rdKeyLru.lruUpdate(vid, key):
discard rdb.rdKeyLru.lruAppend(key, val, RdKeyLruMaxSize) discard rdb.rdKeyLru.lruAppend(vid, key, RdKeyLruMaxSize)
else:
dsc.delete(vid.toOpenArray, KeyCF).isOkOr:
# Caller must `rollback()` which will flush the `rdKeyLru` cache
const errSym = RdbBeDriverDelKeyError
when extraTraceMessages:
trace logTxt "putKey()", vid, error=errSym, info=error
return err((vid,errSym,error))
# Update cache, vertex will most probably never be visited anymore
rdb.rdKeyLru.del vid
# Store on write batch queue
dsc.putImpl(name, key, val).isOkOr:
return err(error)
ok() ok()
proc putVtx*( proc putVtx*(
rdb: var RdbInst; rdb: var RdbInst;
data: openArray[(uint64,Blob)]; data: openArray[(VertexID,VertexRef)];
): Result[void,(uint64,AristoError,string)] = ): Result[void,(VertexID,AristoError,string)] =
let let dsc = rdb.session
dsc = rdb.session for (vid,vtx) in data:
name = rdb.store.name
for (xid,val) in data: if vtx.isValid:
let key = xid.toRdbKey VtxPfx let rc = vtx.blobify()
if rc.isErr:
# Caller must `rollback()` which will flush the `rdVtxLru` cache
return err((vid,rc.error,""))
dsc.put(vid.toOpenArray, rc.value, VtxCF).isOkOr:
# Caller must `rollback()` which will flush the `rdVtxLru` cache
const errSym = RdbBeDriverPutVtxError
when extraTraceMessages:
trace logTxt "putVtx()", vid, error=errSym, info=error
return err((vid,errSym,error))
# Update cache # Update cache
if not rdb.rdVtxLru.lruUpdate(key, val): if not rdb.rdVtxLru.lruUpdate(vid, vtx):
discard rdb.rdVtxLru.lruAppend(key, val, RdVtxLruMaxSize) discard rdb.rdVtxLru.lruAppend(vid, vtx, RdVtxLruMaxSize)
else:
dsc.delete(vid.toOpenArray, VtxCF).isOkOr:
# Caller must `rollback()` which will flush the `rdVtxLru` cache
const errSym = RdbBeDriverDelVtxError
when extraTraceMessages:
trace logTxt "putVtx()", vid, error=errSym, info=error
return err((vid,errSym,error))
# Update cache, vertex will most probably never be visited anymore
rdb.rdVtxLru.del vid
# Store on write batch queue
dsc.putImpl(name, key, val).isOkOr:
return err(error)
ok() ok()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -17,7 +17,6 @@ import
eth/common, eth/common,
stew/endians2, stew/endians2,
rocksdb, rocksdb,
../init_common,
./rdb_desc ./rdb_desc
const const
@ -35,63 +34,53 @@ when extraTraceMessages:
# Public iterators # Public iterators
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
iterator walk*( iterator walkAdm*(rdb: RdbInst): tuple[xid: uint64, data: Blob] =
rdb: RdbInst; ## Walk over key-value pairs of the admin column of the database.
): tuple[pfx: StorageType, xid: uint64, data: Blob] = ##
## Walk over all key-value pairs of the database. ## Non-decodable entries are are ignored.
## ##
## Non-decodable entries are stepped over and ignored.
block walkBody: block walkBody:
let rit = rdb.store.openIterator().valueOr: let rit = rdb.admCol.openIterator().valueOr:
when extraTraceMessages: when extraTraceMessages:
trace logTxt "walk", pfx="all", error trace logTxt "walkAdm()", error
break walkBody break walkBody
defer: rit.close() defer: rit.close()
for (key,val) in rit.pairs: for (key,val) in rit.pairs:
if key.len == 9: if key.len == 8 and val.len != 0:
if StorageType.high.ord < key[0]: yield (uint64.fromBytesBE key, val)
break walkBody
let
pfx = StorageType(key[0])
id = uint64.fromBytesBE key.toOpenArray(1, key.len - 1)
yield (pfx, id, val)
iterator walkKey*(rdb: RdbInst): tuple[vid: uint64, data: Blob] =
iterator walk*( ## Walk over key-value pairs of the hash key column of the database.
rdb: RdbInst;
pfx: StorageType;
): tuple[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 and ignored. ## Non-decodable entries are are ignored.
## ##
block walkBody: block walkBody:
let rit = rdb.store.openIterator().valueOr: let rit = rdb.keyCol.openIterator().valueOr:
when extraTraceMessages: when extraTraceMessages:
echo ">>> walk (2) oops", trace logTxt "walkKey()", error
" pfx=", pfx
trace logTxt "walk", pfx, error
break walkBody break walkBody
defer: rit.close() defer: rit.close()
# Start at first entry not less than `<pfx> & 1` for (key,val) in rit.pairs:
rit.seekToKey 1u64.toRdbKey pfx if key.len == 8 and val.len != 0:
yield (uint64.fromBytesBE key, val)
# Fetch sub-table data as long as the current key is acceptable iterator walkVtx*(rdb: RdbInst): tuple[vid: uint64, data: Blob] =
while rit.isValid(): ## Walk over key-value pairs of the hash key column of the database.
let key = rit.key() ##
if key.len == 9: ## Non-decodable entries are are ignored.
if key[0] != pfx.ord.uint: ##
break walkBody # done block walkBody:
let rit = rdb.vtxCol.openIterator().valueOr:
when extraTraceMessages:
trace logTxt "walkVtx()", error
break walkBody
defer: rit.close()
let val = rit.value() for (key,val) in rit.pairs:
if val.len != 0: if key.len == 8 and val.len != 0:
yield (uint64.fromBytesBE key.toOpenArray(1, key.high()), val) yield (uint64.fromBytesBE key, val)
# Update Iterator
rit.next()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# End # End

View File

@ -172,7 +172,7 @@ when isMainModule:
noisy.accountsRunner(sam, resetDb=true) noisy.accountsRunner(sam, resetDb=true)
when true: # and false: when true: # and false:
let persistent = false # or true let persistent = false or true
noisy.showElapsed("@snap_test_list"): noisy.showElapsed("@snap_test_list"):
for n,sam in snapTestList: for n,sam in snapTestList:
noisy.accountsRunner(sam, persistent=persistent) noisy.accountsRunner(sam, persistent=persistent)

View File

@ -134,7 +134,7 @@ proc dbTriplet(w: LeafQuartet; rdbPath: string): Result[DbTriplet,AristoError] =
check (n, report.error) == (n,0) check (n, report.error) == (n,0)
return err(report.error) return err(report.error)
return ok dx ok dx
# ---------------------- # ----------------------
@ -338,7 +338,6 @@ proc testDistributedAccess*(
let c11Fil1_eq_db1RoFilter = c11Filter1.isDbEq(db1.balancer, db1, noisy) let c11Fil1_eq_db1RoFilter = c11Filter1.isDbEq(db1.balancer, db1, noisy)
xCheck c11Fil1_eq_db1RoFilter: xCheck c11Fil1_eq_db1RoFilter:
noisy.say "*** testDistributedAccess (7)", "n=", n, noisy.say "*** testDistributedAccess (7)", "n=", n,
"\n c11Filter1\n ", c11Filter1.pp(db1),
"db1".dump(db1), "db1".dump(db1),
"" ""
@ -346,10 +345,8 @@ proc testDistributedAccess*(
let c11Fil3_eq_db3RoFilter = c11Filter3.isDbEq(db3.balancer, db3, noisy) let c11Fil3_eq_db3RoFilter = c11Filter3.isDbEq(db3.balancer, db3, noisy)
xCheck c11Fil3_eq_db3RoFilter: xCheck c11Fil3_eq_db3RoFilter:
noisy.say "*** testDistributedAccess (8)", "n=", n, noisy.say "*** testDistributedAccess (8)", "n=", n,
"\n c11Filter3\n ", c11Filter3.pp(db3),
"db3".dump(db3), "db3".dump(db3),
"" ""
# Check/verify backends # Check/verify backends
block: block:
let ok = dy.checkBeOk(noisy=noisy,fifos=true) let ok = dy.checkBeOk(noisy=noisy,fifos=true)