parent
cf1267e845
commit
92df0b067f
|
@ -99,17 +99,24 @@ proc delete*(
|
||||||
cf.db.delete(key, cf.handle)
|
cf.db.delete(key, cf.handle)
|
||||||
|
|
||||||
proc openIterator*(
|
proc openIterator*(
|
||||||
cf: ColFamilyReadOnly | ColFamilyReadWrite
|
cf: ColFamilyReadOnly | ColFamilyReadWrite,
|
||||||
|
readOpts = defaultReadOptions(autoClose = true),
|
||||||
): RocksDBResult[RocksIteratorRef] {.inline.} =
|
): RocksDBResult[RocksIteratorRef] {.inline.} =
|
||||||
## Opens an `RocksIteratorRef` for the given column family.
|
## Opens an `RocksIteratorRef` for the given column family.
|
||||||
cf.db.openIterator(cf.handle)
|
cf.db.openIterator(readOpts, cf.handle)
|
||||||
|
|
||||||
proc openWriteBatch*(cf: ColFamilyReadWrite): WriteBatchRef {.inline.} =
|
proc openWriteBatch*(cf: ColFamilyReadWrite): WriteBatchRef {.inline.} =
|
||||||
## Opens a `WriteBatchRef` for the given column family.
|
## Opens a `WriteBatchRef` for the given column family.
|
||||||
cf.db.openWriteBatch(cf.handle)
|
cf.db.openWriteBatch(cf.handle)
|
||||||
|
|
||||||
|
proc openWriteBatchWithIndex*(
|
||||||
|
cf: ColFamilyReadWrite, reservedBytes = 0, overwriteKey = false
|
||||||
|
): WriteBatchWIRef {.inline.} =
|
||||||
|
## Opens a `WriteBatchRef` for the given column family.
|
||||||
|
cf.db.openWriteBatchWithIndex(reservedBytes, overwriteKey, cf.handle)
|
||||||
|
|
||||||
proc write*(
|
proc write*(
|
||||||
cf: ColFamilyReadWrite, updates: WriteBatchRef
|
cf: ColFamilyReadWrite, updates: WriteBatchRef | WriteBatchWIRef
|
||||||
): RocksDBResult[void] {.inline.} =
|
): RocksDBResult[void] {.inline.} =
|
||||||
## Writes the updates in the `WriteBatchRef` to the column family.
|
## Writes the updates in the `WriteBatchRef` to the column family.
|
||||||
cf.db.write(updates)
|
cf.db.write(updates)
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
|
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import ../lib/librocksdb
|
import ../lib/librocksdb, ../snapshot
|
||||||
|
|
||||||
|
export snapshot.SnapshotRef, snapshot.isClosed, snapshot.getSequenceNumber
|
||||||
|
|
||||||
type
|
type
|
||||||
ReadOptionsPtr* = ptr rocksdb_readoptions_t
|
ReadOptionsPtr* = ptr rocksdb_readoptions_t
|
||||||
|
@ -51,6 +53,10 @@ opt ignoreRangeDeletions, bool, uint8
|
||||||
opt deadline, int, uint64
|
opt deadline, int, uint64
|
||||||
opt ioTimeout, int, uint64
|
opt ioTimeout, int, uint64
|
||||||
|
|
||||||
|
proc setSnapshot*(readOpts: ReadOptionsRef, snapshot: SnapshotRef) =
|
||||||
|
doAssert not readOpts.isClosed()
|
||||||
|
rocksdb_readoptions_set_snapshot(readOpts.cPtr, snapshot.cPtr)
|
||||||
|
|
||||||
proc defaultReadOptions*(autoClose = false): ReadOptionsRef {.inline.} =
|
proc defaultReadOptions*(autoClose = false): ReadOptionsRef {.inline.} =
|
||||||
let readOpts = createReadOptions(autoClose)
|
let readOpts = createReadOptions(autoClose)
|
||||||
|
|
||||||
|
|
|
@ -31,11 +31,12 @@ import
|
||||||
./options/[dbopts, readopts, writeopts],
|
./options/[dbopts, readopts, writeopts],
|
||||||
./columnfamily/[cfopts, cfdescriptor, cfhandle],
|
./columnfamily/[cfopts, cfdescriptor, cfhandle],
|
||||||
./internal/[cftable, utils],
|
./internal/[cftable, utils],
|
||||||
./[rocksiterator, rocksresult, writebatch, writebatchwi]
|
./[rocksiterator, rocksresult, writebatch, writebatchwi, snapshot]
|
||||||
|
|
||||||
export
|
export
|
||||||
rocksresult, dbopts, readopts, writeopts, cfdescriptor, cfhandle, rocksiterator,
|
rocksresult, dbopts, readopts, writeopts, cfdescriptor, cfhandle, rocksiterator,
|
||||||
writebatch, writebatchwi
|
writebatch, writebatchwi, snapshot.SnapshotRef, snapshot.isClosed,
|
||||||
|
snapshot.getSequenceNumber
|
||||||
|
|
||||||
type
|
type
|
||||||
RocksDbPtr* = ptr rocksdb_t
|
RocksDbPtr* = ptr rocksdb_t
|
||||||
|
@ -355,16 +356,17 @@ proc delete*(
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
proc openIterator*(
|
proc openIterator*(
|
||||||
db: RocksDbRef, cfHandle = db.defaultCfHandle
|
db: RocksDbRef,
|
||||||
|
readOpts = defaultReadOptions(autoClose = true),
|
||||||
|
cfHandle = db.defaultCfHandle,
|
||||||
): RocksDBResult[RocksIteratorRef] =
|
): RocksDBResult[RocksIteratorRef] =
|
||||||
## Opens an `RocksIteratorRef` for the specified column family.
|
## Opens an `RocksIteratorRef` for the specified column family.
|
||||||
## The iterator should be closed using the `close` method after usage.
|
## The iterator should be closed using the `close` method after usage.
|
||||||
doAssert not db.isClosed()
|
doAssert not db.isClosed()
|
||||||
|
|
||||||
let rocksIterPtr =
|
let rocksIterPtr = rocksdb_create_iterator_cf(db.cPtr, readOpts.cPtr, cfHandle.cPtr)
|
||||||
rocksdb_create_iterator_cf(db.cPtr, db.readOpts.cPtr, cfHandle.cPtr)
|
|
||||||
|
|
||||||
ok(newRocksIterator(rocksIterPtr))
|
ok(newRocksIterator(rocksIterPtr, readOpts))
|
||||||
|
|
||||||
proc openWriteBatch*(
|
proc openWriteBatch*(
|
||||||
db: RocksDbReadWriteRef, cfHandle = db.defaultCfHandle
|
db: RocksDbReadWriteRef, cfHandle = db.defaultCfHandle
|
||||||
|
@ -442,6 +444,28 @@ proc ingestExternalFile*(
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
|
proc getSnapshot*(db: RocksDbRef): RocksDBResult[SnapshotRef] =
|
||||||
|
## Return a handle to the current DB state. Iterators created with this handle
|
||||||
|
## will all observe a stable snapshot of the current DB state. The caller must
|
||||||
|
## call ReleaseSnapshot(result) when the snapshot is no longer needed.
|
||||||
|
doAssert not db.isClosed()
|
||||||
|
|
||||||
|
let sHandle = rocksdb_create_snapshot(db.cPtr)
|
||||||
|
if sHandle.isNil():
|
||||||
|
err("rocksdb: failed to create snapshot")
|
||||||
|
else:
|
||||||
|
ok(newSnapshot(sHandle, SnapshotType.rocksdb))
|
||||||
|
|
||||||
|
proc releaseSnapshot*(db: RocksDbRef, snapshot: SnapshotRef) =
|
||||||
|
## Release a previously acquired snapshot. The caller must not use "snapshot"
|
||||||
|
## after this call.
|
||||||
|
doAssert not db.isClosed()
|
||||||
|
doAssert snapshot.kind == SnapshotType.rocksdb
|
||||||
|
|
||||||
|
if not snapshot.isClosed():
|
||||||
|
rocksdb_release_snapshot(db.cPtr, snapshot.cPtr)
|
||||||
|
snapshot.setClosed()
|
||||||
|
|
||||||
proc close*(db: RocksDbRef) =
|
proc close*(db: RocksDbRef) =
|
||||||
## Close the `RocksDbRef` which will release the connection to the database
|
## Close the `RocksDbRef` which will release the connection to the database
|
||||||
## and free the memory associated with it. `close` is idempotent and can
|
## and free the memory associated with it. `close` is idempotent and can
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import ./lib/librocksdb, ./internal/utils, ./rocksresult
|
import ./lib/librocksdb, ./internal/utils, ./options/readopts, ./rocksresult
|
||||||
|
|
||||||
export rocksresult
|
export rocksresult
|
||||||
|
|
||||||
|
@ -21,10 +21,13 @@ type
|
||||||
|
|
||||||
RocksIteratorRef* = ref object
|
RocksIteratorRef* = ref object
|
||||||
cPtr: RocksIteratorPtr
|
cPtr: RocksIteratorPtr
|
||||||
|
readOpts: ReadOptionsRef
|
||||||
|
|
||||||
proc newRocksIterator*(cPtr: RocksIteratorPtr): RocksIteratorRef =
|
proc newRocksIterator*(
|
||||||
|
cPtr: RocksIteratorPtr, readOpts: ReadOptionsRef
|
||||||
|
): RocksIteratorRef =
|
||||||
doAssert not cPtr.isNil()
|
doAssert not cPtr.isNil()
|
||||||
RocksIteratorRef(cPtr: cPtr)
|
RocksIteratorRef(cPtr: cPtr, readOpts: readOpts)
|
||||||
|
|
||||||
proc isClosed*(iter: RocksIteratorRef): bool {.inline.} =
|
proc isClosed*(iter: RocksIteratorRef): bool {.inline.} =
|
||||||
## Returns `true` if the iterator is closed and `false` otherwise.
|
## Returns `true` if the iterator is closed and `false` otherwise.
|
||||||
|
@ -128,6 +131,8 @@ proc close*(iter: RocksIteratorRef) =
|
||||||
rocksdb_iter_destroy(iter.cPtr)
|
rocksdb_iter_destroy(iter.cPtr)
|
||||||
iter.cPtr = nil
|
iter.cPtr = nil
|
||||||
|
|
||||||
|
autoCloseNonNil(iter.readOpts)
|
||||||
|
|
||||||
iterator pairs*(iter: RocksIteratorRef): tuple[key: seq[byte], value: seq[byte]] =
|
iterator pairs*(iter: RocksIteratorRef): tuple[key: seq[byte], value: seq[byte]] =
|
||||||
## Iterates over the key value pairs in the column family yielding them in
|
## Iterates over the key value pairs in the column family yielding them in
|
||||||
## the form of a tuple. The iterator is automatically closed after the
|
## the form of a tuple. The iterator is automatically closed after the
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
## A `SnapshotRef` represents a view of the state of the database at some point in time.
|
||||||
|
|
||||||
|
{.push raises: [].}
|
||||||
|
|
||||||
|
import ./lib/librocksdb
|
||||||
|
|
||||||
|
type
|
||||||
|
SnapshotPtr* = ptr rocksdb_snapshot_t
|
||||||
|
|
||||||
|
SnapshotType* = enum
|
||||||
|
rocksdb
|
||||||
|
transactiondb
|
||||||
|
|
||||||
|
SnapshotRef* = ref object
|
||||||
|
cPtr: SnapshotPtr
|
||||||
|
kind: SnapshotType
|
||||||
|
|
||||||
|
proc newSnapshot*(cPtr: SnapshotPtr, kind: SnapshotType): SnapshotRef =
|
||||||
|
doAssert not cPtr.isNil()
|
||||||
|
SnapshotRef(cPtr: cPtr, kind: kind)
|
||||||
|
|
||||||
|
proc isClosed*(snapshot: SnapshotRef): bool {.inline.} =
|
||||||
|
## Returns `true` if the `SnapshotRef` has been closed and `false` otherwise.
|
||||||
|
snapshot.cPtr.isNil()
|
||||||
|
|
||||||
|
proc cPtr*(snapshot: SnapshotRef): SnapshotPtr =
|
||||||
|
## Get the underlying database pointer.
|
||||||
|
doAssert not snapshot.isClosed()
|
||||||
|
snapshot.cPtr
|
||||||
|
|
||||||
|
proc kind*(snapshot: SnapshotRef): SnapshotType =
|
||||||
|
## Get the kind of the `SnapshotRef`.
|
||||||
|
snapshot.kind
|
||||||
|
|
||||||
|
proc getSequenceNumber*(snapshot: SnapshotRef): uint64 =
|
||||||
|
## Return the associated sequence number.
|
||||||
|
doAssert not snapshot.isClosed()
|
||||||
|
rocksdb_snapshot_get_sequence_number(snapshot.cPtr).uint64
|
||||||
|
|
||||||
|
proc setClosed*(snapshot: SnapshotRef) =
|
||||||
|
# The snapshot should be released from `RocksDbRef` or `TransactionDbRef`
|
||||||
|
snapshot.cPtr = nil
|
|
@ -22,10 +22,12 @@ import
|
||||||
./transactions/[transaction, txdbopts, txopts],
|
./transactions/[transaction, txdbopts, txopts],
|
||||||
./columnfamily/[cfopts, cfdescriptor, cfhandle],
|
./columnfamily/[cfopts, cfdescriptor, cfhandle],
|
||||||
./internal/[cftable, utils],
|
./internal/[cftable, utils],
|
||||||
./rocksresult
|
./[rocksiterator, rocksresult, snapshot]
|
||||||
|
|
||||||
export
|
export
|
||||||
dbopts, txdbopts, cfdescriptor, readopts, writeopts, txopts, transaction, rocksresult
|
dbopts, txdbopts, cfdescriptor, readopts, writeopts, txopts, transaction,
|
||||||
|
rocksiterator, rocksresult, snapshot.SnapshotRef, snapshot.isClosed,
|
||||||
|
snapshot.getSequenceNumber
|
||||||
|
|
||||||
type
|
type
|
||||||
TransactionDbPtr* = ptr rocksdb_transactiondb_t
|
TransactionDbPtr* = ptr rocksdb_transactiondb_t
|
||||||
|
@ -120,6 +122,42 @@ proc beginTransaction*(
|
||||||
|
|
||||||
newTransaction(txPtr, readOpts, writeOpts, txOpts, nil, cfHandle)
|
newTransaction(txPtr, readOpts, writeOpts, txOpts, nil, cfHandle)
|
||||||
|
|
||||||
|
proc openIterator*(
|
||||||
|
db: TransactionDbRef,
|
||||||
|
readOpts = defaultReadOptions(autoClose = true),
|
||||||
|
cfHandle = db.defaultCfHandle,
|
||||||
|
): RocksDBResult[RocksIteratorRef] =
|
||||||
|
## Opens an `RocksIteratorRef` for the specified column family.
|
||||||
|
## The iterator should be closed using the `close` method after usage.
|
||||||
|
doAssert not db.isClosed()
|
||||||
|
|
||||||
|
let rocksIterPtr =
|
||||||
|
rocksdb_transactiondb_create_iterator_cf(db.cPtr, readOpts.cPtr, cfHandle.cPtr)
|
||||||
|
|
||||||
|
ok(newRocksIterator(rocksIterPtr, readOpts))
|
||||||
|
|
||||||
|
proc getSnapshot*(db: TransactionDbRef): RocksDBResult[SnapshotRef] =
|
||||||
|
## Return a handle to the current DB state. Iterators created with this handle
|
||||||
|
## will all observe a stable snapshot of the current DB state. The caller must
|
||||||
|
## call ReleaseSnapshot(result) when the snapshot is no longer needed.
|
||||||
|
doAssert not db.isClosed()
|
||||||
|
|
||||||
|
let sHandle = rocksdb_transactiondb_create_snapshot(db.cPtr)
|
||||||
|
if sHandle.isNil():
|
||||||
|
err("rocksdb: failed to create snapshot")
|
||||||
|
else:
|
||||||
|
ok(newSnapshot(sHandle, SnapshotType.transactiondb))
|
||||||
|
|
||||||
|
proc releaseSnapshot*(db: TransactionDbRef, snapshot: SnapshotRef) =
|
||||||
|
## Release a previously acquired snapshot. The caller must not use "snapshot"
|
||||||
|
## after this call.
|
||||||
|
doAssert not db.isClosed()
|
||||||
|
doAssert snapshot.kind == SnapshotType.transactiondb
|
||||||
|
|
||||||
|
if not snapshot.isClosed():
|
||||||
|
rocksdb_transactiondb_release_snapshot(db.cPtr, snapshot.cPtr)
|
||||||
|
snapshot.setClosed()
|
||||||
|
|
||||||
proc close*(db: TransactionDbRef) =
|
proc close*(db: TransactionDbRef) =
|
||||||
## Close the `TransactionDbRef`.
|
## Close the `TransactionDbRef`.
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,10 @@ import
|
||||||
../lib/librocksdb,
|
../lib/librocksdb,
|
||||||
../options/[readopts, writeopts],
|
../options/[readopts, writeopts],
|
||||||
../internal/[cftable, utils],
|
../internal/[cftable, utils],
|
||||||
../rocksresult,
|
../[rocksiterator, rocksresult],
|
||||||
./[txopts, otxopts]
|
./[txopts, otxopts]
|
||||||
|
|
||||||
export rocksresult
|
export rocksiterator, rocksresult
|
||||||
|
|
||||||
type
|
type
|
||||||
TransactionPtr* = ptr rocksdb_transaction_t
|
TransactionPtr* = ptr rocksdb_transaction_t
|
||||||
|
@ -162,6 +162,20 @@ proc rollback*(tx: TransactionRef): RocksDBResult[void] =
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
|
proc openIterator*(
|
||||||
|
db: TransactionRef,
|
||||||
|
readOpts = defaultReadOptions(autoClose = true),
|
||||||
|
cfHandle = db.defaultCfHandle,
|
||||||
|
): RocksDBResult[RocksIteratorRef] =
|
||||||
|
## Opens an `RocksIteratorRef` for the specified column family.
|
||||||
|
## The iterator should be closed using the `close` method after usage.
|
||||||
|
doAssert not db.isClosed()
|
||||||
|
|
||||||
|
let rocksIterPtr =
|
||||||
|
rocksdb_transaction_create_iterator_cf(db.cPtr, readOpts.cPtr, cfHandle.cPtr)
|
||||||
|
|
||||||
|
ok(newRocksIterator(rocksIterPtr, readOpts))
|
||||||
|
|
||||||
proc close*(tx: TransactionRef) =
|
proc close*(tx: TransactionRef) =
|
||||||
## Close the `TransactionRef`.
|
## Close the `TransactionRef`.
|
||||||
if not tx.isClosed():
|
if not tx.isClosed():
|
||||||
|
|
|
@ -46,7 +46,7 @@ proc isClosed*(batch: WriteBatchWIRef): bool {.inline.} =
|
||||||
batch.cPtr.isNil()
|
batch.cPtr.isNil()
|
||||||
|
|
||||||
proc cPtr*(batch: WriteBatchWIRef): WriteBatchWIPtr =
|
proc cPtr*(batch: WriteBatchWIRef): WriteBatchWIPtr =
|
||||||
## Get the underlying database pointer.
|
## Get the underlying write batch pointer.
|
||||||
doAssert not batch.isClosed()
|
doAssert not batch.isClosed()
|
||||||
batch.cPtr
|
batch.cPtr
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ proc delete*(
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
proc get*(
|
proc getFromBatch*(
|
||||||
batch: WriteBatchWIRef,
|
batch: WriteBatchWIRef,
|
||||||
key: openArray[byte],
|
key: openArray[byte],
|
||||||
onData: DataProc,
|
onData: DataProc,
|
||||||
|
@ -118,7 +118,7 @@ proc get*(
|
||||||
rocksdb_free(data)
|
rocksdb_free(data)
|
||||||
ok(true)
|
ok(true)
|
||||||
|
|
||||||
proc get*(
|
proc getFromBatch*(
|
||||||
batch: WriteBatchWIRef, key: openArray[byte], cfHandle = batch.defaultCfHandle
|
batch: WriteBatchWIRef, key: openArray[byte], cfHandle = batch.defaultCfHandle
|
||||||
): RocksDBResult[seq[byte]] =
|
): RocksDBResult[seq[byte]] =
|
||||||
## Get the value for a given key from the batch.
|
## Get the value for a given key from the batch.
|
||||||
|
@ -127,7 +127,7 @@ proc get*(
|
||||||
proc onData(data: openArray[byte]) =
|
proc onData(data: openArray[byte]) =
|
||||||
dataRes.ok(@data)
|
dataRes.ok(@data)
|
||||||
|
|
||||||
let res = batch.get(key, onData, cfHandle)
|
let res = batch.getFromBatch(key, onData, cfHandle)
|
||||||
if res.isOk():
|
if res.isOk():
|
||||||
return dataRes
|
return dataRes
|
||||||
|
|
||||||
|
|
|
@ -87,3 +87,19 @@ suite "ColFamily Tests":
|
||||||
|
|
||||||
readOnlyCf.db.close()
|
readOnlyCf.db.close()
|
||||||
check readOnlyCf.db.isClosed()
|
check readOnlyCf.db.isClosed()
|
||||||
|
|
||||||
|
test "Test iterator":
|
||||||
|
let cf = db.getColFamily(CF_OTHER).get()
|
||||||
|
check cf.put(key, val).isOk()
|
||||||
|
|
||||||
|
let iter = cf.openIterator().get()
|
||||||
|
defer:
|
||||||
|
iter.close()
|
||||||
|
|
||||||
|
iter.seekToKey(key)
|
||||||
|
check:
|
||||||
|
iter.isValid() == true
|
||||||
|
iter.key() == key
|
||||||
|
iter.value() == val
|
||||||
|
iter.seekToKey(otherKey)
|
||||||
|
check iter.isValid() == false
|
||||||
|
|
|
@ -460,3 +460,55 @@ suite "RocksDbRef Tests":
|
||||||
|
|
||||||
cfOpts.close()
|
cfOpts.close()
|
||||||
removeDir($dbPath)
|
removeDir($dbPath)
|
||||||
|
|
||||||
|
test "Test iterator":
|
||||||
|
check db.put(key, val).isOk()
|
||||||
|
|
||||||
|
let iter = db.openIterator().get()
|
||||||
|
defer:
|
||||||
|
iter.close()
|
||||||
|
|
||||||
|
iter.seekToKey(key)
|
||||||
|
check:
|
||||||
|
iter.isValid() == true
|
||||||
|
iter.key() == key
|
||||||
|
iter.value() == val
|
||||||
|
iter.seekToKey(otherKey)
|
||||||
|
check iter.isValid() == false
|
||||||
|
|
||||||
|
test "Create and restore snapshot":
|
||||||
|
check:
|
||||||
|
db.put(key, val).isOk()
|
||||||
|
db.keyExists(key).get() == true
|
||||||
|
db.keyMayExist(otherKey).get() == false
|
||||||
|
|
||||||
|
let snapshot = db.getSnapshot().get()
|
||||||
|
check:
|
||||||
|
snapshot.getSequenceNumber() > 0
|
||||||
|
not snapshot.isClosed()
|
||||||
|
|
||||||
|
# after taking snapshot, update the db
|
||||||
|
check:
|
||||||
|
db.delete(key).isOk()
|
||||||
|
db.put(otherKey, val).isOk()
|
||||||
|
db.keyMayExist(key).get() == false
|
||||||
|
db.keyExists(otherKey).get() == true
|
||||||
|
|
||||||
|
let readOpts = defaultReadOptions(autoClose = true)
|
||||||
|
readOpts.setSnapshot(snapshot)
|
||||||
|
|
||||||
|
# read from the snapshot using an iterator
|
||||||
|
let iter = db.openIterator(readOpts = readOpts).get()
|
||||||
|
defer:
|
||||||
|
iter.close()
|
||||||
|
iter.seekToKey(key)
|
||||||
|
check:
|
||||||
|
iter.isValid() == true
|
||||||
|
iter.key() == key
|
||||||
|
iter.value() == val
|
||||||
|
iter.seekToKey(otherKey)
|
||||||
|
check:
|
||||||
|
iter.isValid() == false
|
||||||
|
|
||||||
|
db.releaseSnapshot(snapshot)
|
||||||
|
check snapshot.isClosed()
|
||||||
|
|
|
@ -46,7 +46,7 @@ suite "RocksIteratorRef Tests":
|
||||||
removeDir($dbPath)
|
removeDir($dbPath)
|
||||||
|
|
||||||
test "Iterate forwards using default column family":
|
test "Iterate forwards using default column family":
|
||||||
let res = db.openIterator(defaultCfHandle)
|
let res = db.openIterator(cfHandle = defaultCfHandle)
|
||||||
check res.isOk()
|
check res.isOk()
|
||||||
|
|
||||||
var iter = res.get()
|
var iter = res.get()
|
||||||
|
@ -72,7 +72,7 @@ suite "RocksIteratorRef Tests":
|
||||||
check expected == byte(4)
|
check expected == byte(4)
|
||||||
|
|
||||||
test "Iterate backwards using other column family":
|
test "Iterate backwards using other column family":
|
||||||
let res = db.openIterator(otherCfHandle)
|
let res = db.openIterator(cfHandle = otherCfHandle)
|
||||||
check res.isOk()
|
check res.isOk()
|
||||||
|
|
||||||
var iter = res.get()
|
var iter = res.get()
|
||||||
|
@ -106,12 +106,12 @@ suite "RocksIteratorRef Tests":
|
||||||
iter.close()
|
iter.close()
|
||||||
|
|
||||||
test "Open two iterators on the same column family":
|
test "Open two iterators on the same column family":
|
||||||
let res1 = db.openIterator(defaultCfHandle)
|
let res1 = db.openIterator(cfHandle = defaultCfHandle)
|
||||||
check res1.isOk()
|
check res1.isOk()
|
||||||
var iter1 = res1.get()
|
var iter1 = res1.get()
|
||||||
defer:
|
defer:
|
||||||
iter1.close()
|
iter1.close()
|
||||||
let res2 = db.openIterator(defaultCfHandle)
|
let res2 = db.openIterator(cfHandle = defaultCfHandle)
|
||||||
check res2.isOk()
|
check res2.isOk()
|
||||||
var iter2 = res2.get()
|
var iter2 = res2.get()
|
||||||
defer:
|
defer:
|
||||||
|
@ -129,12 +129,12 @@ suite "RocksIteratorRef Tests":
|
||||||
iter2.value() == @[byte(3)]
|
iter2.value() == @[byte(3)]
|
||||||
|
|
||||||
test "Open two iterators on different column families":
|
test "Open two iterators on different column families":
|
||||||
let res1 = db.openIterator(defaultCfHandle)
|
let res1 = db.openIterator(cfHandle = defaultCfHandle)
|
||||||
check res1.isOk()
|
check res1.isOk()
|
||||||
var iter1 = res1.get()
|
var iter1 = res1.get()
|
||||||
defer:
|
defer:
|
||||||
iter1.close()
|
iter1.close()
|
||||||
let res2 = db.openIterator(otherCfHandle)
|
let res2 = db.openIterator(cfHandle = otherCfHandle)
|
||||||
check res2.isOk()
|
check res2.isOk()
|
||||||
var iter2 = res2.get()
|
var iter2 = res2.get()
|
||||||
defer:
|
defer:
|
||||||
|
@ -152,7 +152,7 @@ suite "RocksIteratorRef Tests":
|
||||||
iter2.value() == @[byte(3)]
|
iter2.value() == @[byte(3)]
|
||||||
|
|
||||||
test "Iterate forwards using seek to key":
|
test "Iterate forwards using seek to key":
|
||||||
let res = db.openIterator(defaultCfHandle)
|
let res = db.openIterator(cfHandle = defaultCfHandle)
|
||||||
check res.isOk()
|
check res.isOk()
|
||||||
|
|
||||||
var iter = res.get()
|
var iter = res.get()
|
||||||
|
@ -180,7 +180,7 @@ suite "RocksIteratorRef Tests":
|
||||||
iter.value() == val1
|
iter.value() == val1
|
||||||
|
|
||||||
test "Empty column family":
|
test "Empty column family":
|
||||||
let res = db.openIterator(emptyCfHandle)
|
let res = db.openIterator(cfHandle = emptyCfHandle)
|
||||||
check res.isOk()
|
check res.isOk()
|
||||||
var iter = res.get()
|
var iter = res.get()
|
||||||
defer:
|
defer:
|
||||||
|
@ -193,7 +193,7 @@ suite "RocksIteratorRef Tests":
|
||||||
check not iter.isValid()
|
check not iter.isValid()
|
||||||
|
|
||||||
test "Test status":
|
test "Test status":
|
||||||
let res = db.openIterator(emptyCfHandle)
|
let res = db.openIterator(cfHandle = emptyCfHandle)
|
||||||
check res.isOk()
|
check res.isOk()
|
||||||
var iter = res.get()
|
var iter = res.get()
|
||||||
defer:
|
defer:
|
||||||
|
@ -204,7 +204,7 @@ suite "RocksIteratorRef Tests":
|
||||||
check iter.status().isOk()
|
check iter.status().isOk()
|
||||||
|
|
||||||
test "Test pairs iterator":
|
test "Test pairs iterator":
|
||||||
let res = db.openIterator(defaultCfHandle)
|
let res = db.openIterator(cfHandle = defaultCfHandle)
|
||||||
check res.isOk()
|
check res.isOk()
|
||||||
var iter = res.get()
|
var iter = res.get()
|
||||||
|
|
||||||
|
|
|
@ -307,3 +307,87 @@ suite "TransactionDbRef Tests":
|
||||||
writeOpts.isClosed() == false
|
writeOpts.isClosed() == false
|
||||||
txOpts.isClosed() == false
|
txOpts.isClosed() == false
|
||||||
tx.isClosed() == true
|
tx.isClosed() == true
|
||||||
|
|
||||||
|
test "Test iterator":
|
||||||
|
let tx1 = db.beginTransaction()
|
||||||
|
defer:
|
||||||
|
tx1.close()
|
||||||
|
check:
|
||||||
|
tx1.put(key1, val1).isOk()
|
||||||
|
tx1.commit().isOk()
|
||||||
|
|
||||||
|
block:
|
||||||
|
# test the db iterator
|
||||||
|
let iter = db.openIterator().get()
|
||||||
|
defer:
|
||||||
|
iter.close()
|
||||||
|
|
||||||
|
iter.seekToKey(key1)
|
||||||
|
check:
|
||||||
|
iter.isValid() == true
|
||||||
|
iter.key() == key1
|
||||||
|
iter.value() == val1
|
||||||
|
iter.seekToKey(key2)
|
||||||
|
check iter.isValid() == false
|
||||||
|
|
||||||
|
block:
|
||||||
|
# test the tx iterator
|
||||||
|
let iter = tx1.openIterator().get()
|
||||||
|
defer:
|
||||||
|
iter.close()
|
||||||
|
|
||||||
|
iter.seekToKey(key1)
|
||||||
|
check:
|
||||||
|
iter.isValid() == true
|
||||||
|
iter.key() == key1
|
||||||
|
iter.value() == val1
|
||||||
|
iter.seekToKey(key2)
|
||||||
|
check iter.isValid() == false
|
||||||
|
|
||||||
|
test "Create and restore snapshot":
|
||||||
|
let tx1 = db.beginTransaction()
|
||||||
|
defer:
|
||||||
|
tx1.close()
|
||||||
|
check:
|
||||||
|
tx1.put(key1, val1).isOk()
|
||||||
|
tx1.commit().isOk()
|
||||||
|
|
||||||
|
let snapshot = db.getSnapshot().get()
|
||||||
|
check:
|
||||||
|
snapshot.getSequenceNumber() > 0
|
||||||
|
not snapshot.isClosed()
|
||||||
|
|
||||||
|
# after taking snapshot, update the db
|
||||||
|
let tx2 = db.beginTransaction()
|
||||||
|
defer:
|
||||||
|
tx2.close()
|
||||||
|
check:
|
||||||
|
tx2.delete(key1).isOk()
|
||||||
|
tx2.put(key2, val2).isOk()
|
||||||
|
tx2.commit().isOk()
|
||||||
|
|
||||||
|
let readOpts = defaultReadOptions(autoClose = true)
|
||||||
|
readOpts.setSnapshot(snapshot)
|
||||||
|
|
||||||
|
# read from the snapshot using an iterator
|
||||||
|
let iter = db.openIterator(readOpts = readOpts).get()
|
||||||
|
defer:
|
||||||
|
iter.close()
|
||||||
|
iter.seekToKey(key1)
|
||||||
|
check:
|
||||||
|
iter.isValid() == true
|
||||||
|
iter.key() == key1
|
||||||
|
iter.value() == val1
|
||||||
|
iter.seekToKey(key2)
|
||||||
|
check iter.isValid() == false
|
||||||
|
|
||||||
|
# read from the snapshot using a transaction
|
||||||
|
let tx3 = db.beginTransaction(readOpts = readOpts)
|
||||||
|
defer:
|
||||||
|
tx3.close()
|
||||||
|
check:
|
||||||
|
tx3.get(key1).get() == val1
|
||||||
|
tx3.get(key2).isErr()
|
||||||
|
|
||||||
|
db.releaseSnapshot(snapshot)
|
||||||
|
check snapshot.isClosed()
|
||||||
|
|
|
@ -51,9 +51,9 @@ suite "WriteBatchWIRef Tests":
|
||||||
batch.count() == 4
|
batch.count() == 4
|
||||||
not batch.isClosed()
|
not batch.isClosed()
|
||||||
|
|
||||||
batch.get(key1).get() == val1
|
batch.getFromBatch(key1).get() == val1
|
||||||
batch.get(key2).isErr()
|
batch.getFromBatch(key2).isErr()
|
||||||
batch.get(key3).get() == val3
|
batch.getFromBatch(key3).get() == val3
|
||||||
|
|
||||||
let res = db.write(batch)
|
let res = db.write(batch)
|
||||||
check:
|
check:
|
||||||
|
@ -63,9 +63,9 @@ suite "WriteBatchWIRef Tests":
|
||||||
db.keyExists(key2).get() == false
|
db.keyExists(key2).get() == false
|
||||||
db.get(key3).get() == val3
|
db.get(key3).get() == val3
|
||||||
|
|
||||||
batch.get(key1).get() == val1
|
batch.getFromBatch(key1).get() == val1
|
||||||
batch.get(key2).isErr()
|
batch.getFromBatch(key2).isErr()
|
||||||
batch.get(key3).get() == val3
|
batch.getFromBatch(key3).get() == val3
|
||||||
|
|
||||||
batch.clear()
|
batch.clear()
|
||||||
check:
|
check:
|
||||||
|
@ -88,9 +88,9 @@ suite "WriteBatchWIRef Tests":
|
||||||
batch.count() == 4
|
batch.count() == 4
|
||||||
not batch.isClosed()
|
not batch.isClosed()
|
||||||
|
|
||||||
batch.get(key1, otherCfHandle).get() == val1
|
batch.getFromBatch(key1, otherCfHandle).get() == val1
|
||||||
batch.get(key2, otherCfHandle).isErr()
|
batch.getFromBatch(key2, otherCfHandle).isErr()
|
||||||
batch.get(key3, otherCfHandle).get() == val3
|
batch.getFromBatch(key3, otherCfHandle).get() == val3
|
||||||
|
|
||||||
let res = db.write(batch)
|
let res = db.write(batch)
|
||||||
check:
|
check:
|
||||||
|
@ -99,9 +99,9 @@ suite "WriteBatchWIRef Tests":
|
||||||
db.keyExists(key2, otherCfHandle).get() == false
|
db.keyExists(key2, otherCfHandle).get() == false
|
||||||
db.get(key3, otherCfHandle).get() == val3
|
db.get(key3, otherCfHandle).get() == val3
|
||||||
|
|
||||||
batch.get(key1, otherCfHandle).get() == val1
|
batch.getFromBatch(key1, otherCfHandle).get() == val1
|
||||||
batch.get(key2, otherCfHandle).isErr()
|
batch.getFromBatch(key2, otherCfHandle).isErr()
|
||||||
batch.get(key3, otherCfHandle).get() == val3
|
batch.getFromBatch(key3, otherCfHandle).get() == val3
|
||||||
|
|
||||||
batch.clear()
|
batch.clear()
|
||||||
check:
|
check:
|
||||||
|
@ -205,13 +205,13 @@ suite "WriteBatchWIRef Tests":
|
||||||
batch1.delete(key1).isOk()
|
batch1.delete(key1).isOk()
|
||||||
batch1.put(key1, val3).isOk()
|
batch1.put(key1, val3).isOk()
|
||||||
batch1.count() == 3
|
batch1.count() == 3
|
||||||
batch1.get(key1).get() == val3
|
batch1.getFromBatch(key1).get() == val3
|
||||||
|
|
||||||
batch2.put(key1, val3).isOk()
|
batch2.put(key1, val3).isOk()
|
||||||
batch2.put(key1, val2).isOk()
|
batch2.put(key1, val2).isOk()
|
||||||
batch2.put(key1, val1).isOk()
|
batch2.put(key1, val1).isOk()
|
||||||
batch2.count() == 3
|
batch2.count() == 3
|
||||||
batch2.get(key1).get() == val1
|
batch2.getFromBatch(key1).get() == val1
|
||||||
|
|
||||||
test "Put, get and delete empty key":
|
test "Put, get and delete empty key":
|
||||||
let batch = db.openWriteBatchWithIndex()
|
let batch = db.openWriteBatchWithIndex()
|
||||||
|
@ -221,9 +221,9 @@ suite "WriteBatchWIRef Tests":
|
||||||
let empty: seq[byte] = @[]
|
let empty: seq[byte] = @[]
|
||||||
check:
|
check:
|
||||||
batch.put(empty, val1).isOk()
|
batch.put(empty, val1).isOk()
|
||||||
batch.get(empty).get() == val1
|
batch.getFromBatch(empty).get() == val1
|
||||||
batch.delete(empty).isOk()
|
batch.delete(empty).isOk()
|
||||||
batch.get(empty).isErr()
|
batch.getFromBatch(empty).isErr()
|
||||||
|
|
||||||
test "Test close":
|
test "Test close":
|
||||||
let batch = db.openWriteBatchWithIndex()
|
let batch = db.openWriteBatchWithIndex()
|
||||||
|
|
Loading…
Reference in New Issue