diff --git a/include/tidesdb/tidesdb.hpp b/include/tidesdb/tidesdb.hpp index 393f447..e910e32 100644 --- a/include/tidesdb/tidesdb.hpp +++ b/include/tidesdb/tidesdb.hpp @@ -297,6 +297,15 @@ class ColumnFamily */ void flushMemtable(); + /** + * @brief Synchronously flush memtable and run aggressive compaction to completion + * + * Blocks until all flush and compaction I/O is complete. Use before backup, + * after bulk deletes, or during maintenance windows where a guaranteed clean + * on-disk state is required. + */ + void purge(); + /** * @brief Check if a flush operation is in progress * @return true if flushing, false otherwise @@ -637,6 +646,15 @@ class TidesDB */ void checkpoint(const std::string& dir); + /** + * @brief Synchronously flush and aggressively compact all column families + * + * Calls purge() on each column family and then drains the global flush and + * compaction queues. Blocks until all work is complete. Throws on the first + * column family that fails. + */ + void purge(); + /** * @brief Get default database configuration * @return Default Config struct diff --git a/src/tidesdb.cpp b/src/tidesdb.cpp index 1a7782d..52be007 100644 --- a/src/tidesdb.cpp +++ b/src/tidesdb.cpp @@ -265,6 +265,12 @@ void ColumnFamily::flushMemtable() checkResult(result, "failed to flush memtable"); } +void ColumnFamily::purge() +{ + int result = tidesdb_purge_cf(cf_); + checkResult(result, "failed to purge column family"); +} + bool ColumnFamily::isFlushing() const { return tidesdb_is_flushing(cf_) != 0; @@ -788,6 +794,12 @@ void TidesDB::checkpoint(const std::string& dir) checkResult(result, "failed to create checkpoint"); } +void TidesDB::purge() +{ + int result = tidesdb_purge(db_); + checkResult(result, "failed to purge database"); +} + Config TidesDB::defaultConfig() { tidesdb_config_t cConfig = tidesdb_default_config(); diff --git a/tests/tidesdb_test.cpp b/tests/tidesdb_test.cpp index d4eea53..e0a603d 100644 --- a/tests/tidesdb_test.cpp +++ b/tests/tidesdb_test.cpp @@ -497,6 +497,53 @@ TEST_F(TidesDBTest, FlushMemtable) cf.flushMemtable(); } +TEST_F(TidesDBTest, PurgeColumnFamily) +{ + tidesdb::TidesDB db(getConfig()); + + auto cfConfig = tidesdb::ColumnFamilyConfig::defaultConfig(); + db.createColumnFamily("test_cf", cfConfig); + + auto cf = db.getColumnFamily("test_cf"); + + { + auto txn = db.beginTransaction(); + for (int i = 0; i < 100; ++i) + { + std::string key = "key" + std::to_string(i); + std::string value = "value" + std::to_string(i); + txn.put(cf, key, value, -1); + } + txn.commit(); + } + + ASSERT_NO_THROW(cf.purge()); +} + +TEST_F(TidesDBTest, PurgeDatabase) +{ + tidesdb::TidesDB db(getConfig()); + + auto cfConfig = tidesdb::ColumnFamilyConfig::defaultConfig(); + db.createColumnFamily("cf1", cfConfig); + db.createColumnFamily("cf2", cfConfig); + + auto cf1 = db.getColumnFamily("cf1"); + auto cf2 = db.getColumnFamily("cf2"); + + { + auto txn = db.beginTransaction(); + for (int i = 0; i < 50; ++i) + { + txn.put(cf1, "k1_" + std::to_string(i), "v1_" + std::to_string(i), -1); + txn.put(cf2, "k2_" + std::to_string(i), "v2_" + std::to_string(i), -1); + } + txn.commit(); + } + + ASSERT_NO_THROW(db.purge()); +} + TEST_F(TidesDBTest, NonExistentColumnFamily) { tidesdb::TidesDB db(getConfig());