From 55487c8e1dc4e0ccaa2ca351ed200933b69cc2c3 Mon Sep 17 00:00:00 2001 From: web3-developer <51288821+web3-developer@users.noreply.github.com> Date: Sat, 17 Feb 2024 01:23:49 +0800 Subject: [PATCH] Started rewrite of library. --- rocksdb.nim | 308 +-------------------------- rocksdb/columnfamily/cfopts.nim | 45 ++++ rocksdb/columnfamily/descriptor.nim | 37 ++++ rocksdb/columnfamily/handle.nim | 46 ++++ rocksdb/internal/utils.nim | 0 rocksdb/{ => lib}/headers/c.h | 0 rocksdb/{ => lib}/librocksdb.nim | 0 rocksdb/options/dbopts.nim | 77 +++++++ rocksdb/options/readopts.nim | 37 ++++ rocksdb/options/writeopts.nim | 37 ++++ rocksdb/rocksdb.nim | 94 +++++++++ rocksdb/rocksdb_old.nim | 316 ++++++++++++++++++++++++++++ 12 files changed, 691 insertions(+), 306 deletions(-) create mode 100644 rocksdb/columnfamily/cfopts.nim create mode 100644 rocksdb/columnfamily/descriptor.nim create mode 100644 rocksdb/columnfamily/handle.nim create mode 100644 rocksdb/internal/utils.nim rename rocksdb/{ => lib}/headers/c.h (100%) rename rocksdb/{ => lib}/librocksdb.nim (100%) create mode 100644 rocksdb/options/dbopts.nim create mode 100644 rocksdb/options/readopts.nim create mode 100644 rocksdb/options/writeopts.nim create mode 100644 rocksdb/rocksdb.nim create mode 100644 rocksdb/rocksdb_old.nim diff --git a/rocksdb.nim b/rocksdb.nim index 499dd3a..c06e357 100644 --- a/rocksdb.nim +++ b/rocksdb.nim @@ -7,310 +7,6 @@ # # at your option. This file may not be copied, modified, or distributed except according to those terms. -{.push raises: [Defect].} - -import std/[cpuinfo, options, tables], - stew/[byteutils, results] - -export results - -const useCApi = true - -when useCApi: - import rocksdb/librocksdb - export librocksdb - -else: - {.error: "The C++ API of RocksDB is not supported yet".} - - # The intention of this template is that it will hide the - # difference between the C and C++ APIs for objects such - # as Read/WriteOptions, which are allocated either on the - # stack or the heap. - template initResource(resourceName) = - var res = resourceName() - res - -type - RocksDBInstance* = object - db*: ptr rocksdb_t - backupEngine: ptr rocksdb_backup_engine_t - options*: seq[ptr rocksdb_options_t] - readOptions*: ptr rocksdb_readoptions_t - writeOptions: ptr rocksdb_writeoptions_t - dbPath: string # needed for clear() - columnFamilyNames: cstringArray - columnFamilies: TableRef[cstring, ptr rocksdb_column_family_handle_t] - - DataProc* = proc(val: openArray[byte]) {.gcsafe, raises: [Defect].} - - RocksDBResult*[T] = Result[T, string] - -template bailOnErrors {.dirty.} = - if not errors.isNil: - result.err($(errors)) - rocksdb_free(errors) - return result - -template validateColumnFamily( - db: RocksDBInstance, - columnFamily: string): ptr rocksdb_column_family_handle_t = - - if not db.columnFamilies.contains(columnFamily): - return err("rocksdb: unknown column family") - - let columnFamilyHandle= db.columnFamilies.getOrDefault(columnFamily) - doAssert not columnFamilyHandle.isNil - columnFamilyHandle - - -proc init*(rocks: var RocksDBInstance, - dbPath, dbBackupPath: string, - readOnly = false, - cpus = countProcessors(), - createIfMissing = true, - maxOpenFiles = -1, - columnFamilyNames: openArray[string] = @["default"]): RocksDBResult[void] = - - for i in 0..columnFamilyNames.high: - rocks.options.add(rocksdb_options_create()) - rocks.readOptions = rocksdb_readoptions_create() - rocks.writeOptions = rocksdb_writeoptions_create() - rocks.dbPath = dbPath - rocks.columnFamilyNames = columnFamilyNames.allocCStringArray - rocks.columnFamilies = newTable[cstring, ptr rocksdb_column_family_handle_t]() - - for opts in rocks.options: - # Optimize RocksDB. This is the easiest way to get RocksDB to perform well: - rocksdb_options_increase_parallelism(opts, cpus.int32) - # This requires snappy - disabled because rocksdb is not always compiled with - # snappy support (for example Fedora 28, certain Ubuntu versions) - # rocksdb_options_optimize_level_style_compaction(options, 0); - rocksdb_options_set_create_if_missing(opts, uint8(createIfMissing)) - # default set to keep all files open (-1), allow setting it to a specific - # value, e.g. in case the application limit would be reached. - rocksdb_options_set_max_open_files(opts, maxOpenFiles.cint) - # Enable creating column families if they do not exist - rocksdb_options_set_create_missing_column_families(opts, uint8(true)) - - var - columnFamilyHandles = newSeq[ptr rocksdb_column_family_handle_t](columnFamilyNames.len) - errors: cstring - if readOnly: - rocks.db = rocksdb_open_for_read_only_column_families( - rocks.options[0], - dbPath, - columnFamilyNames.len().cint, - rocks.columnFamilyNames, - rocks.options[0].addr, - columnFamilyHandles[0].addr, - 0'u8, - cast[cstringArray](errors.addr)) - else: - rocks.db = rocksdb_open_column_families( - rocks.options[0], - dbPath, - columnFamilyNames.len().cint, - rocks.columnFamilyNames, - rocks.options[0].addr, - columnFamilyHandles[0].addr, - cast[cstringArray](errors.addr)) - bailOnErrors() - - for i in 0.. 0: unsafeAddr val[0] else: nil), - csize_t(val.len), - cast[cstringArray](errors.addr)) - bailOnErrors() - - ok() - -proc contains*(db: RocksDBInstance, key: openArray[byte], columnFamily = "default"): RocksDBResult[bool] = - if key.len <= 0: - return err("rocksdb: key cannot be empty on contains") - - let columnFamilyHandle = db.validateColumnFamily(columnFamily) - - var - errors: cstring - len: csize_t - data = rocksdb_get_cf( - db.db, - db.readOptions, - columnFamilyHandle, - cast[cstring](unsafeAddr key[0]), - csize_t(key.len), - addr len, - cast[cstringArray](errors.addr)) - bailOnErrors() - - if not data.isNil: - rocksdb_free(data) - ok(true) - else: - ok(false) - -proc del*( - db: RocksDBInstance, - key: openArray[byte], - columnFamily = "default"): RocksDBResult[bool] = - - if key.len <= 0: - return err("rocksdb: key cannot be empty on del") - - let columnFamilyHandle = db.validateColumnFamily(columnFamily) - - # This seems like a bad idea, but right now I don't want to - # get sidetracked by this. --Adam - if not db.contains(key, columnFamily).get: - return ok(false) - - var errors: cstring - rocksdb_delete_cf( - db.db, - db.writeOptions, - columnFamilyHandle, - cast[cstring](unsafeAddr key[0]), - csize_t(key.len), - cast[cstringArray](errors.addr)) - bailOnErrors() - - ok(true) - -proc clear*(db: var RocksDBInstance): RocksDBResult[bool] = - raiseAssert "unimplemented" - -proc backup*(db: RocksDBInstance): RocksDBResult[void] = - var errors: cstring - rocksdb_backup_engine_create_new_backup(db.backupEngine, db.db, cast[cstringArray](errors.addr)) - bailOnErrors() - ok() - -# XXX: destructors are just too buggy at the moment: -# https://github.com/nim-lang/Nim/issues/8112 -# proc `=destroy`*(db: var RocksDBInstance) = -proc close*(db: var RocksDBInstance) = - - if not db.columnFamilies.isNil: - for _, v in db.columnFamilies: - rocksdb_column_family_handle_destroy(v) - db.columnFamilies = nil - - if not db.columnFamilyNames.isNil: - db.columnFamilyNames.deallocCStringArray() - db.columnFamilyNames = nil - - if not db.writeOptions.isNil: - rocksdb_writeoptions_destroy(db.writeOptions) - db.writeOptions = nil - - if not db.readOptions.isNil: - rocksdb_readoptions_destroy(db.readOptions) - db.readOptions = nil - - if db.options.len() > 0: - for o in db.options: - rocksdb_options_destroy(o) - db.options = @[] - - if not db.backupEngine.isNil: - rocksdb_backup_engine_close(db.backupEngine) - db.backupEngine = nil - - if not db.db.isNil: - rocksdb_close(db.db) - db.db = nil +import ./rocksdb/[rocksdb_old, rocksdb] +export rocksdb_old, rocksdb \ No newline at end of file diff --git a/rocksdb/columnfamily/cfopts.nim b/rocksdb/columnfamily/cfopts.nim new file mode 100644 index 0000000..1e14144 --- /dev/null +++ b/rocksdb/columnfamily/cfopts.nim @@ -0,0 +1,45 @@ +# Nim-RocksDB +# Copyright 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) +# * GPL license, version 2.0, ([LICENSE-GPLv2](LICENSE-GPLv2) or https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) +# +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +import + ../lib/librocksdb + +type + OptionsPtr = ptr rocksdb_options_t + + ColFamilyOptionsRef* = ref object + optionsPtr: OptionsPtr + +proc newColFamilyOptions*(): ColFamilyOptionsRef = + ColFamilyOptionsRef(optionsPtr: rocksdb_options_create()) + +template isClosed(dbOpts: ColFamilyOptionsRef): bool = + dbOpts.optionsPtr.isNil() + +proc setCreateMissingColumnFamilies*(cfOpts: var ColFamilyOptionsRef, flag: bool) = + doAssert not cfOpts.isClosed() + rocksdb_options_set_create_missing_column_families(cfOpts.optionsPtr, flag.uint8) + +proc defaultColFamilyOptions*(): ColFamilyOptionsRef = + var opts = newColFamilyOptions() + # Enable creating column families if they do not exist + opts.setCreateMissingColumnFamilies(true) + return opts + +proc getCreateMissingColumnFamilies*(cfOpts: ColFamilyOptionsRef): bool = + doAssert not cfOpts.isClosed() + rocksdb_options_get_create_missing_column_families(cfOpts.optionsPtr).bool + +proc close*(cfOpts: var ColFamilyOptionsRef) = + if not cfOpts.isClosed(): + rocksdb_options_destroy(cfOpts.optionsPtr) + cfOpts.optionsPtr = nil + diff --git a/rocksdb/columnfamily/descriptor.nim b/rocksdb/columnfamily/descriptor.nim new file mode 100644 index 0000000..a5c3077 --- /dev/null +++ b/rocksdb/columnfamily/descriptor.nim @@ -0,0 +1,37 @@ +# Nim-RocksDB +# Copyright 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) +# * GPL license, version 2.0, ([LICENSE-GPLv2](LICENSE-GPLv2) or https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) +# +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +import + ./cfopts + +const DEFAULT_COLUMN_FAMILY* = "default" + +type + ColFamilyDescriptor* = object + name: string + options: ColFamilyOptionsRef + +proc initColFamilyDescriptor*( + name: string, + options = defaultColFamilyOptions()): ColFamilyDescriptor = + ColFamilyDescriptor(name: name, options: options) + +proc name*(descriptor: ColFamilyDescriptor): string = + descriptor.name + +proc options*(descriptor: ColFamilyDescriptor): ColFamilyOptionsRef = + descriptor.options + +proc defaultColFamilyDescriptor*(): ColFamilyDescriptor = + initColFamilyDescriptor(DEFAULT_COLUMN_FAMILY) + +template close*(descriptor: var ColFamilyDescriptor) = + descriptor.options.close() diff --git a/rocksdb/columnfamily/handle.nim b/rocksdb/columnfamily/handle.nim new file mode 100644 index 0000000..4cd4885 --- /dev/null +++ b/rocksdb/columnfamily/handle.nim @@ -0,0 +1,46 @@ +# Nim-RocksDB +# Copyright 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) +# * GPL license, version 2.0, ([LICENSE-GPLv2](LICENSE-GPLv2) or https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) +# +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +import + ../lib/librocksdb, + ./descriptor + +type + ColFamilyHandlePtr* = ptr rocksdb_column_family_handle_t + + ColFamilyHandleRef* = ref object + handlePtr: ColFamilyHandlePtr + +proc newColFamilyHandle*(handlePtr: ColFamilyHandlePtr): ColFamilyHandleRef = + ColFamilyHandleRef(handlePtr: handlePtr) + +template isClosed(handle: ColFamilyHandleRef): bool = + handle.handlePtr.isNil() + +proc getId*(handle: ColFamilyHandleRef): int = + doAssert not handle.isClosed() + rocksdb_column_family_handle_get_id(handle.handlePtr).int + +proc getName*(handle: ColFamilyHandleRef): string = + doAssert not handle.isClosed() + var nameLen: csize_t # do we need to use this? + $rocksdb_column_family_handle_get_name(handle.handlePtr, nameLen.addr) + +proc isDefault*(handle: ColFamilyHandleRef): bool = + handle.getName() == DEFAULT_COLUMN_FAMILY + +# proc getDescriptor*(handle: ColFamilyHandleRef): ColumnFamilyDescriptor = +# doAssert not handle.isClosed() + +proc close*(handle: var ColFamilyHandleRef) = + if not handle.isClosed(): + rocksdb_column_family_handle_destroy(handle.handlePtr) + handle.handlePtr = nil \ No newline at end of file diff --git a/rocksdb/internal/utils.nim b/rocksdb/internal/utils.nim new file mode 100644 index 0000000..e69de29 diff --git a/rocksdb/headers/c.h b/rocksdb/lib/headers/c.h similarity index 100% rename from rocksdb/headers/c.h rename to rocksdb/lib/headers/c.h diff --git a/rocksdb/librocksdb.nim b/rocksdb/lib/librocksdb.nim similarity index 100% rename from rocksdb/librocksdb.nim rename to rocksdb/lib/librocksdb.nim diff --git a/rocksdb/options/dbopts.nim b/rocksdb/options/dbopts.nim new file mode 100644 index 0000000..ed9c575 --- /dev/null +++ b/rocksdb/options/dbopts.nim @@ -0,0 +1,77 @@ +# Nim-RocksDB +# Copyright 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) +# * GPL license, version 2.0, ([LICENSE-GPLv2](LICENSE-GPLv2) or https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) +# +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +import + std/cpuinfo, + ../lib/librocksdb + +type + OptionsPtr = ptr rocksdb_options_t + + DbOptionsRef* = ref object + optionsPtr: OptionsPtr + +proc newDbOptions*(): DbOptionsRef = + DbOptionsRef(optionsPtr: rocksdb_options_create()) + +template isClosed(dbOpts: DbOptionsRef): bool = + dbOpts.optionsPtr.isNil() + +proc setIncreaseParallelism*(dbOpts: var DbOptionsRef, totalThreads: int) = + doAssert totalThreads > 0 + doAssert not dbOpts.isClosed() + rocksdb_options_increase_parallelism(dbOpts.optionsPtr, totalThreads.cint) + +proc setCreateIfMissing*(dbOpts: var DbOptionsRef, flag: bool) = + doAssert not dbOpts.isClosed() + rocksdb_options_set_create_if_missing(dbOpts.optionsPtr, flag.uint8) + +proc setMaxOpenFiles*(dbOpts: var DbOptionsRef, maxOpenFiles: int) = + doAssert maxOpenFiles > -1 + doAssert not dbOpts.isClosed() + rocksdb_options_set_max_open_files(dbOpts.optionsPtr, maxOpenFiles.cint) + +proc setCreateMissingColumnFamilies*(dbOpts: var DbOptionsRef, flag: bool) = + doAssert not dbOpts.isClosed() + rocksdb_options_set_create_missing_column_families(dbOpts.optionsPtr, flag.uint8) + +proc defaultDbOptions*(): DbOptionsRef = + var opts = newDbOptions() + # Optimize RocksDB. This is the easiest way to get RocksDB to perform well: + opts.setIncreaseParallelism(countProcessors()) + # This requires snappy - disabled because rocksdb is not always compiled with + # snappy support (for example Fedora 28, certain Ubuntu versions) + # rocksdb_options_optimize_level_style_compaction(options, 0); + opts.setCreateIfMissing(true) + # default set to keep all files open (-1), allow setting it to a specific + # value, e.g. in case the application limit would be reached. + opts.setMaxOpenFiles(-1) + # Enable creating column families if they do not exist + opts.setCreateMissingColumnFamilies(true) + return opts + +proc getCreateIfMissing*(dbOpts: DbOptionsRef): bool = + doAssert not dbOpts.isClosed() + rocksdb_options_get_create_if_missing(dbOpts.optionsPtr).bool + +proc getMaxOpenFiles*(dbOpts: DbOptionsRef): int = + doAssert not dbOpts.isClosed() + rocksdb_options_get_max_open_files(dbOpts.optionsPtr).int + +proc getCreateMissingColumnFamilies*(dbOpts: DbOptionsRef): bool = + doAssert not dbOpts.isClosed() + rocksdb_options_get_create_missing_column_families(dbOpts.optionsPtr).bool + +proc close*(dbOpts: var DbOptionsRef) = + if not dbOpts.isClosed(): + rocksdb_options_destroy(dbOpts.optionsPtr) + dbOpts.optionsPtr = nil + diff --git a/rocksdb/options/readopts.nim b/rocksdb/options/readopts.nim new file mode 100644 index 0000000..97fe76c --- /dev/null +++ b/rocksdb/options/readopts.nim @@ -0,0 +1,37 @@ +# Nim-RocksDB +# Copyright 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) +# * GPL license, version 2.0, ([LICENSE-GPLv2](LICENSE-GPLv2) or https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) +# +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +import + ../lib/librocksdb + +type + ReadOptionsPtr = ptr rocksdb_readoptions_t + + ReadOptionsRef* = ref object + readOptsPtr: ReadOptionsPtr + +proc newReadOptions*(): ReadOptionsRef = + ReadOptionsRef(readOptsPtr: rocksdb_readoptions_create()) + +template defaultReadOptions*(): ReadOptionsRef = + newReadOptions() + +template isClosed(readOpts: ReadOptionsRef): bool = + readOpts.readOptsPtr.isNil() + +# TODO: Add setters and getters for read options properties. +# Currently we are using the default settings. + +proc close*(readOpts: var ReadOptionsRef) = + if not readOpts.isClosed(): + rocksdb_readoptions_destroy(readOpts.readOptsPtr) + readOpts.readOptsPtr = nil + diff --git a/rocksdb/options/writeopts.nim b/rocksdb/options/writeopts.nim new file mode 100644 index 0000000..d4ca8cd --- /dev/null +++ b/rocksdb/options/writeopts.nim @@ -0,0 +1,37 @@ +# Nim-RocksDB +# Copyright 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) +# * GPL license, version 2.0, ([LICENSE-GPLv2](LICENSE-GPLv2) or https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) +# +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +import + ../lib/librocksdb + +type + WriteOptionsPtr = ptr rocksdb_writeoptions_t + + WriteOptionsRef* = ref object + writeOptsPtr: WriteOptionsPtr + +proc newWriteOptions*(): WriteOptionsRef = + WriteOptionsRef(writeOptsPtr: rocksdb_writeoptions_create()) + +template defaultWriteOptions*(): WriteOptionsRef = + newWriteOptions() + +template isClosed(writeOpts: WriteOptionsRef): bool = + writeOpts.writeOptsPtr.isNil() + +# TODO: Add setters and getters for write options properties. +# Currently we are using the default settings. + +proc close*(writeOpts: var WriteOptionsRef) = + if not writeOpts.isClosed(): + rocksdb_writeoptions_destroy(writeOpts.writeOptsPtr) + writeOpts.writeOptsPtr = nil + diff --git a/rocksdb/rocksdb.nim b/rocksdb/rocksdb.nim new file mode 100644 index 0000000..c741485 --- /dev/null +++ b/rocksdb/rocksdb.nim @@ -0,0 +1,94 @@ +# Nim-RocksDB +# Copyright 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) +# * GPL license, version 2.0, ([LICENSE-GPLv2](LICENSE-GPLv2) or https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) +# +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +{.push raises: [].} + +import + std/[cpuinfo, tables], + results, + ./lib/librocksdb, + ./options/[dbopts, readopts, writeopts], + ./columnfamily/[cfopts, descriptor, handle] + +export results + +type + RocksDBResult*[T] = Result[T, string] + + RocksDbPtr = ptr rocksdb_t + + RocksDbRef* = ref object + rocksDbPtr: RocksDbPtr + dbOpts: DbOptionsRef + readOpts: ReadOptionsRef + writeOpts: WriteOptionsRef + # dbPath: string + # columnFamilyNames: cstringArray + # columnFamilies: TableRef[cstring, ptr rocksdb_column_family_handle_t] + + #DataProc* = proc(val: openArray[byte]) {.gcsafe, raises: [].} + +proc openRocksDb*( + path: string, + dbOpts = defaultDbOptions(), + readOpts = defaultReadOptions(), + writeOpts = defaultWriteOptions(), + columnFamilies = @[defaultColFamilyDescriptor()]): RocksDBResult[RocksDbRef] = + + discard + + # for i in 0..columnFamilyNames.high: + # rocks.options.add(rocksdb_options_create()) + # rocks.readOptions = rocksdb_readoptions_create() + # rocks.writeOptions = rocksdb_writeoptions_create() + # rocks.dbPath = dbPath + # rocks.columnFamilyNames = columnFamilyNames.allocCStringArray + # rocks.columnFamilies = newTable[cstring, ptr rocksdb_column_family_handle_t]() + + # for opts in rocks.options: + # # Optimize RocksDB. This is the easiest way to get RocksDB to perform well: + # rocksdb_options_increase_parallelism(opts, cpus.int32) + # # This requires snappy - disabled because rocksdb is not always compiled with + # # snappy support (for example Fedora 28, certain Ubuntu versions) + # # rocksdb_options_optimize_level_style_compaction(options, 0); + # rocksdb_options_set_create_if_missing(opts, uint8(createIfMissing)) + # # default set to keep all files open (-1), allow setting it to a specific + # # value, e.g. in case the application limit would be reached. + # rocksdb_options_set_max_open_files(opts, maxOpenFiles.cint) + # # Enable creating column families if they do not exist + # rocksdb_options_set_create_missing_column_families(opts, uint8(true)) + + # var + # columnFamilyHandles = newSeq[ptr rocksdb_column_family_handle_t](columnFamilyNames.len) + # errors: cstring + # rocks.db = rocksdb_open_column_families( + # rocks.options[0], + # dbPath, + # columnFamilyNames.len().cint, + # rocks.columnFamilyNames, + # rocks.options[0].addr, + # columnFamilyHandles[0].addr, + # cast[cstringArray](errors.addr)) + # bailOnErrors() + + # for i in 0.. 0: unsafeAddr val[0] else: nil), + csize_t(val.len), + cast[cstringArray](errors.addr)) + bailOnErrors() + + ok() + +proc contains*(db: RocksDBInstance, key: openArray[byte], columnFamily = "default"): RocksDBResult[bool] = + if key.len <= 0: + return err("rocksdb: key cannot be empty on contains") + + let columnFamilyHandle = db.validateColumnFamily(columnFamily) + + var + errors: cstring + len: csize_t + data = rocksdb_get_cf( + db.db, + db.readOptions, + columnFamilyHandle, + cast[cstring](unsafeAddr key[0]), + csize_t(key.len), + addr len, + cast[cstringArray](errors.addr)) + bailOnErrors() + + if not data.isNil: + rocksdb_free(data) + ok(true) + else: + ok(false) + +proc del*( + db: RocksDBInstance, + key: openArray[byte], + columnFamily = "default"): RocksDBResult[bool] = + + if key.len <= 0: + return err("rocksdb: key cannot be empty on del") + + let columnFamilyHandle = db.validateColumnFamily(columnFamily) + + # This seems like a bad idea, but right now I don't want to + # get sidetracked by this. --Adam + if not db.contains(key, columnFamily).get: + return ok(false) + + var errors: cstring + rocksdb_delete_cf( + db.db, + db.writeOptions, + columnFamilyHandle, + cast[cstring](unsafeAddr key[0]), + csize_t(key.len), + cast[cstringArray](errors.addr)) + bailOnErrors() + + ok(true) + +proc clear*(db: var RocksDBInstance): RocksDBResult[bool] = + raiseAssert "unimplemented" + +proc backup*(db: RocksDBInstance): RocksDBResult[void] = + var errors: cstring + rocksdb_backup_engine_create_new_backup(db.backupEngine, db.db, cast[cstringArray](errors.addr)) + bailOnErrors() + ok() + +# XXX: destructors are just too buggy at the moment: +# https://github.com/nim-lang/Nim/issues/8112 +#proc `=destroy`*(db: var RocksDBInstance) = +proc close*(db: var RocksDBInstance) = + + if not db.columnFamilies.isNil: + for _, v in db.columnFamilies: + rocksdb_column_family_handle_destroy(v) + db.columnFamilies = nil + + if not db.columnFamilyNames.isNil: + db.columnFamilyNames.deallocCStringArray() + db.columnFamilyNames = nil + + if not db.writeOptions.isNil: + rocksdb_writeoptions_destroy(db.writeOptions) + db.writeOptions = nil + + if not db.readOptions.isNil: + rocksdb_readoptions_destroy(db.readOptions) + db.readOptions = nil + + if db.options.len() > 0: + for o in db.options: + rocksdb_options_destroy(o) + db.options = @[] + + if not db.backupEngine.isNil: + rocksdb_backup_engine_close(db.backupEngine) + db.backupEngine = nil + + if not db.db.isNil: + rocksdb_close(db.db) + db.db = nil +