use crate::error::{check_result, Result};
use crate::ffi;
use std::ffi::CString;
use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(i32)]
pub enum CompressionAlgorithm {
#[default]
None = ffi::NO_COMPRESSION,
Snappy = ffi::SNAPPY_COMPRESSION,
Lz4 = ffi::LZ4_COMPRESSION,
Zstd = ffi::ZSTD_COMPRESSION,
Lz4Fast = ffi::LZ4_FAST_COMPRESSION,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(i32)]
pub enum SyncMode {
#[default]
None = ffi::TDB_SYNC_NONE,
Full = ffi::TDB_SYNC_FULL,
Interval = ffi::TDB_SYNC_INTERVAL,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(i32)]
pub enum LogLevel {
Debug = ffi::TDB_LOG_DEBUG,
#[default]
Info = ffi::TDB_LOG_INFO,
Warn = ffi::TDB_LOG_WARN,
Error = ffi::TDB_LOG_ERROR,
Fatal = ffi::TDB_LOG_FATAL,
None = ffi::TDB_LOG_NONE,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(i32)]
pub enum IsolationLevel {
ReadUncommitted = ffi::TDB_ISOLATION_READ_UNCOMMITTED,
#[default]
ReadCommitted = ffi::TDB_ISOLATION_READ_COMMITTED,
RepeatableRead = ffi::TDB_ISOLATION_REPEATABLE_READ,
Snapshot = ffi::TDB_ISOLATION_SNAPSHOT,
Serializable = ffi::TDB_ISOLATION_SERIALIZABLE,
}
#[derive(Debug, Clone)]
pub struct ObjectStoreConfig {
pub local_cache_path: Option<String>,
pub local_cache_max_bytes: usize,
pub cache_on_read: bool,
pub cache_on_write: bool,
pub max_concurrent_uploads: i32,
pub max_concurrent_downloads: i32,
pub multipart_threshold: usize,
pub multipart_part_size: usize,
pub sync_manifest_to_object: bool,
pub replicate_wal: bool,
pub wal_upload_sync: bool,
pub wal_sync_threshold_bytes: usize,
pub wal_sync_on_commit: bool,
pub replica_mode: bool,
pub replica_sync_interval_us: u64,
pub replica_replay_wal: bool,
}
impl ObjectStoreConfig {
pub fn new() -> Self {
Self::default()
}
pub fn local_cache_path(mut self, path: &str) -> Self {
self.local_cache_path = Some(path.to_string());
self
}
pub fn local_cache_max_bytes(mut self, size: usize) -> Self {
self.local_cache_max_bytes = size;
self
}
pub fn cache_on_read(mut self, enable: bool) -> Self {
self.cache_on_read = enable;
self
}
pub fn cache_on_write(mut self, enable: bool) -> Self {
self.cache_on_write = enable;
self
}
pub fn max_concurrent_uploads(mut self, n: i32) -> Self {
self.max_concurrent_uploads = n;
self
}
pub fn max_concurrent_downloads(mut self, n: i32) -> Self {
self.max_concurrent_downloads = n;
self
}
pub fn multipart_threshold(mut self, size: usize) -> Self {
self.multipart_threshold = size;
self
}
pub fn multipart_part_size(mut self, size: usize) -> Self {
self.multipart_part_size = size;
self
}
pub fn sync_manifest_to_object(mut self, enable: bool) -> Self {
self.sync_manifest_to_object = enable;
self
}
pub fn replicate_wal(mut self, enable: bool) -> Self {
self.replicate_wal = enable;
self
}
pub fn wal_upload_sync(mut self, enable: bool) -> Self {
self.wal_upload_sync = enable;
self
}
pub fn wal_sync_threshold_bytes(mut self, size: usize) -> Self {
self.wal_sync_threshold_bytes = size;
self
}
pub fn wal_sync_on_commit(mut self, enable: bool) -> Self {
self.wal_sync_on_commit = enable;
self
}
pub fn replica_mode(mut self, enable: bool) -> Self {
self.replica_mode = enable;
self
}
pub fn replica_sync_interval_us(mut self, interval: u64) -> Self {
self.replica_sync_interval_us = interval;
self
}
pub fn replica_replay_wal(mut self, enable: bool) -> Self {
self.replica_replay_wal = enable;
self
}
pub(crate) fn to_c_config(&self) -> (ffi::tidesdb_objstore_config_t, Option<CString>) {
let (cache_path_ptr, cache_path_cstr) = match &self.local_cache_path {
Some(p) => {
let cs = CString::new(p.as_str()).unwrap_or_default();
let ptr = cs.as_ptr();
(ptr, Some(cs))
}
None => (std::ptr::null(), None),
};
let config = ffi::tidesdb_objstore_config_t {
local_cache_path: cache_path_ptr,
local_cache_max_bytes: self.local_cache_max_bytes,
cache_on_read: if self.cache_on_read { 1 } else { 0 },
cache_on_write: if self.cache_on_write { 1 } else { 0 },
max_concurrent_uploads: self.max_concurrent_uploads,
max_concurrent_downloads: self.max_concurrent_downloads,
multipart_threshold: self.multipart_threshold,
multipart_part_size: self.multipart_part_size,
sync_manifest_to_object: if self.sync_manifest_to_object { 1 } else { 0 },
replicate_wal: if self.replicate_wal { 1 } else { 0 },
wal_upload_sync: if self.wal_upload_sync { 1 } else { 0 },
wal_sync_threshold_bytes: self.wal_sync_threshold_bytes,
wal_sync_on_commit: if self.wal_sync_on_commit { 1 } else { 0 },
replica_mode: if self.replica_mode { 1 } else { 0 },
replica_sync_interval_us: self.replica_sync_interval_us,
replica_replay_wal: if self.replica_replay_wal { 1 } else { 0 },
};
(config, cache_path_cstr)
}
}
impl Default for ObjectStoreConfig {
fn default() -> Self {
let c = unsafe { ffi::tidesdb_objstore_default_config() };
ObjectStoreConfig {
local_cache_path: None,
local_cache_max_bytes: c.local_cache_max_bytes,
cache_on_read: c.cache_on_read != 0,
cache_on_write: c.cache_on_write != 0,
max_concurrent_uploads: c.max_concurrent_uploads,
max_concurrent_downloads: c.max_concurrent_downloads,
multipart_threshold: c.multipart_threshold,
multipart_part_size: c.multipart_part_size,
sync_manifest_to_object: c.sync_manifest_to_object != 0,
replicate_wal: c.replicate_wal != 0,
wal_upload_sync: c.wal_upload_sync != 0,
wal_sync_threshold_bytes: c.wal_sync_threshold_bytes,
wal_sync_on_commit: c.wal_sync_on_commit != 0,
replica_mode: c.replica_mode != 0,
replica_sync_interval_us: c.replica_sync_interval_us,
replica_replay_wal: c.replica_replay_wal != 0,
}
}
}
pub(crate) struct CConfigData {
pub config: ffi::tidesdb_config_t,
_db_path: CString,
_objstore_config: Option<Box<ffi::tidesdb_objstore_config_t>>,
_cache_path: Option<CString>,
}
#[derive(Debug, Clone)]
pub struct Config {
pub db_path: String,
pub num_flush_threads: i32,
pub num_compaction_threads: i32,
pub log_level: LogLevel,
pub block_cache_size: usize,
pub max_open_sstables: usize,
pub max_memory_usage: usize,
pub log_to_file: bool,
pub log_truncation_at: usize,
pub unified_memtable: bool,
pub unified_memtable_write_buffer_size: usize,
pub unified_memtable_skip_list_max_level: i32,
pub unified_memtable_skip_list_probability: f32,
pub unified_memtable_sync_mode: SyncMode,
pub unified_memtable_sync_interval_us: u64,
pub object_store_fs_path: Option<String>,
pub object_store_config: Option<ObjectStoreConfig>,
}
impl Config {
pub fn new<P: AsRef<Path>>(db_path: P) -> Self {
Config {
db_path: db_path.as_ref().to_string_lossy().into_owned(),
num_flush_threads: 2,
num_compaction_threads: 2,
log_level: LogLevel::Info,
block_cache_size: 64 * 1024 * 1024, max_open_sstables: 256,
max_memory_usage: 0, log_to_file: false,
log_truncation_at: 24 * 1024 * 1024, unified_memtable: false,
unified_memtable_write_buffer_size: 0,
unified_memtable_skip_list_max_level: 0,
unified_memtable_skip_list_probability: 0.0,
unified_memtable_sync_mode: SyncMode::None,
unified_memtable_sync_interval_us: 0,
object_store_fs_path: None,
object_store_config: None,
}
}
pub fn num_flush_threads(mut self, n: i32) -> Self {
self.num_flush_threads = n;
self
}
pub fn num_compaction_threads(mut self, n: i32) -> Self {
self.num_compaction_threads = n;
self
}
pub fn log_level(mut self, level: LogLevel) -> Self {
self.log_level = level;
self
}
pub fn block_cache_size(mut self, size: usize) -> Self {
self.block_cache_size = size;
self
}
pub fn max_open_sstables(mut self, n: usize) -> Self {
self.max_open_sstables = n;
self
}
pub fn max_memory_usage(mut self, size: usize) -> Self {
self.max_memory_usage = size;
self
}
pub fn log_to_file(mut self, enable: bool) -> Self {
self.log_to_file = enable;
self
}
pub fn log_truncation_at(mut self, size: usize) -> Self {
self.log_truncation_at = size;
self
}
pub fn unified_memtable(mut self, enable: bool) -> Self {
self.unified_memtable = enable;
self
}
pub fn unified_memtable_write_buffer_size(mut self, size: usize) -> Self {
self.unified_memtable_write_buffer_size = size;
self
}
pub fn unified_memtable_skip_list_max_level(mut self, level: i32) -> Self {
self.unified_memtable_skip_list_max_level = level;
self
}
pub fn unified_memtable_skip_list_probability(mut self, prob: f32) -> Self {
self.unified_memtable_skip_list_probability = prob;
self
}
pub fn unified_memtable_sync_mode(mut self, mode: SyncMode) -> Self {
self.unified_memtable_sync_mode = mode;
self
}
pub fn unified_memtable_sync_interval_us(mut self, interval: u64) -> Self {
self.unified_memtable_sync_interval_us = interval;
self
}
pub fn object_store_fs(mut self, root_dir: &str) -> Self {
self.object_store_fs_path = Some(root_dir.to_string());
self
}
pub fn object_store_config(mut self, config: ObjectStoreConfig) -> Self {
self.object_store_config = Some(config);
self
}
pub(crate) fn to_c_config(&self) -> crate::error::Result<CConfigData> {
let c_path = CString::new(self.db_path.as_str())?;
let objstore_ptr = match &self.object_store_fs_path {
Some(root_dir) => {
let c_root = CString::new(root_dir.as_str())?;
let ptr = unsafe { ffi::tidesdb_objstore_fs_create(c_root.as_ptr()) };
if ptr.is_null() {
return Err(crate::error::Error::NullPointer("object store connector"));
}
ptr
}
None => std::ptr::null_mut(),
};
let (boxed_os_config, cache_path_cstr) = if !objstore_ptr.is_null() {
let os_cfg = self
.object_store_config
.as_ref()
.cloned()
.unwrap_or_default();
let (c_os_config, cache_cstr) = os_cfg.to_c_config();
(Some(Box::new(c_os_config)), cache_cstr)
} else {
(None, None)
};
let os_config_ptr = match &boxed_os_config {
Some(b) => &**b as *const ffi::tidesdb_objstore_config_t as *mut _,
None => std::ptr::null_mut(),
};
let config = ffi::tidesdb_config_t {
db_path: c_path.as_ptr(),
num_flush_threads: self.num_flush_threads,
num_compaction_threads: self.num_compaction_threads,
log_level: self.log_level as i32,
block_cache_size: self.block_cache_size,
max_open_sstables: self.max_open_sstables,
log_to_file: if self.log_to_file { 1 } else { 0 },
log_truncation_at: self.log_truncation_at,
max_memory_usage: self.max_memory_usage,
unified_memtable: if self.unified_memtable { 1 } else { 0 },
unified_memtable_write_buffer_size: self.unified_memtable_write_buffer_size,
unified_memtable_skip_list_max_level: self.unified_memtable_skip_list_max_level,
unified_memtable_skip_list_probability: self.unified_memtable_skip_list_probability,
unified_memtable_sync_mode: self.unified_memtable_sync_mode as i32,
unified_memtable_sync_interval_us: self.unified_memtable_sync_interval_us,
object_store: objstore_ptr,
object_store_config: os_config_ptr,
};
Ok(CConfigData {
config,
_db_path: c_path,
_objstore_config: boxed_os_config,
_cache_path: cache_path_cstr,
})
}
}
impl Default for Config {
fn default() -> Self {
Config {
db_path: String::new(),
num_flush_threads: 2,
num_compaction_threads: 2,
log_level: LogLevel::Info,
block_cache_size: 64 * 1024 * 1024,
max_open_sstables: 256,
max_memory_usage: 0,
log_to_file: false,
log_truncation_at: 24 * 1024 * 1024,
unified_memtable: false,
unified_memtable_write_buffer_size: 0,
unified_memtable_skip_list_max_level: 0,
unified_memtable_skip_list_probability: 0.0,
unified_memtable_sync_mode: SyncMode::None,
unified_memtable_sync_interval_us: 0,
object_store_fs_path: None,
object_store_config: None,
}
}
}
#[derive(Debug, Clone)]
pub struct ColumnFamilyConfig {
pub write_buffer_size: usize,
pub level_size_ratio: usize,
pub min_levels: i32,
pub dividing_level_offset: i32,
pub klog_value_threshold: usize,
pub compression_algorithm: CompressionAlgorithm,
pub enable_bloom_filter: bool,
pub bloom_fpr: f64,
pub enable_block_indexes: bool,
pub index_sample_ratio: i32,
pub block_index_prefix_len: i32,
pub sync_mode: SyncMode,
pub sync_interval_us: u64,
pub comparator_name: String,
pub skip_list_max_level: i32,
pub skip_list_probability: f32,
pub default_isolation_level: IsolationLevel,
pub min_disk_space: u64,
pub l1_file_count_trigger: i32,
pub l0_queue_stall_threshold: i32,
pub use_btree: bool,
pub object_lazy_compaction: bool,
pub object_prefetch_compaction: bool,
}
impl ColumnFamilyConfig {
pub fn new() -> Self {
Self::default()
}
pub fn write_buffer_size(mut self, size: usize) -> Self {
self.write_buffer_size = size;
self
}
pub fn level_size_ratio(mut self, ratio: usize) -> Self {
self.level_size_ratio = ratio;
self
}
pub fn min_levels(mut self, levels: i32) -> Self {
self.min_levels = levels;
self
}
pub fn compression_algorithm(mut self, algo: CompressionAlgorithm) -> Self {
self.compression_algorithm = algo;
self
}
pub fn enable_bloom_filter(mut self, enable: bool) -> Self {
self.enable_bloom_filter = enable;
self
}
pub fn bloom_fpr(mut self, fpr: f64) -> Self {
self.bloom_fpr = fpr;
self
}
pub fn enable_block_indexes(mut self, enable: bool) -> Self {
self.enable_block_indexes = enable;
self
}
pub fn sync_mode(mut self, mode: SyncMode) -> Self {
self.sync_mode = mode;
self
}
pub fn sync_interval_us(mut self, interval: u64) -> Self {
self.sync_interval_us = interval;
self
}
pub fn default_isolation_level(mut self, level: IsolationLevel) -> Self {
self.default_isolation_level = level;
self
}
pub fn dividing_level_offset(mut self, offset: i32) -> Self {
self.dividing_level_offset = offset;
self
}
pub fn klog_value_threshold(mut self, threshold: usize) -> Self {
self.klog_value_threshold = threshold;
self
}
pub fn index_sample_ratio(mut self, ratio: i32) -> Self {
self.index_sample_ratio = ratio;
self
}
pub fn block_index_prefix_len(mut self, len: i32) -> Self {
self.block_index_prefix_len = len;
self
}
pub fn comparator_name(mut self, name: &str) -> Self {
self.comparator_name = name.to_string();
self
}
pub fn skip_list_max_level(mut self, level: i32) -> Self {
self.skip_list_max_level = level;
self
}
pub fn skip_list_probability(mut self, prob: f32) -> Self {
self.skip_list_probability = prob;
self
}
pub fn min_disk_space(mut self, space: u64) -> Self {
self.min_disk_space = space;
self
}
pub fn l1_file_count_trigger(mut self, trigger: i32) -> Self {
self.l1_file_count_trigger = trigger;
self
}
pub fn l0_queue_stall_threshold(mut self, threshold: i32) -> Self {
self.l0_queue_stall_threshold = threshold;
self
}
pub fn use_btree(mut self, enable: bool) -> Self {
self.use_btree = enable;
self
}
pub fn object_lazy_compaction(mut self, enable: bool) -> Self {
self.object_lazy_compaction = enable;
self
}
pub fn object_prefetch_compaction(mut self, enable: bool) -> Self {
self.object_prefetch_compaction = enable;
self
}
pub fn load_from_ini(ini_file: &str, section_name: &str) -> Result<Self> {
let c_ini_file = CString::new(ini_file)?;
let c_section_name = CString::new(section_name)?;
let mut c_config = unsafe { ffi::tidesdb_default_column_family_config() };
let result = unsafe {
ffi::tidesdb_cf_config_load_from_ini(
c_ini_file.as_ptr(),
c_section_name.as_ptr(),
&mut c_config,
)
};
check_result(result, "failed to load config from INI")?;
Ok(Self::from_c_config(&c_config))
}
pub fn save_to_ini(&self, ini_file: &str, section_name: &str) -> Result<()> {
let c_ini_file = CString::new(ini_file)?;
let c_section_name = CString::new(section_name)?;
let c_config = self.to_c_config();
let result = unsafe {
ffi::tidesdb_cf_config_save_to_ini(
c_ini_file.as_ptr(),
c_section_name.as_ptr(),
&c_config,
)
};
check_result(result, "failed to save config to INI")
}
fn from_c_config(c_config: &ffi::tidesdb_column_family_config_t) -> Self {
let mut comparator_name = String::new();
let name_bytes: Vec<u8> = c_config
.comparator_name
.iter()
.take_while(|&&c| c != 0)
.map(|&c| c as u8)
.collect();
if let Ok(s) = std::str::from_utf8(&name_bytes) {
comparator_name = s.to_string();
}
ColumnFamilyConfig {
write_buffer_size: c_config.write_buffer_size,
level_size_ratio: c_config.level_size_ratio,
min_levels: c_config.min_levels,
dividing_level_offset: c_config.dividing_level_offset,
klog_value_threshold: c_config.klog_value_threshold,
compression_algorithm: match c_config.compression_algo {
ffi::SNAPPY_COMPRESSION => CompressionAlgorithm::Snappy,
ffi::LZ4_COMPRESSION => CompressionAlgorithm::Lz4,
ffi::ZSTD_COMPRESSION => CompressionAlgorithm::Zstd,
ffi::LZ4_FAST_COMPRESSION => CompressionAlgorithm::Lz4Fast,
_ => CompressionAlgorithm::None,
},
enable_bloom_filter: c_config.enable_bloom_filter != 0,
bloom_fpr: c_config.bloom_fpr,
enable_block_indexes: c_config.enable_block_indexes != 0,
index_sample_ratio: c_config.index_sample_ratio,
block_index_prefix_len: c_config.block_index_prefix_len,
sync_mode: match c_config.sync_mode {
ffi::TDB_SYNC_FULL => SyncMode::Full,
ffi::TDB_SYNC_INTERVAL => SyncMode::Interval,
_ => SyncMode::None,
},
sync_interval_us: c_config.sync_interval_us,
comparator_name,
skip_list_max_level: c_config.skip_list_max_level,
skip_list_probability: c_config.skip_list_probability,
default_isolation_level: match c_config.default_isolation_level {
ffi::TDB_ISOLATION_READ_UNCOMMITTED => IsolationLevel::ReadUncommitted,
ffi::TDB_ISOLATION_REPEATABLE_READ => IsolationLevel::RepeatableRead,
ffi::TDB_ISOLATION_SNAPSHOT => IsolationLevel::Snapshot,
ffi::TDB_ISOLATION_SERIALIZABLE => IsolationLevel::Serializable,
_ => IsolationLevel::ReadCommitted,
},
min_disk_space: c_config.min_disk_space,
l1_file_count_trigger: c_config.l1_file_count_trigger,
l0_queue_stall_threshold: c_config.l0_queue_stall_threshold,
use_btree: c_config.use_btree != 0,
object_lazy_compaction: c_config.object_lazy_compaction != 0,
object_prefetch_compaction: c_config.object_prefetch_compaction != 0,
}
}
pub(crate) fn to_c_config(&self) -> ffi::tidesdb_column_family_config_t {
let mut config = ffi::tidesdb_column_family_config_t {
name: [0; ffi::TDB_MAX_CF_NAME_LEN],
write_buffer_size: self.write_buffer_size,
level_size_ratio: self.level_size_ratio,
min_levels: self.min_levels,
dividing_level_offset: self.dividing_level_offset,
klog_value_threshold: self.klog_value_threshold,
compression_algo: self.compression_algorithm as i32,
enable_bloom_filter: if self.enable_bloom_filter { 1 } else { 0 },
bloom_fpr: self.bloom_fpr,
enable_block_indexes: if self.enable_block_indexes { 1 } else { 0 },
index_sample_ratio: self.index_sample_ratio,
block_index_prefix_len: self.block_index_prefix_len,
sync_mode: self.sync_mode as i32,
sync_interval_us: self.sync_interval_us,
comparator_name: [0; ffi::TDB_MAX_COMPARATOR_NAME],
comparator_ctx_str: [0; ffi::TDB_MAX_COMPARATOR_CTX],
comparator_fn_cached: std::ptr::null_mut(),
comparator_ctx_cached: std::ptr::null_mut(),
skip_list_max_level: self.skip_list_max_level,
skip_list_probability: self.skip_list_probability,
default_isolation_level: self.default_isolation_level as i32,
min_disk_space: self.min_disk_space,
l1_file_count_trigger: self.l1_file_count_trigger,
l0_queue_stall_threshold: self.l0_queue_stall_threshold,
use_btree: if self.use_btree { 1 } else { 0 },
commit_hook_fn: None,
commit_hook_ctx: std::ptr::null_mut(),
object_lazy_compaction: if self.object_lazy_compaction { 1 } else { 0 },
object_prefetch_compaction: if self.object_prefetch_compaction { 1 } else { 0 },
};
if !self.comparator_name.is_empty() {
let bytes = self.comparator_name.as_bytes();
let len = bytes.len().min(ffi::TDB_MAX_COMPARATOR_NAME - 1);
for (i, &b) in bytes[..len].iter().enumerate() {
config.comparator_name[i] = b as i8;
}
}
config
}
}
impl Default for ColumnFamilyConfig {
fn default() -> Self {
let c_config = unsafe { ffi::tidesdb_default_column_family_config() };
let mut comparator_name = String::new();
let name_bytes: Vec<u8> = c_config
.comparator_name
.iter()
.take_while(|&&c| c != 0)
.map(|&c| c as u8)
.collect();
if let Ok(s) = std::str::from_utf8(&name_bytes) {
comparator_name = s.to_string();
}
ColumnFamilyConfig {
write_buffer_size: c_config.write_buffer_size,
level_size_ratio: c_config.level_size_ratio,
min_levels: c_config.min_levels,
dividing_level_offset: c_config.dividing_level_offset,
klog_value_threshold: c_config.klog_value_threshold,
compression_algorithm: match c_config.compression_algo {
ffi::SNAPPY_COMPRESSION => CompressionAlgorithm::Snappy,
ffi::LZ4_COMPRESSION => CompressionAlgorithm::Lz4,
ffi::ZSTD_COMPRESSION => CompressionAlgorithm::Zstd,
ffi::LZ4_FAST_COMPRESSION => CompressionAlgorithm::Lz4Fast,
_ => CompressionAlgorithm::None,
},
enable_bloom_filter: c_config.enable_bloom_filter != 0,
bloom_fpr: c_config.bloom_fpr,
enable_block_indexes: c_config.enable_block_indexes != 0,
index_sample_ratio: c_config.index_sample_ratio,
block_index_prefix_len: c_config.block_index_prefix_len,
sync_mode: match c_config.sync_mode {
ffi::TDB_SYNC_FULL => SyncMode::Full,
ffi::TDB_SYNC_INTERVAL => SyncMode::Interval,
_ => SyncMode::None,
},
sync_interval_us: c_config.sync_interval_us,
comparator_name,
skip_list_max_level: c_config.skip_list_max_level,
skip_list_probability: c_config.skip_list_probability,
default_isolation_level: match c_config.default_isolation_level {
ffi::TDB_ISOLATION_READ_UNCOMMITTED => IsolationLevel::ReadUncommitted,
ffi::TDB_ISOLATION_REPEATABLE_READ => IsolationLevel::RepeatableRead,
ffi::TDB_ISOLATION_SNAPSHOT => IsolationLevel::Snapshot,
ffi::TDB_ISOLATION_SERIALIZABLE => IsolationLevel::Serializable,
_ => IsolationLevel::ReadCommitted,
},
min_disk_space: c_config.min_disk_space,
l1_file_count_trigger: c_config.l1_file_count_trigger,
l0_queue_stall_threshold: c_config.l0_queue_stall_threshold,
use_btree: c_config.use_btree != 0,
object_lazy_compaction: c_config.object_lazy_compaction != 0,
object_prefetch_compaction: c_config.object_prefetch_compaction != 0,
}
}
}