diff --git a/rocksdb/transactions/transaction.nim b/rocksdb/transactions/transaction.nim index e0db707..8c27bcd 100644 --- a/rocksdb/transactions/transaction.nim +++ b/rocksdb/transactions/transaction.nim @@ -23,10 +23,10 @@ import ../lib/librocksdb, ../options/[readopts, writeopts], ../internal/[cftable, utils], - ../rocksresult, + ../[rocksiterator, rocksresult], ./[txopts, otxopts] -export rocksresult +export rocksiterator, rocksresult type TransactionPtr* = ptr rocksdb_transaction_t @@ -162,6 +162,20 @@ proc rollback*(tx: TransactionRef): RocksDBResult[void] = 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) = ## Close the `TransactionRef`. if not tx.isClosed(): diff --git a/rocksdb/writebatchwi.nim b/rocksdb/writebatchwi.nim index f4b4f9c..59456c0 100644 --- a/rocksdb/writebatchwi.nim +++ b/rocksdb/writebatchwi.nim @@ -87,7 +87,7 @@ proc delete*( ok() -proc get*( +proc getFromBatch*( batch: WriteBatchWIRef, key: openArray[byte], onData: DataProc, @@ -118,7 +118,7 @@ proc get*( rocksdb_free(data) ok(true) -proc get*( +proc getFromBatch*( batch: WriteBatchWIRef, key: openArray[byte], cfHandle = batch.defaultCfHandle ): RocksDBResult[seq[byte]] = ## Get the value for a given key from the batch. @@ -127,7 +127,7 @@ proc get*( proc onData(data: openArray[byte]) = dataRes.ok(@data) - let res = batch.get(key, onData, cfHandle) + let res = batch.getFromBatch(key, onData, cfHandle) if res.isOk(): return dataRes diff --git a/tests/test_rocksdb.nim b/tests/test_rocksdb.nim index 4a48345..28bef1c 100644 --- a/tests/test_rocksdb.nim +++ b/tests/test_rocksdb.nim @@ -461,6 +461,21 @@ suite "RocksDbRef Tests": cfOpts.close() 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() @@ -472,6 +487,7 @@ suite "RocksDbRef Tests": snapshot.getSequenceNumber() > 0 not snapshot.isClosed() + # after taking snapshot, update the db check: db.delete(key).isOk() db.put(otherKey, val).isOk() @@ -480,10 +496,11 @@ suite "RocksDbRef Tests": 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 diff --git a/tests/test_transactiondb.nim b/tests/test_transactiondb.nim index 454ecb5..53ef338 100644 --- a/tests/test_transactiondb.nim +++ b/tests/test_transactiondb.nim @@ -308,8 +308,46 @@ suite "TransactionDbRef Tests": txOpts.isClosed() == false 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() @@ -319,7 +357,10 @@ suite "TransactionDbRef Tests": 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() @@ -327,18 +368,26 @@ suite "TransactionDbRef Tests": 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: - iter.isValid() == false + tx3.get(key1).get() == val1 + tx3.get(key2).isErr() db.releaseSnapshot(snapshot) check snapshot.isClosed() diff --git a/tests/test_writebatchwi.nim b/tests/test_writebatchwi.nim index 457d06d..c59c446 100644 --- a/tests/test_writebatchwi.nim +++ b/tests/test_writebatchwi.nim @@ -51,9 +51,9 @@ suite "WriteBatchWIRef Tests": batch.count() == 4 not batch.isClosed() - batch.get(key1).get() == val1 - batch.get(key2).isErr() - batch.get(key3).get() == val3 + batch.getFromBatch(key1).get() == val1 + batch.getFromBatch(key2).isErr() + batch.getFromBatch(key3).get() == val3 let res = db.write(batch) check: @@ -63,9 +63,9 @@ suite "WriteBatchWIRef Tests": db.keyExists(key2).get() == false db.get(key3).get() == val3 - batch.get(key1).get() == val1 - batch.get(key2).isErr() - batch.get(key3).get() == val3 + batch.getFromBatch(key1).get() == val1 + batch.getFromBatch(key2).isErr() + batch.getFromBatch(key3).get() == val3 batch.clear() check: @@ -88,9 +88,9 @@ suite "WriteBatchWIRef Tests": batch.count() == 4 not batch.isClosed() - batch.get(key1, otherCfHandle).get() == val1 - batch.get(key2, otherCfHandle).isErr() - batch.get(key3, otherCfHandle).get() == val3 + batch.getFromBatch(key1, otherCfHandle).get() == val1 + batch.getFromBatch(key2, otherCfHandle).isErr() + batch.getFromBatch(key3, otherCfHandle).get() == val3 let res = db.write(batch) check: @@ -99,9 +99,9 @@ suite "WriteBatchWIRef Tests": db.keyExists(key2, otherCfHandle).get() == false db.get(key3, otherCfHandle).get() == val3 - batch.get(key1, otherCfHandle).get() == val1 - batch.get(key2, otherCfHandle).isErr() - batch.get(key3, otherCfHandle).get() == val3 + batch.getFromBatch(key1, otherCfHandle).get() == val1 + batch.getFromBatch(key2, otherCfHandle).isErr() + batch.getFromBatch(key3, otherCfHandle).get() == val3 batch.clear() check: @@ -205,13 +205,13 @@ suite "WriteBatchWIRef Tests": batch1.delete(key1).isOk() batch1.put(key1, val3).isOk() batch1.count() == 3 - batch1.get(key1).get() == val3 + batch1.getFromBatch(key1).get() == val3 batch2.put(key1, val3).isOk() batch2.put(key1, val2).isOk() batch2.put(key1, val1).isOk() batch2.count() == 3 - batch2.get(key1).get() == val1 + batch2.getFromBatch(key1).get() == val1 test "Put, get and delete empty key": let batch = db.openWriteBatchWithIndex() @@ -221,9 +221,9 @@ suite "WriteBatchWIRef Tests": let empty: seq[byte] = @[] check: batch.put(empty, val1).isOk() - batch.get(empty).get() == val1 + batch.getFromBatch(empty).get() == val1 batch.delete(empty).isOk() - batch.get(empty).isErr() + batch.getFromBatch(empty).isErr() test "Test close": let batch = db.openWriteBatchWithIndex()