Skip to content

Commit 7a0f7ca

Browse files
authored
Merge pull request #56 from tidesdb/0.11.0
align with tdb 920 with tombstone density capability, and range compa…
2 parents 6e8e12b + e0de0ed commit 7a0f7ca

4 files changed

Lines changed: 263 additions & 4 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "tidesdb"
7-
version = "0.10.0"
7+
version = "0.11.0"
88
description = "Official Python bindings for TidesDB - A high-performance embedded key-value storage engine"
99
readme = "README.md"
1010
requires-python = ">=3.10"

src/tidesdb/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
TDB_ERR_READONLY,
5050
)
5151

52-
__version__ = "0.10.0"
52+
__version__ = "0.11.0"
5353
__all__ = [
5454
"TidesDB",
5555
"Transaction",

src/tidesdb/tidesdb.py

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

787814
def 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

792837
def 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

Comments
 (0)