Skip to content

Commit

Permalink
Update Nimbus codebase to use the new nim-rocksdb API. (#2054)
Browse files Browse the repository at this point in the history
* Bump nim-rocksdb.

* Update codebase to use latest nim-rocksdb API.

* Update copyright notices.

* Fix memory leak due to allocCStringArray without deallocCStringArray.

* Improve kvstore_rocksdb code.

* Refactor and cleanup RocksStoreRef.

* Update nim-rocksdb submodule to latest.
  • Loading branch information
web3-developer committed Mar 5, 2024
1 parent 587ca3a commit 11691c3
Show file tree
Hide file tree
Showing 18 changed files with 183 additions and 99 deletions.
12 changes: 7 additions & 5 deletions nimbus/db/aristo/aristo_init/rocks_db/rdb_desc.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# nimbus-eth1
# Copyright (c) 2023 Status Research & Development GmbH
# Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http:https://www.apache.org/licenses/LICENSE-2.0)
Expand All @@ -16,24 +16,26 @@
import
std/[tables, os],
eth/common,
rocksdb/lib/librocksdb,
rocksdb,
stew/endians2,
../../aristo_desc,
../init_common

type
RdbInst* = object
store*: RocksDBInstance ## Rocks DB database handler
dbOpts*: DbOptionsRef
store*: RocksDbReadWriteRef ## Rocks DB database handler
basePath*: string ## Database directory

# Low level Rocks DB access for bulk store
envOpt*: rocksdb_envoptions_t
impOpt*: rocksdb_ingestexternalfileoptions_t
envOpt*: ptr rocksdb_envoptions_t
impOpt*: ptr rocksdb_ingestexternalfileoptions_t

RdbKey* = array[1 + sizeof VertexID, byte]
## Sub-table key, <pfx> + VertexID

RdbTabs* = array[StorageType,Table[uint64,Blob]]
RdbTabs* = array[StorageType, Table[uint64,Blob]]
## Combined table for caching data to be stored/updated

const
Expand Down
13 changes: 9 additions & 4 deletions nimbus/db/aristo/aristo_init/rocks_db/rdb_init.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# nimbus-eth1
# Copyright (c) 2023 Status Research & Development GmbH
# Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http:https://www.apache.org/licenses/LICENSE-2.0)
Expand All @@ -16,6 +16,7 @@
import
std/os,
chronicles,
rocksdb/lib/librocksdb,
rocksdb,
results,
../../aristo_desc,
Expand Down Expand Up @@ -61,15 +62,19 @@ proc init*(
except OSError, IOError:
return err((RdbBeCantCreateTmpDir, ""))

let rc = rdb.store.init(
dbPath=dataDir, dbBackuppath=backupsDir, readOnly=false,
maxOpenFiles=openMax)
let dbOpts = defaultDbOptions()
dbOpts.setMaxOpenFiles(openMax)

let rc = openRocksDb(dataDir, dbOpts)
if rc.isErr:
let error = RdbBeDriverInitError
debug logTxt "driver failed", dataDir, backupsDir, openMax,
error, info=rc.error
return err((RdbBeDriverInitError, rc.error))

rdb.dbOpts = dbOpts
rdb.store = rc.get()

# The following is a default setup (subject to change)
rdb.impOpt = rocksdb_ingestexternalfileoptions_create()
rdb.envOpt = rocksdb_envoptions_create()
Expand Down
21 changes: 12 additions & 9 deletions nimbus/db/aristo/aristo_init/rocks_db/rdb_put.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# nimbus-eth1
# Copyright (c) 2023 Status Research & Development GmbH
# Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http:https://www.apache.org/licenses/LICENSE-2.0)
Expand All @@ -17,6 +17,7 @@ import
std/[algorithm, os, sequtils, strutils, sets, tables],
chronicles,
eth/common,
rocksdb/lib/librocksdb,
rocksdb,
results,
"../.."/[aristo_constants, aristo_desc],
Expand All @@ -28,7 +29,7 @@ logScope:

type
RdbPutSession = object
writer: rocksdb_sstfilewriter_t
writer: ptr rocksdb_sstfilewriter_t
sstPath: string
nRecords: int

Expand Down Expand Up @@ -75,7 +76,7 @@ proc begin(
var csError: cstring

var session = RdbPutSession(
writer: rocksdb_sstfilewriter_create(rdb.envOpt, rdb.store.options),
writer: rocksdb_sstfilewriter_create(rdb.envOpt, rdb.dbOpts.cPtr),
sstPath: rdb.sstFilePath)

if session.writer.isNil:
Expand All @@ -88,7 +89,7 @@ proc begin(
session.sstPath.rmFileIgnExpt

session.writer.rocksdb_sstfilewriter_open(
session.sstPath.cstring, addr csError)
session.sstPath.cstring, cast[cstringArray](csError.addr))
if not csError.isNil:
session.destroy()
return err((RdbBeOpenSstWriter, $csError))
Expand All @@ -111,7 +112,8 @@ proc add(

session.writer.rocksdb_sstfilewriter_add(
cast[cstring](unsafeAddr key[0]), csize_t(key.len),
cast[cstring](unsafeAddr val[0]), csize_t(val.len), addr csError)
cast[cstring](unsafeAddr val[0]), csize_t(val.len),
cast[cstringArray](csError.addr))
if not csError.isNil:
return err((RdbBeAddSstWriter, $csError))

Expand All @@ -129,12 +131,13 @@ proc commit(
var csError: cstring

if 0 < session.nRecords:
session.writer.rocksdb_sstfilewriter_finish(addr csError)
session.writer.rocksdb_sstfilewriter_finish(cast[cstringArray](csError.addr))
if not csError.isNil:
return err((RdbBeFinishSstWriter, $csError))

rdb.store.db.rocksdb_ingest_external_file(
[session.sstPath].allocCStringArray, 1, rdb.impOpt, addr csError)
var sstPath = session.sstPath.cstring
rdb.store.cPtr.rocksdb_ingest_external_file(
cast[cstringArray](sstPath.addr), 1, rdb.impOpt, cast[cstringArray](csError.addr))
if not csError.isNil:
return err((RdbBeIngestSstWriter, $csError))

Expand Down Expand Up @@ -186,7 +189,7 @@ proc put*(

# Delete vertices after successfully updating vertices with non-zero values.
for key in delKey:
let rc = rdb.store.del key
let rc = rdb.store.delete key
if rc.isErr:
return err((RdbBeDriverDelError,rc.error))

Expand Down
20 changes: 15 additions & 5 deletions nimbus/db/aristo/aristo_init/rocks_db/rdb_walk.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# nimbus-eth1
# Copyright (c) 2023 Status Research & Development GmbH
# Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http:https://www.apache.org/licenses/LICENSE-2.0)
Expand All @@ -17,6 +17,7 @@ import
std/sequtils,
eth/common,
stew/endians2,
rocksdb/lib/librocksdb,
rocksdb,
../init_common,
./rdb_desc
Expand Down Expand Up @@ -49,8 +50,13 @@ iterator walk*(
## Walk over all key-value pairs of the database.
##
## Non-decodable entries are stepped over and ignored.
let rit = rdb.store.db.rocksdb_create_iterator(rdb.store.readOptions)
defer: rit.rocksdb_iter_destroy()

let
readOptions = rocksdb_readoptions_create()
rit = rdb.store.cPtr.rocksdb_create_iterator(readOptions)
defer:
rit.rocksdb_iter_destroy()
readOptions.rocksdb_readoptions_destroy()

rit.rocksdb_iter_seek_to_first()

Expand Down Expand Up @@ -91,8 +97,12 @@ iterator walk*(
# Unsupported
break walkBody

let rit = rdb.store.db.rocksdb_create_iterator(rdb.store.readOptions)
defer: rit.rocksdb_iter_destroy()
let
readOptions = rocksdb_readoptions_create()
rit = rdb.store.cPtr.rocksdb_create_iterator(readOptions)
defer:
rit.rocksdb_iter_destroy()
readOptions.rocksdb_readoptions_destroy()

var
kLen: csize_t
Expand Down
2 changes: 1 addition & 1 deletion nimbus/db/core_db/backend/legacy_rocksdb.nim
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ proc newLegacyPersistentCoreDbRef*(path: string): CoreDbRef =
raise (ref ResultDefect)(msg: msg)

proc done() =
backend.rdb.store.close()
backend.rdb.close()

LegaPersDbRef(rdb: backend.rdb).init(LegacyDbPersistent, backend.trieDB, done)

Expand Down
86 changes: 61 additions & 25 deletions nimbus/db/kvstore_rocksdb.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Nimbus
# Copyright (c) 2023 Status Research & Development GmbH
# Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http:https://www.apache.org/licenses/LICENSE-2.0)
Expand All @@ -12,45 +12,76 @@

import
std/os,
rocksdb, stew/results,
stew/results,
rocksdb,
eth/db/kvstore

export results, kvstore
export kvstore

const maxOpenFiles = 512

type
RocksStoreRef* = ref object of RootObj
store*: RocksDBInstance
tmpDir*: string
db: RocksDbRef
backupEngine: BackupEngineRef
readOnly: bool

proc get*(db: RocksStoreRef, key: openArray[byte], onData: kvstore.DataProc): KvResult[bool] =
db.store.get(key, onData)
proc readOnly*(store: RocksStoreRef): bool =
store.readOnly

proc find*(db: RocksStoreRef, prefix: openArray[byte], onFind: kvstore.KeyValueProc): KvResult[int] =
proc readOnlyDb*(store: RocksStoreRef): RocksDbReadOnlyRef =
doAssert store.readOnly
store.db.RocksDbReadOnlyRef

proc readWriteDb*(store: RocksStoreRef): RocksDbReadWriteRef =
doAssert not store.readOnly
store.db.RocksDbReadWriteRef

template validateCanWriteAndGet(store: RocksStoreRef): RocksDbReadWriteRef =
if store.readOnly:
raiseAssert "Unimplemented"
store.db.RocksDbReadWriteRef

proc get*(store: RocksStoreRef, key: openArray[byte], onData: kvstore.DataProc): KvResult[bool] =
store.db.get(key, onData)

proc find*(store: RocksStoreRef, prefix: openArray[byte], onFind: kvstore.KeyValueProc): KvResult[int] =
raiseAssert "Unimplemented"

proc put*(db: RocksStoreRef, key, value: openArray[byte]): KvResult[void] =
db.store.put(key, value)
proc put*(store: RocksStoreRef, key, value: openArray[byte]): KvResult[void] =
store.validateCanWriteAndGet().put(key, value)

proc contains*(store: RocksStoreRef, key: openArray[byte]): KvResult[bool] =
store.db.keyExists(key)

proc contains*(db: RocksStoreRef, key: openArray[byte]): KvResult[bool] =
db.store.contains(key)
proc del*(store: RocksStoreRef, key: openArray[byte]): KvResult[bool] =
let db = store.validateCanWriteAndGet()

proc del*(db: RocksStoreRef, key: openArray[byte]): KvResult[bool] =
db.store.del(key)
let exists = ? db.keyExists(key)
if not exists:
return ok(false)

proc clear*(db: RocksStoreRef): KvResult[bool] =
db.store.clear()
let res = db.delete(key)
if res.isErr():
return err(res.error())

proc close*(db: RocksStoreRef) =
db.store.close
ok(true)

proc clear*(store: RocksStoreRef): KvResult[bool] =
raiseAssert "Unimplemented"

proc close*(store: RocksStoreRef) =
store.db.close()
store.backupEngine.close()

proc init*(
T: type RocksStoreRef, basePath: string, name: string,
T: type RocksStoreRef,
basePath: string,
name: string,
readOnly = false): KvResult[T] =

let
dataDir = basePath / name / "data"
# tmpDir = basePath / name / "tmp" -- notused
backupsDir = basePath / name / "backups"

try:
Expand All @@ -59,9 +90,14 @@ proc init*(
except OSError, IOError:
return err("rocksdb: cannot create database directory")

var store: RocksDBInstance
if (let v = store.init(
dataDir, backupsDir, readOnly, maxOpenFiles = maxOpenFiles); v.isErr):
return err(v.error)
let backupEngine = ? openBackupEngine(backupsDir)

let dbOpts = defaultDbOptions()
dbOpts.setMaxOpenFiles(maxOpenFiles)

ok(T(store: store))
if readOnly:
let readOnlyDb = ? openRocksDbReadOnly(dataDir, dbOpts)
ok(T(db: readOnlyDb, backupEngine: backupEngine, readOnly: true))
else:
let readWriteDb = ? openRocksDb(dataDir, dbOpts)
ok(T(db: readWriteDb, backupEngine: backupEngine, readOnly: false))
10 changes: 6 additions & 4 deletions nimbus/db/kvt/kvt_init/rocks_db/rdb_desc.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# nimbus-eth1
# Copyright (c) 2023 Status Research & Development GmbH
# Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http:https://www.apache.org/licenses/LICENSE-2.0)
Expand All @@ -15,16 +15,18 @@

import
std/os,
rocksdb/lib/librocksdb,
rocksdb

type
RdbInst* = object
store*: RocksDBInstance ## Rocks DB database handler
dbOpts*: DbOptionsRef
store*: RocksDbReadWriteRef ## Rocks DB database handler
basePath*: string ## Database directory

# Low level Rocks DB access for bulk store
envOpt*: rocksdb_envoptions_t
impOpt*: rocksdb_ingestexternalfileoptions_t
envOpt*: ptr rocksdb_envoptions_t
impOpt*: ptr rocksdb_ingestexternalfileoptions_t

const
BaseFolder* = "nimbus" # Same as for Legacy DB
Expand Down
13 changes: 9 additions & 4 deletions nimbus/db/kvt/kvt_init/rocks_db/rdb_init.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# nimbus-eth1
# Copyright (c) 2023 Status Research & Development GmbH
# Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http:https://www.apache.org/licenses/LICENSE-2.0)
Expand All @@ -16,6 +16,7 @@
import
std/os,
chronicles,
rocksdb/lib/librocksdb,
rocksdb,
results,
../../kvt_desc,
Expand Down Expand Up @@ -61,15 +62,19 @@ proc init*(
except OSError, IOError:
return err((RdbBeCantCreateTmpDir, ""))

let rc = rdb.store.init(
dbPath=dataDir, dbBackuppath=backupsDir, readOnly=false,
maxOpenFiles=openMax)
let dbOpts = defaultDbOptions()
dbOpts.setMaxOpenFiles(openMax)

let rc = openRocksDb(dataDir, dbOpts)
if rc.isErr:
let error = RdbBeDriverInitError
debug logTxt "driver failed", dataDir, backupsDir, openMax,
error, info=rc.error
return err((RdbBeDriverInitError, rc.error))

rdb.dbOpts = dbOpts
rdb.store = rc.get()

# The following is a default setup (subject to change)
rdb.impOpt = rocksdb_ingestexternalfileoptions_create()
rdb.envOpt = rocksdb_envoptions_create()
Expand Down
Loading

0 comments on commit 11691c3

Please sign in to comment.