@@ -209,6 +209,8 @@ class _CColumnFamilyConfig(Structure):
209209 ("min_disk_space" , c_uint64 ),
210210 ("l1_file_count_trigger" , c_int ),
211211 ("l0_queue_stall_threshold" , c_int ),
212+ ("tombstone_density_trigger" , c_double ),
213+ ("tombstone_density_min_entries" , c_uint64 ),
212214 ("use_btree" , c_int ),
213215 ("commit_hook_fn" , c_void_p ),
214216 ("commit_hook_ctx" , c_void_p ),
@@ -279,6 +281,7 @@ class _CConfig(Structure):
279281 ("unified_memtable_sync_interval_us" , c_uint64 ),
280282 ("object_store" , c_void_p ),
281283 ("object_store_config" , c_void_p ),
284+ ("max_concurrent_flushes" , c_int ),
282285 ]
283286
284287
@@ -302,6 +305,11 @@ class _CStats(Structure):
302305 ("btree_total_nodes" , c_uint64 ),
303306 ("btree_max_height" , c_uint32 ),
304307 ("btree_avg_height" , c_double ),
308+ ("total_tombstones" , c_uint64 ),
309+ ("tombstone_ratio" , c_double ),
310+ ("level_tombstone_counts" , POINTER (c_uint64 )),
311+ ("max_sst_density" , c_double ),
312+ ("max_sst_density_level" , c_int ),
305313 ]
306314
307315
@@ -477,6 +485,15 @@ class _CDbStats(Structure):
477485_lib .tidesdb_compact .argtypes = [c_void_p ]
478486_lib .tidesdb_compact .restype = c_int
479487
488+ _lib .tidesdb_compact_range .argtypes = [
489+ c_void_p ,
490+ POINTER (c_uint8 ),
491+ c_size_t ,
492+ POINTER (c_uint8 ),
493+ c_size_t ,
494+ ]
495+ _lib .tidesdb_compact_range .restype = c_int
496+
480497_lib .tidesdb_flush_memtable .argtypes = [c_void_p ]
481498_lib .tidesdb_flush_memtable .restype = c_int
482499
@@ -633,6 +650,7 @@ class Config:
633650 unified_memtable_sync_interval_us : int = 0
634651 object_store : c_void_p | None = None
635652 object_store_config : ObjStoreConfig | None = None
653+ max_concurrent_flushes : int = 0
636654
637655
638656@dataclass
@@ -659,6 +677,8 @@ class ColumnFamilyConfig:
659677 min_disk_space : int = 100 * 1024 * 1024
660678 l1_file_count_trigger : int = 4
661679 l0_queue_stall_threshold : int = 20
680+ tombstone_density_trigger : float = 0.0
681+ tombstone_density_min_entries : int = 1024
662682 use_btree : bool = False
663683 object_lazy_compaction : bool = False
664684 object_prefetch_compaction : bool = True
@@ -691,6 +711,8 @@ def _to_c_struct(self, name: str = "") -> _CColumnFamilyConfig:
691711 c_config .min_disk_space = self .min_disk_space
692712 c_config .l1_file_count_trigger = self .l1_file_count_trigger
693713 c_config .l0_queue_stall_threshold = self .l0_queue_stall_threshold
714+ c_config .tombstone_density_trigger = self .tombstone_density_trigger
715+ c_config .tombstone_density_min_entries = self .tombstone_density_min_entries
694716 c_config .use_btree = 1 if self .use_btree else 0
695717 c_config .object_lazy_compaction = 1 if self .object_lazy_compaction else 0
696718 c_config .object_prefetch_compaction = 1 if self .object_prefetch_compaction else 0
@@ -721,6 +743,11 @@ class Stats:
721743 btree_total_nodes : int = 0
722744 btree_max_height : int = 0
723745 btree_avg_height : float = 0.0
746+ total_tombstones : int = 0
747+ tombstone_ratio : float = 0.0
748+ level_tombstone_counts : list [int ] | None = None
749+ max_sst_density : float = 0.0
750+ max_sst_density_level : int = 0
724751 config : ColumnFamilyConfig | None = None
725752
726753
@@ -785,8 +812,26 @@ class CommitOp:
785812
786813
787814def default_config () -> Config :
788- """Get default database configuration."""
789- return Config (db_path = "" )
815+ """Get default database configuration sourced from the C library."""
816+ c_cfg = _lib .tidesdb_default_config ()
817+ return Config (
818+ db_path = "" ,
819+ num_flush_threads = c_cfg .num_flush_threads ,
820+ num_compaction_threads = c_cfg .num_compaction_threads ,
821+ log_level = LogLevel (c_cfg .log_level ),
822+ block_cache_size = c_cfg .block_cache_size ,
823+ max_open_sstables = c_cfg .max_open_sstables ,
824+ log_to_file = bool (c_cfg .log_to_file ),
825+ log_truncation_at = c_cfg .log_truncation_at ,
826+ max_memory_usage = c_cfg .max_memory_usage ,
827+ unified_memtable = bool (c_cfg .unified_memtable ),
828+ unified_memtable_write_buffer_size = c_cfg .unified_memtable_write_buffer_size ,
829+ unified_memtable_skip_list_max_level = c_cfg .unified_memtable_skip_list_max_level ,
830+ unified_memtable_skip_list_probability = c_cfg .unified_memtable_skip_list_probability ,
831+ unified_memtable_sync_mode = SyncMode (c_cfg .unified_memtable_sync_mode ),
832+ unified_memtable_sync_interval_us = c_cfg .unified_memtable_sync_interval_us ,
833+ max_concurrent_flushes = c_cfg .max_concurrent_flushes ,
834+ )
790835
791836
792837def objstore_default_config () -> ObjStoreConfig :
@@ -864,6 +909,8 @@ def default_column_family_config() -> ColumnFamilyConfig:
864909 min_disk_space = c_config .min_disk_space ,
865910 l1_file_count_trigger = c_config .l1_file_count_trigger ,
866911 l0_queue_stall_threshold = c_config .l0_queue_stall_threshold ,
912+ tombstone_density_trigger = c_config .tombstone_density_trigger ,
913+ tombstone_density_min_entries = c_config .tombstone_density_min_entries ,
867914 use_btree = bool (c_config .use_btree ),
868915 object_lazy_compaction = bool (c_config .object_lazy_compaction ),
869916 object_prefetch_compaction = bool (c_config .object_prefetch_compaction ),
@@ -926,6 +973,8 @@ def load_config_from_ini(file_path: str, cf_name: str) -> ColumnFamilyConfig:
926973 min_disk_space = c_config .min_disk_space ,
927974 l1_file_count_trigger = c_config .l1_file_count_trigger ,
928975 l0_queue_stall_threshold = c_config .l0_queue_stall_threshold ,
976+ tombstone_density_trigger = c_config .tombstone_density_trigger ,
977+ tombstone_density_min_entries = c_config .tombstone_density_min_entries ,
929978 use_btree = bool (c_config .use_btree ),
930979 object_lazy_compaction = bool (c_config .object_lazy_compaction ),
931980 object_prefetch_compaction = bool (c_config .object_prefetch_compaction ),
@@ -1090,6 +1139,42 @@ def compact(self) -> None:
10901139 if result != TDB_SUCCESS :
10911140 raise TidesDBError .from_code (result , "failed to compact column family" )
10921141
1142+ def compact_range (self , start_key : bytes | None , end_key : bytes | None ) -> None :
1143+ """
1144+ Synchronously compact every SSTable whose key range overlaps
1145+ [start_key, end_key).
1146+
1147+ Output is merged toward the largest level affected. Pass None for an
1148+ unbounded endpoint. Both endpoints None/empty is rejected with
1149+ TDB_ERR_INVALID_ARGS - use compact() for full-CF compaction.
1150+
1151+ Args:
1152+ start_key: Inclusive lower bound, or None for unbounded.
1153+ end_key: Exclusive upper bound, or None for unbounded.
1154+
1155+ Raises:
1156+ TidesDBError: TDB_ERR_INVALID_ARGS if both endpoints are unbounded,
1157+ TDB_ERR_LOCKED if another compaction is running, or other I/O
1158+ errors from the underlying merge.
1159+ """
1160+ if start_key is None or len (start_key ) == 0 :
1161+ start_buf = None
1162+ start_len = 0
1163+ else :
1164+ start_buf = (c_uint8 * len (start_key )).from_buffer_copy (start_key )
1165+ start_len = len (start_key )
1166+
1167+ if end_key is None or len (end_key ) == 0 :
1168+ end_buf = None
1169+ end_len = 0
1170+ else :
1171+ end_buf = (c_uint8 * len (end_key )).from_buffer_copy (end_key )
1172+ end_len = len (end_key )
1173+
1174+ result = _lib .tidesdb_compact_range (self ._cf , start_buf , start_len , end_buf , end_len )
1175+ if result != TDB_SUCCESS :
1176+ raise TidesDBError .from_code (result , "failed to compact range" )
1177+
10931178 def flush_memtable (self ) -> None :
10941179 """Manually trigger memtable flush for this column family."""
10951180 result = _lib .tidesdb_flush_memtable (self ._cf )
@@ -1266,6 +1351,7 @@ def get_stats(self) -> Stats:
12661351 level_sizes = []
12671352 level_num_sstables = []
12681353 level_key_counts = []
1354+ level_tombstone_counts : list [int ] = []
12691355
12701356 if c_stats .num_levels > 0 :
12711357 if c_stats .level_sizes :
@@ -1277,6 +1363,9 @@ def get_stats(self) -> Stats:
12771363 if c_stats .level_key_counts :
12781364 for i in range (c_stats .num_levels ):
12791365 level_key_counts .append (c_stats .level_key_counts [i ])
1366+ if c_stats .level_tombstone_counts :
1367+ for i in range (c_stats .num_levels ):
1368+ level_tombstone_counts .append (c_stats .level_tombstone_counts [i ])
12801369
12811370 config = None
12821371 if c_stats .config :
@@ -1302,6 +1391,8 @@ def get_stats(self) -> Stats:
13021391 min_disk_space = c_cfg .min_disk_space ,
13031392 l1_file_count_trigger = c_cfg .l1_file_count_trigger ,
13041393 l0_queue_stall_threshold = c_cfg .l0_queue_stall_threshold ,
1394+ tombstone_density_trigger = c_cfg .tombstone_density_trigger ,
1395+ tombstone_density_min_entries = c_cfg .tombstone_density_min_entries ,
13051396 use_btree = bool (c_cfg .use_btree ),
13061397 object_lazy_compaction = bool (c_cfg .object_lazy_compaction ),
13071398 object_prefetch_compaction = bool (c_cfg .object_prefetch_compaction ),
@@ -1323,6 +1414,11 @@ def get_stats(self) -> Stats:
13231414 btree_total_nodes = c_stats .btree_total_nodes ,
13241415 btree_max_height = c_stats .btree_max_height ,
13251416 btree_avg_height = c_stats .btree_avg_height ,
1417+ total_tombstones = c_stats .total_tombstones ,
1418+ tombstone_ratio = c_stats .tombstone_ratio ,
1419+ level_tombstone_counts = level_tombstone_counts ,
1420+ max_sst_density = c_stats .max_sst_density ,
1421+ max_sst_density_level = c_stats .max_sst_density_level ,
13261422 config = config ,
13271423 )
13281424
@@ -1624,6 +1720,7 @@ def __init__(self, config: Config) -> None:
16241720 unified_memtable_sync_interval_us = config .unified_memtable_sync_interval_us ,
16251721 object_store = obj_store_ptr ,
16261722 object_store_config = obj_store_config_ptr ,
1723+ max_concurrent_flushes = config .max_concurrent_flushes ,
16271724 )
16281725
16291726 db_ptr = c_void_p ()
@@ -1654,6 +1751,7 @@ def open(
16541751 unified_memtable_sync_interval_us : int = 0 ,
16551752 object_store : c_void_p | None = None ,
16561753 object_store_config : ObjStoreConfig | None = None ,
1754+ max_concurrent_flushes : int = 0 ,
16571755 ) -> TidesDB :
16581756 """
16591757 Convenience method to open a database with individual parameters.
@@ -1676,6 +1774,8 @@ def open(
16761774 unified_memtable_sync_interval_us: Sync interval in microseconds for unified memtable
16771775 object_store: Object store connector handle (from objstore_fs_create())
16781776 object_store_config: Object store behavior configuration
1777+ max_concurrent_flushes: Global semaphore on in-flight memtable flushes
1778+ across all column families (0 = library default)
16791779
16801780 Returns:
16811781 TidesDB instance
@@ -1698,6 +1798,7 @@ def open(
16981798 unified_memtable_sync_interval_us = unified_memtable_sync_interval_us ,
16991799 object_store = object_store ,
17001800 object_store_config = object_store_config ,
1801+ max_concurrent_flushes = max_concurrent_flushes ,
17011802 )
17021803 return cls (config )
17031804
0 commit comments