Fix segfault in filterpolicy close (#60)

* Fix seq fault caused by double free. Now using API correctly.

* Add tests to cover autoClose.
This commit is contained in:
web3-developer 2024-07-02 12:44:05 +08:00 committed by GitHub
parent caedba0b3f
commit 01ced36404
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 353 additions and 66 deletions

View File

@ -11,12 +11,13 @@
import ../lib/librocksdb, ../internal/utils, ../options/tableopts import ../lib/librocksdb, ../internal/utils, ../options/tableopts
export tableopts
type type
SlicetransformPtr* = ptr rocksdb_slicetransform_t SlicetransformPtr* = ptr rocksdb_slicetransform_t
SlicetransformRef* = ref object SlicetransformRef* = ref object
cPtr: SlicetransformPtr cPtr: SlicetransformPtr
autoClose*: bool # if true then close will be called when it's parent is closed
ColFamilyOptionsPtr* = ptr rocksdb_options_t ColFamilyOptionsPtr* = ptr rocksdb_options_t
@ -25,7 +26,6 @@ type
# type - CF options are a subset of rocksdb_options_t - when in doubt, check: # type - CF options are a subset of rocksdb_options_t - when in doubt, check:
# https://github.com/facebook/rocksdb/blob/b8c9a2576af6a1d0ffcfbb517dfcb7e7037bd460/include/rocksdb/options.h#L66 # https://github.com/facebook/rocksdb/blob/b8c9a2576af6a1d0ffcfbb517dfcb7e7037bd460/include/rocksdb/options.h#L66
cPtr: ColFamilyOptionsPtr cPtr: ColFamilyOptionsPtr
sliceTransform: SlicetransformRef
tableOpts: TableOptionsRef tableOpts: TableOptionsRef
autoClose*: bool # if true then close will be called when the database is closed autoClose*: bool # if true then close will be called when the database is closed
@ -40,11 +40,8 @@ type
xpressCompression = rocksdb_xpress_compression xpressCompression = rocksdb_xpress_compression
zstdCompression = rocksdb_zstd_compression zstdCompression = rocksdb_zstd_compression
proc createFixedPrefix*(value: int, autoClose = false): SlicetransformRef = proc createFixedPrefix*(value: int): SlicetransformRef =
SlicetransformRef( SlicetransformRef(cPtr: rocksdb_slicetransform_create_fixed_prefix(value.csize_t))
cPtr: rocksdb_slicetransform_create_fixed_prefix(value.csize_t),
autoClose: autoClose,
)
proc isClosed*(s: SlicetransformRef): bool {.inline.} = proc isClosed*(s: SlicetransformRef): bool {.inline.} =
s.cPtr.isNil() s.cPtr.isNil()
@ -58,7 +55,7 @@ proc close*(s: SlicetransformRef) =
rocksdb_slicetransform_destroy(s.cPtr) rocksdb_slicetransform_destroy(s.cPtr)
s.cPtr = nil s.cPtr = nil
proc newColFamilyOptions*(autoClose = false): ColFamilyOptionsRef = proc createColFamilyOptions*(autoClose = false): ColFamilyOptionsRef =
ColFamilyOptionsRef(cPtr: rocksdb_options_create(), autoClose: autoClose) ColFamilyOptionsRef(cPtr: rocksdb_options_create(), autoClose: autoClose)
proc isClosed*(cfOpts: ColFamilyOptionsRef): bool {.inline.} = proc isClosed*(cfOpts: ColFamilyOptionsRef): bool {.inline.} =
@ -73,7 +70,6 @@ proc close*(cfOpts: ColFamilyOptionsRef) =
rocksdb_options_destroy(cfOpts.cPtr) rocksdb_options_destroy(cfOpts.cPtr)
cfOpts.cPtr = nil cfOpts.cPtr = nil
autoCloseNonNil(cfOpts.sliceTransform)
autoCloseNonNil(cfOpts.tableOpts) autoCloseNonNil(cfOpts.tableOpts)
template opt(nname, ntyp, ctyp: untyped) = template opt(nname, ntyp, ctyp: untyped) =
@ -126,7 +122,7 @@ opt blobCompactionReadaheadSize, int, uint64
opt blobFileStartingLevel, int, cint opt blobFileStartingLevel, int, cint
proc defaultColFamilyOptions*(autoClose = false): ColFamilyOptionsRef = proc defaultColFamilyOptions*(autoClose = false): ColFamilyOptionsRef =
newColFamilyOptions(autoClose) createColFamilyOptions(autoClose)
# proc setFixedPrefixExtractor*(dbOpts: ColFamilyOptionsRef, length: int) = # proc setFixedPrefixExtractor*(dbOpts: ColFamilyOptionsRef, length: int) =
# doAssert not dbOpts.isClosed() # doAssert not dbOpts.isClosed()
@ -135,11 +131,14 @@ proc defaultColFamilyOptions*(autoClose = false): ColFamilyOptionsRef =
proc `setPrefixExtractor`*(cfOpts: ColFamilyOptionsRef, value: SlicetransformRef) = proc `setPrefixExtractor`*(cfOpts: ColFamilyOptionsRef, value: SlicetransformRef) =
doAssert not cfOpts.isClosed() doAssert not cfOpts.isClosed()
doAssert cfOpts.sliceTransform.isNil()
# don't allow overwriting an existing sliceTransform which could leak memory
# Destroys the existing slice transform if there is one attached to the column
# family options and takes ownership of the passed slice transform. After this call,
# the ColFamilyOptionsRef is responsible for cleaning up the policy when it is no
# longer needed so we set the filter policy to nil so that isClosed() will return true
# and prevent the filter policy from being double freed which was causing a seg fault.
rocksdb_options_set_prefix_extractor(cfOpts.cPtr, value.cPtr) rocksdb_options_set_prefix_extractor(cfOpts.cPtr, value.cPtr)
cfOpts.sliceTransform = value value.cPtr = nil
proc `blockBasedTableFactory=`*( proc `blockBasedTableFactory=`*(
cfOpts: ColFamilyOptionsRef, tableOpts: TableOptionsRef cfOpts: ColFamilyOptionsRef, tableOpts: TableOptionsRef

View File

@ -18,7 +18,7 @@ type
cPtr: BackupEngineOptionsPtr cPtr: BackupEngineOptionsPtr
autoClose*: bool # if true then close will be called when the backup engine is closed autoClose*: bool # if true then close will be called when the backup engine is closed
proc newBackupEngineOptions*(autoClose = false): BackupEngineOptionsRef = proc createBackupEngineOptions*(autoClose = false): BackupEngineOptionsRef =
BackupEngineOptionsRef(cPtr: rocksdb_options_create(), autoClose: autoClose) BackupEngineOptionsRef(cPtr: rocksdb_options_create(), autoClose: autoClose)
proc isClosed*(engineOpts: BackupEngineOptionsRef): bool {.inline.} = proc isClosed*(engineOpts: BackupEngineOptionsRef): bool {.inline.} =
@ -31,7 +31,7 @@ proc cPtr*(engineOpts: BackupEngineOptionsRef): BackupEngineOptionsPtr =
# TODO: Add setters and getters for backup options properties. # TODO: Add setters and getters for backup options properties.
proc defaultBackupEngineOptions*(autoClose = false): BackupEngineOptionsRef {.inline.} = proc defaultBackupEngineOptions*(autoClose = false): BackupEngineOptionsRef {.inline.} =
let opts = newBackupEngineOptions(autoClose) let opts = createBackupEngineOptions(autoClose)
# TODO: set defaults here # TODO: set defaults here

View File

@ -4,12 +4,19 @@ type
CachePtr* = ptr rocksdb_cache_t CachePtr* = ptr rocksdb_cache_t
CacheRef* = ref object CacheRef* = ref object
cPtr*: CachePtr cPtr: CachePtr
autoClose*: bool # if true then close will be called when it's parent is closed autoClose*: bool # if true then close will be called when it's parent is closed
proc cacheCreateLRU*(size: int, autoClose = false): CacheRef = proc cacheCreateLRU*(size: int, autoClose = false): CacheRef =
CacheRef(cPtr: rocksdb_cache_create_lru(size.csize_t), autoClose: autoClose) CacheRef(cPtr: rocksdb_cache_create_lru(size.csize_t), autoClose: autoClose)
proc isClosed*(cache: CacheRef): bool =
isNil(cache.cPtr)
proc cPtr*(cache: CacheRef): CachePtr =
doAssert not cache.isClosed()
cache.cPtr
proc close*(cache: CacheRef) = proc close*(cache: CacheRef) =
if cache.cPtr != nil: if cache.cPtr != nil:
rocksdb_cache_destroy(cache.cPtr) rocksdb_cache_destroy(cache.cPtr)

View File

@ -21,7 +21,7 @@ type
cache: CacheRef cache: CacheRef
autoClose*: bool # if true then close will be called when the database is closed autoClose*: bool # if true then close will be called when the database is closed
proc newDbOptions*(autoClose = false): DbOptionsRef = proc createDbOptions*(autoClose = false): DbOptionsRef =
DbOptionsRef(cPtr: rocksdb_options_create(), autoClose: autoClose) DbOptionsRef(cPtr: rocksdb_options_create(), autoClose: autoClose)
proc isClosed*(dbOpts: DbOptionsRef): bool {.inline.} = proc isClosed*(dbOpts: DbOptionsRef): bool {.inline.} =
@ -102,7 +102,7 @@ proc `rowCache=`*(dbOpts: DbOptionsRef, cache: CacheRef) =
dbOpts.cache = cache dbOpts.cache = cache
proc defaultDbOptions*(autoClose = false): DbOptionsRef = proc defaultDbOptions*(autoClose = false): DbOptionsRef =
let opts: DbOptionsRef = newDbOptions(autoClose) let opts: DbOptionsRef = createDbOptions(autoClose)
# Optimize RocksDB. This is the easiest way to get RocksDB to perform well: # Optimize RocksDB. This is the easiest way to get RocksDB to perform well:
opts.increaseParallelism(countProcessors()) opts.increaseParallelism(countProcessors())

View File

@ -18,7 +18,7 @@ type
cPtr: ReadOptionsPtr cPtr: ReadOptionsPtr
autoClose*: bool # if true then close will be called when the database is closed autoClose*: bool # if true then close will be called when the database is closed
proc newReadOptions*(autoClose = false): ReadOptionsRef = proc createReadOptions*(autoClose = false): ReadOptionsRef =
ReadOptionsRef(cPtr: rocksdb_readoptions_create(), autoClose: autoClose) ReadOptionsRef(cPtr: rocksdb_readoptions_create(), autoClose: autoClose)
proc isClosed*(readOpts: ReadOptionsRef): bool {.inline.} = proc isClosed*(readOpts: ReadOptionsRef): bool {.inline.} =
@ -31,7 +31,7 @@ proc cPtr*(readOpts: ReadOptionsRef): ReadOptionsPtr =
# TODO: Add setters and getters for read options properties. # TODO: Add setters and getters for read options properties.
proc defaultReadOptions*(autoClose = false): ReadOptionsRef {.inline.} = proc defaultReadOptions*(autoClose = false): ReadOptionsRef {.inline.} =
newReadOptions(autoClose) createReadOptions(autoClose)
# TODO: set prefered defaults # TODO: set prefered defaults
proc close*(readOpts: ReadOptionsRef) = proc close*(readOpts: ReadOptionsRef) =

View File

@ -1,20 +1,20 @@
import ../lib/librocksdb, ../internal/utils, ./cache import ../lib/librocksdb, ../internal/utils, ./cache
export cache
type type
# TODO might eventually wrap this # TODO might eventually wrap this
TableOptionsPtr* = ptr rocksdb_block_based_table_options_t TableOptionsPtr* = ptr rocksdb_block_based_table_options_t
TableOptionsRef* = ref object TableOptionsRef* = ref object
cPtr*: TableOptionsPtr cPtr: TableOptionsPtr
cache: CacheRef cache: CacheRef
filterPolicy: FilterPolicyRef
autoClose*: bool # if true then close will be called when it's parent is closed autoClose*: bool # if true then close will be called when it's parent is closed
FilterPolicyPtr* = ptr rocksdb_filterpolicy_t FilterPolicyPtr* = ptr rocksdb_filterpolicy_t
FilterPolicyRef* = ref object FilterPolicyRef* = ref object
cPtr*: FilterPolicyPtr cPtr: FilterPolicyPtr
autoClose*: bool # if true then close will be called when it's parent is closed
IndexType* {.pure.} = enum IndexType* {.pure.} = enum
binarySearch = rocksdb_block_based_table_index_type_binary_search binarySearch = rocksdb_block_based_table_index_type_binary_search
@ -27,21 +27,22 @@ type
rocksdb_block_based_table_data_block_index_type_binary_search_and_hash rocksdb_block_based_table_data_block_index_type_binary_search_and_hash
proc createRibbon*(bitsPerKey: float, autoClose = false): FilterPolicyRef = proc createRibbon*(bitsPerKey: float, autoClose = false): FilterPolicyRef =
FilterPolicyRef( FilterPolicyRef(cPtr: rocksdb_filterpolicy_create_ribbon(bitsPerKey))
cPtr: rocksdb_filterpolicy_create_ribbon(bitsPerKey), autoClose: autoClose
)
proc createRibbonHybrid*( proc createRibbonHybrid*(
bitsPerKey: float, bloomBeforeLevel: int = 0, autoClose = false bitsPerKey: float, bloomBeforeLevel: int = 0, autoClose = false
): FilterPolicyRef = ): FilterPolicyRef =
FilterPolicyRef( FilterPolicyRef(
cPtr: rocksdb_filterpolicy_create_ribbon_hybrid(bitsPerKey, bloomBeforeLevel.cint), cPtr: rocksdb_filterpolicy_create_ribbon_hybrid(bitsPerKey, bloomBeforeLevel.cint)
autoClose: autoClose,
) )
proc isClosed*(policy: FilterPolicyRef): bool = proc isClosed*(policy: FilterPolicyRef): bool =
isNil(policy.cPtr) isNil(policy.cPtr)
proc cPtr*(policy: FilterPolicyRef): FilterPolicyPtr =
doAssert not policy.isClosed()
policy.cPtr
proc close*(policy: FilterPolicyRef) = proc close*(policy: FilterPolicyRef) =
if not isClosed(policy): if not isClosed(policy):
rocksdb_filterpolicy_destroy(policy.cPtr) rocksdb_filterpolicy_destroy(policy.cPtr)
@ -53,13 +54,9 @@ proc createTableOptions*(autoClose = false): TableOptionsRef =
proc isClosed*(opts: TableOptionsRef): bool = proc isClosed*(opts: TableOptionsRef): bool =
isNil(opts.cPtr) isNil(opts.cPtr)
proc close*(opts: TableOptionsRef) = proc cPtr*(opts: TableOptionsRef): TableOptionsPtr =
if not isClosed(opts): doAssert not opts.isClosed()
rocksdb_block_based_options_destroy(opts.cPtr) opts.cPtr
opts.cPtr = nil
autoCloseNonNil(opts.cache)
autoCloseNonNil(opts.filterPolicy)
template opt(nname, ntyp, ctyp: untyped) = template opt(nname, ntyp, ctyp: untyped) =
proc `nname=`*(opts: TableOptionsRef, value: ntyp) = proc `nname=`*(opts: TableOptionsRef, value: ntyp) =
@ -95,11 +92,15 @@ proc `blockCache=`*(opts: TableOptionsRef, cache: CacheRef) =
proc `filterPolicy=`*(opts: TableOptionsRef, policy: FilterPolicyRef) = proc `filterPolicy=`*(opts: TableOptionsRef, policy: FilterPolicyRef) =
doAssert not opts.isClosed() doAssert not opts.isClosed()
doAssert opts.filterPolicy.isNil()
# don't allow overwriting an existing policy which could leak memory
# Destroys the existing policy if there is one attached to the table options
# and takes ownership of the passed in policy. After this call, the TableOptionsRef
# is responsible for cleaning up the policy when it is no longer needed
# so we set the filter policy to nil so that isClosed() will return true
# and prevent the filter policy from being double freed which was causing a seg fault.
# See here: https://github.com/facebook/rocksdb/blob/22fe23edc89e9842ed72b613de172cd80d3b00da/include/rocksdb/filter_policy.h#L152
rocksdb_block_based_options_set_filter_policy(opts.cPtr, policy.cPtr) rocksdb_block_based_options_set_filter_policy(opts.cPtr, policy.cPtr)
opts.filterPolicy = policy policy.cPtr = nil
proc defaultTableOptions*(autoClose = false): TableOptionsRef = proc defaultTableOptions*(autoClose = false): TableOptionsRef =
# https://github.com/facebook/rocksdb/wiki/Setup-Options-and-Basic-Tuning#other-general-options # https://github.com/facebook/rocksdb/wiki/Setup-Options-and-Basic-Tuning#other-general-options
@ -109,3 +110,10 @@ proc defaultTableOptions*(autoClose = false): TableOptionsRef =
opts.pinL0FilterAndIndexBlocksInCache = true opts.pinL0FilterAndIndexBlocksInCache = true
opts opts
proc close*(opts: TableOptionsRef) =
if not isClosed(opts):
rocksdb_block_based_options_destroy(opts.cPtr)
opts.cPtr = nil
autoCloseNonNil(opts.cache)

View File

@ -18,7 +18,7 @@ type
cPtr: WriteOptionsPtr cPtr: WriteOptionsPtr
autoClose*: bool # if true then close will be called when the database is closed autoClose*: bool # if true then close will be called when the database is closed
proc newWriteOptions*(autoClose = false): WriteOptionsRef = proc createWriteOptions*(autoClose = false): WriteOptionsRef =
WriteOptionsRef(cPtr: rocksdb_writeoptions_create(), autoClose: autoClose) WriteOptionsRef(cPtr: rocksdb_writeoptions_create(), autoClose: autoClose)
proc isClosed*(writeOpts: WriteOptionsRef): bool {.inline.} = proc isClosed*(writeOpts: WriteOptionsRef): bool {.inline.} =
@ -31,7 +31,7 @@ proc cPtr*(writeOpts: WriteOptionsRef): WriteOptionsPtr =
# TODO: Add setters and getters for write options properties. # TODO: Add setters and getters for write options properties.
proc defaultWriteOptions*(autoClose = false): WriteOptionsRef {.inline.} = proc defaultWriteOptions*(autoClose = false): WriteOptionsRef {.inline.} =
newWriteOptions(autoClose) createWriteOptions(autoClose)
# TODO: set prefered defaults # TODO: set prefered defaults
proc close*(writeOpts: WriteOptionsRef) = proc close*(writeOpts: WriteOptionsRef) =

View File

@ -363,7 +363,7 @@ proc openWriteBatch*(
## Opens a `WriteBatchRef` which defaults to using the specified column family. ## Opens a `WriteBatchRef` which defaults to using the specified column family.
doAssert not db.isClosed() doAssert not db.isClosed()
newWriteBatch(cfHandle) createWriteBatch(cfHandle)
proc write*(db: RocksDbReadWriteRef, updates: WriteBatchRef): RocksDBResult[void] = proc write*(db: RocksDbReadWriteRef, updates: WriteBatchRef): RocksDBResult[void] =
## Apply the updates in the `WriteBatchRef` to the database. ## Apply the updates in the `WriteBatchRef` to the database.
@ -417,10 +417,7 @@ proc close*(db: RocksDbRef) =
# opts should be closed after the database is closed # opts should be closed after the database is closed
autoCloseNonNil(db.dbOpts) autoCloseNonNil(db.dbOpts)
autoCloseNonNil(db.readOpts) autoCloseNonNil(db.readOpts)
autoCloseAll(db.cfDescriptors)
for cfDesc in db.cfDescriptors:
if cfDesc.autoClose:
cfDesc.close()
if db of RocksDbReadWriteRef: if db of RocksDbReadWriteRef:
let db = RocksDbReadWriteRef(db) let db = RocksDbReadWriteRef(db)

View File

@ -18,7 +18,7 @@ type
cPtr: TransactionDbOptionsPtr cPtr: TransactionDbOptionsPtr
autoClose*: bool # if true then close will be called when the database is closed autoClose*: bool # if true then close will be called when the database is closed
proc newTransactionDbOptions*(autoClose = false): TransactionDbOptionsRef = proc createTransactionDbOptions*(autoClose = false): TransactionDbOptionsRef =
TransactionDbOptionsRef( TransactionDbOptionsRef(
cPtr: rocksdb_transactiondb_options_create(), autoClose: autoClose cPtr: rocksdb_transactiondb_options_create(), autoClose: autoClose
) )
@ -35,7 +35,7 @@ proc cPtr*(txDbOpts: TransactionDbOptionsRef): TransactionDbOptionsPtr =
proc defaultTransactionDbOptions*( proc defaultTransactionDbOptions*(
autoClose = false autoClose = false
): TransactionDbOptionsRef {.inline.} = ): TransactionDbOptionsRef {.inline.} =
newTransactionDbOptions(autoClose) createTransactionDbOptions(autoClose)
# TODO: set prefered defaults # TODO: set prefered defaults
proc close*(txDbOpts: TransactionDbOptionsRef) = proc close*(txDbOpts: TransactionDbOptionsRef) =

View File

@ -18,7 +18,7 @@ type
cPtr: TransactionOptionsPtr cPtr: TransactionOptionsPtr
autoClose*: bool # if true then close will be called when the transaction is closed autoClose*: bool # if true then close will be called when the transaction is closed
proc newTransactionOptions*(autoClose = false): TransactionOptionsRef = proc createTransactionOptions*(autoClose = false): TransactionOptionsRef =
TransactionOptionsRef( TransactionOptionsRef(
cPtr: rocksdb_transaction_options_create(), autoClose: autoClose cPtr: rocksdb_transaction_options_create(), autoClose: autoClose
) )
@ -33,7 +33,7 @@ proc cPtr*(txOpts: TransactionOptionsRef): TransactionOptionsPtr =
# TODO: Add setters and getters for backup options properties. # TODO: Add setters and getters for backup options properties.
proc defaultTransactionOptions*(autoClose = false): TransactionOptionsRef {.inline.} = proc defaultTransactionOptions*(autoClose = false): TransactionOptionsRef {.inline.} =
newTransactionOptions(autoClose) createTransactionOptions(autoClose)
# TODO: set prefered defaults # TODO: set prefered defaults
proc close*(txOpts: TransactionOptionsRef) = proc close*(txOpts: TransactionOptionsRef) =

View File

@ -22,7 +22,7 @@ type
cPtr: WriteBatchPtr cPtr: WriteBatchPtr
defaultCfHandle: ColFamilyHandleRef defaultCfHandle: ColFamilyHandleRef
proc newWriteBatch*(defaultCfHandle: ColFamilyHandleRef): WriteBatchRef = proc createWriteBatch*(defaultCfHandle: ColFamilyHandleRef): WriteBatchRef =
WriteBatchRef(cPtr: rocksdb_writebatch_create(), defaultCfHandle: defaultCfHandle) WriteBatchRef(cPtr: rocksdb_writebatch_create(), defaultCfHandle: defaultCfHandle)
proc isClosed*(batch: WriteBatchRef): bool {.inline.} = proc isClosed*(batch: WriteBatchRef): bool {.inline.} =

View File

@ -44,7 +44,7 @@ suite "ColFamilyHandleRef Tests":
removeDir($dbPath) removeDir($dbPath)
test "Test newColFamilyHandle": test "Test newColFamilyHandle":
var cfHandle = newColFamilyHandle(cfHandlePtr) let cfHandle = newColFamilyHandle(cfHandlePtr)
check: check:
not cfHandle.cPtr.isNil() not cfHandle.cPtr.isNil()
@ -53,7 +53,7 @@ suite "ColFamilyHandleRef Tests":
cfHandle.close() cfHandle.close()
test "Test close": test "Test close":
var cfHandle = newColFamilyHandle(cfHandlePtr) let cfHandle = newColFamilyHandle(cfHandlePtr)
check not cfHandle.isClosed() check not cfHandle.isClosed()
cfHandle.close() cfHandle.close()

View File

@ -20,3 +20,45 @@ suite "ColFamilyOptionsRef Tests":
check cfOpts.isClosed() check cfOpts.isClosed()
cfOpts.close() cfOpts.close()
check cfOpts.isClosed() check cfOpts.isClosed()
test "Test auto close enabled":
let
cfOpts = defaultColFamilyOptions()
tableOpts = defaultTableOptions(autoClose = true)
sliceTransform = createFixedPrefix(1000)
cfOpts.blockBasedTableFactory = tableOpts
cfOpts.setPrefixExtractor(sliceTransform)
check:
cfOpts.isClosed() == false
tableOpts.isClosed() == false
sliceTransform.isClosed() == true # closed because tableopts takes ownership
cfOpts.close()
check:
cfOpts.isClosed() == true
tableOpts.isClosed() == true
sliceTransform.isClosed() == true
test "Test auto close disabled":
let
cfOpts = defaultColFamilyOptions()
tableOpts = defaultTableOptions(autoClose = false)
sliceTransform = createFixedPrefix(1000)
cfOpts.blockBasedTableFactory = tableOpts
cfOpts.setPrefixExtractor(sliceTransform)
check:
cfOpts.isClosed() == false
tableOpts.isClosed() == false
sliceTransform.isClosed() == true # closed because tableopts takes ownership
cfOpts.close()
check:
cfOpts.isClosed() == true
tableOpts.isClosed() == false
sliceTransform.isClosed() == true

View File

@ -13,7 +13,7 @@ import unittest2, ../../rocksdb/options/backupopts
suite "BackupEngineOptionsRef Tests": suite "BackupEngineOptionsRef Tests":
test "Test newBackupEngineOptions": test "Test newBackupEngineOptions":
var backupOpts = newBackupEngineOptions() var backupOpts = createBackupEngineOptions()
check not backupOpts.cPtr.isNil() check not backupOpts.cPtr.isNil()

View File

@ -13,7 +13,7 @@ import unittest2, ../../rocksdb/options/dbopts
suite "DbOptionsRef Tests": suite "DbOptionsRef Tests":
test "Test newDbOptions": test "Test newDbOptions":
var dbOpts = newDbOptions() let dbOpts = createDbOptions()
check not dbOpts.cPtr.isNil() check not dbOpts.cPtr.isNil()
@ -28,10 +28,28 @@ suite "DbOptionsRef Tests":
dbOpts.close() dbOpts.close()
test "Test close": test "Test close":
var dbOpts = defaultDbOptions() let dbOpts = defaultDbOptions()
check not dbOpts.isClosed() check not dbOpts.isClosed()
dbOpts.close() dbOpts.close()
check dbOpts.isClosed() check dbOpts.isClosed()
dbOpts.close() dbOpts.close()
check dbOpts.isClosed() check dbOpts.isClosed()
# This is currently failing in MacOS CI due to older version of RocksDb
# test "Test auto close enabled":
# let
# dbOpts = defaultDbOptions()
# cache = cacheCreateLRU(1000, autoClose = true)
# dbOpts.rowCache = cache
# check:
# dbOpts.isClosed() == false
# cache.isClosed() == false
# dbOpts.close()
# check:
# dbOpts.isClosed() == true
# cache.isClosed() == true

View File

@ -13,7 +13,7 @@ import unittest2, ../../rocksdb/options/readopts
suite "ReadOptionsRef Tests": suite "ReadOptionsRef Tests":
test "Test newReadOptions": test "Test newReadOptions":
var readOpts = newReadOptions() var readOpts = createReadOptions()
check not readOpts.cPtr.isNil() check not readOpts.cPtr.isNil()

View File

@ -0,0 +1,80 @@
# 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.
{.used.}
import unittest2, ../../rocksdb/options/tableopts
suite "TableOptionsRef Tests":
test "Test createTableOptions":
let tableOpts = createTableOptions()
check not tableOpts.cPtr.isNil()
tableOpts.close()
test "Test defaultTableOptions":
let tableOpts = defaultTableOptions()
check not tableOpts.cPtr.isNil()
tableOpts.close()
test "Test close":
let tableOpts = defaultTableOptions()
check not tableOpts.isClosed()
tableOpts.close()
check tableOpts.isClosed()
tableOpts.close()
check tableOpts.isClosed()
test "Test auto close enabled":
# TODO: enable filter policy once creating updated DLL build
let
tableOpts = defaultTableOptions()
cache = cacheCreateLRU(1000, autoClose = true)
# filter = createRibbon(9.9, autoClose = true)
tableOpts.blockCache = cache
# tableOpts.filterPolicy = filter
check:
tableOpts.isClosed() == false
cache.isClosed() == false
# filter.isClosed() == true # closed because tableopts takes ownership
tableOpts.close()
check:
tableOpts.isClosed() == true
cache.isClosed() == true
# filter.isClosed() == true
test "Test auto close disabled":
# TODO: enable filter policy once creating updated DLL build
let
tableOpts = defaultTableOptions()
cache = cacheCreateLRU(1000, autoClose = false)
# filter = createRibbon(9.9, autoClose = true)
tableOpts.blockCache = cache
# tableOpts.filterPolicy = filter
check:
tableOpts.isClosed() == false
cache.isClosed() == false
# filter.isClosed() == true # closed because tableopts takes ownership
tableOpts.close()
check:
tableOpts.isClosed() == true
cache.isClosed() == false
# filter.isClosed() == true

View File

@ -13,7 +13,7 @@ import unittest2, ../../rocksdb/options/writeopts
suite "WriteOptionsRef Tests": suite "WriteOptionsRef Tests":
test "Test newWriteOptions": test "Test newWriteOptions":
var writeOpts = newWriteOptions() var writeOpts = createWriteOptions()
check not writeOpts.cPtr.isNil() check not writeOpts.cPtr.isNil()

View File

@ -17,6 +17,7 @@ import
./options/test_dbopts, ./options/test_dbopts,
./options/test_readopts, ./options/test_readopts,
./options/test_writeopts, ./options/test_writeopts,
./options/test_tableopts,
./transactions/test_txdbopts, ./transactions/test_txdbopts,
./transactions/test_txopts, ./transactions/test_txopts,
./test_backup, ./test_backup,

View File

@ -59,3 +59,33 @@ suite "BackupEngineRef Tests":
check engine.isClosed() check engine.isClosed()
engine.close() engine.close()
check engine.isClosed() check engine.isClosed()
test "Test auto close enabled":
let
backupOpts = defaultBackupEngineOptions(autoClose = true)
backupEngine = openBackupEngine(dbPath, backupOpts).get()
check:
backupOpts.isClosed() == false
backupEngine.isClosed() == false
backupEngine.close()
check:
backupOpts.isClosed() == true
backupEngine.isClosed() == true
test "Test auto close disabled":
let
backupOpts = defaultBackupEngineOptions(autoClose = false)
backupEngine = openBackupEngine(dbPath, backupOpts).get()
check:
backupOpts.isClosed() == false
backupEngine.isClosed() == false
backupEngine.close()
check:
backupOpts.isClosed() == false
backupEngine.isClosed() == true

View File

@ -380,7 +380,7 @@ suite "RocksDbRef Tests":
test "Test auto close disabled": test "Test auto close disabled":
let let
dbPath = mkdtemp() / "autoclose-enabled" dbPath = mkdtemp() / "autoclose-disabled"
dbOpts = defaultDbOptions(autoClose = false) dbOpts = defaultDbOptions(autoClose = false)
readOpts = defaultReadOptions(autoClose = false) readOpts = defaultReadOptions(autoClose = false)
writeOpts = defaultWriteOptions(autoClose = false) writeOpts = defaultWriteOptions(autoClose = false)

View File

@ -86,3 +86,33 @@ suite "SstFileWriterRef Tests":
check writer.isClosed() check writer.isClosed()
writer.close() writer.close()
check writer.isClosed() check writer.isClosed()
test "Test auto close enabled":
let
dbOpts = defaultDbOptions(autoClose = true)
writer = openSstFileWriter(sstFilePath, dbOpts).get()
check:
dbOpts.isClosed() == false
writer.isClosed() == false
writer.close()
check:
dbOpts.isClosed() == true
writer.isClosed() == true
test "Test auto close disabled":
let
dbOpts = defaultDbOptions(autoClose = false)
writer = openSstFileWriter(sstFilePath, dbOpts).get()
check:
dbOpts.isClosed() == false
writer.isClosed() == false
writer.close()
check:
dbOpts.isClosed() == false
writer.isClosed() == true

View File

@ -202,21 +202,96 @@ suite "TransactionDbRef Tests":
tx2.close() tx2.close()
check tx2.isClosed() check tx2.isClosed()
test "Test auto close": test "Test auto close enabled":
let let
dbPath = mkdtemp() / "autoclose" dbPath = mkdtemp() / "autoclose-enabled"
dbOpts = defaultDbOptions(autoClose = false) dbOpts = defaultDbOptions(autoClose = true)
txDbOpts = defaultTransactionDbOptions(autoClose = true) txDbOpts = defaultTransactionDbOptions(autoClose = true)
db = openTransactionDb(dbPath, dbOpts, txDbOpts).get() columnFamilies =
@[
initColFamilyDescriptor(CF_DEFAULT, defaultColFamilyOptions(autoClose = true))
]
db = openTransactionDb(dbPath, dbOpts, txDbOpts, columnFamilies).get()
check: check:
dbOpts.isClosed() == false dbOpts.isClosed() == false
txDbOpts.isClosed() == false txDbOpts.isClosed() == false
columnFamilies[0].isClosed() == false
db.isClosed() == false
db.close()
check:
dbOpts.isClosed() == true
txDbOpts.isClosed() == true
columnFamilies[0].isClosed() == true
db.isClosed() == true
test "Test auto close enabled":
let
dbPath = mkdtemp() / "autoclose-disabled"
dbOpts = defaultDbOptions(autoClose = false)
txDbOpts = defaultTransactionDbOptions(autoClose = false)
columnFamilies =
@[
initColFamilyDescriptor(
CF_DEFAULT, defaultColFamilyOptions(autoClose = false)
)
]
db = openTransactionDb(dbPath, dbOpts, txDbOpts, columnFamilies).get()
check:
dbOpts.isClosed() == false
txDbOpts.isClosed() == false
columnFamilies[0].isClosed() == false
db.isClosed() == false db.isClosed() == false
db.close() db.close()
check: check:
dbOpts.isClosed() == false dbOpts.isClosed() == false
txDbOpts.isClosed() == true txDbOpts.isClosed() == false
columnFamilies[0].isClosed() == false
db.isClosed() == true db.isClosed() == true
test "Test auto close tx enabled":
let
readOpts = defaultReadOptions(autoClose = true)
writeOpts = defaultWriteOptions(autoClose = true)
txOpts = defaultTransactionOptions(autoClose = true)
tx = db.beginTransaction(readOpts, writeOpts, txOpts)
check:
readOpts.isClosed() == false
writeOpts.isClosed() == false
txOpts.isClosed() == false
tx.isClosed() == false
tx.close()
check:
readOpts.isClosed() == true
writeOpts.isClosed() == true
txOpts.isClosed() == true
tx.isClosed() == true
test "Test auto close tx disabled":
let
readOpts = defaultReadOptions(autoClose = false)
writeOpts = defaultWriteOptions(autoClose = false)
txOpts = defaultTransactionOptions(autoClose = false)
tx = db.beginTransaction(readOpts, writeOpts, txOpts)
check:
readOpts.isClosed() == false
writeOpts.isClosed() == false
txOpts.isClosed() == false
tx.isClosed() == false
tx.close()
check:
readOpts.isClosed() == false
writeOpts.isClosed() == false
txOpts.isClosed() == false
tx.isClosed() == true

View File

@ -13,7 +13,7 @@ import unittest2, ../../rocksdb/transactions/txdbopts
suite "TransactionDbOptionsRef Tests": suite "TransactionDbOptionsRef Tests":
test "Test newTransactionDbOptions": test "Test newTransactionDbOptions":
var txDbOpts = newTransactionDbOptions() var txDbOpts = createTransactionDbOptions()
check not txDbOpts.cPtr.isNil() check not txDbOpts.cPtr.isNil()

View File

@ -13,7 +13,7 @@ import unittest2, ../../rocksdb/transactions/txopts
suite "TransactionOptionsRef Tests": suite "TransactionOptionsRef Tests":
test "Test newTransactionOptions": test "Test newTransactionOptions":
var txOpts = newTransactionOptions() var txOpts = createTransactionOptions()
check not txOpts.cPtr.isNil() check not txOpts.cPtr.isNil()