Skip to content

Commit 693df77

Browse files
authored
Merge pull request #44 from tidesdb/0-5-6
addition of db stats, purge, and sync wal methods with tests; bumped …
2 parents 2fe98ef + 9254ad7 commit 693df77

3 files changed

Lines changed: 235 additions & 3 deletions

File tree

src/tidesdb.lua

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,33 @@ ffi.cdef[[
180180
// Commit hook operations
181181
int tidesdb_cf_set_commit_hook(void* cf, tidesdb_commit_hook_fn fn, void* ctx);
182182

183+
// Sync WAL
184+
int tidesdb_sync_wal(void* cf);
185+
186+
// Purge operations
187+
int tidesdb_purge_cf(void* cf);
188+
int tidesdb_purge(void* db);
189+
190+
// Database-level statistics
191+
typedef struct {
192+
int num_column_families;
193+
uint64_t total_memory;
194+
uint64_t available_memory;
195+
size_t resolved_memory_limit;
196+
int memory_pressure_level;
197+
int flush_pending_count;
198+
int64_t total_memtable_bytes;
199+
int total_immutable_count;
200+
int total_sstable_count;
201+
uint64_t total_data_size_bytes;
202+
int num_open_sstables;
203+
uint64_t global_seq;
204+
int64_t txn_memory_bytes;
205+
size_t compaction_queue_size;
206+
size_t flush_queue_size;
207+
} tidesdb_db_stats_t;
208+
int tidesdb_get_db_stats(void* db, tidesdb_db_stats_t* stats);
209+
183210
// Backup operations
184211
int tidesdb_backup(void* db, const char* dir);
185212
int tidesdb_checkpoint(void* db, const char* checkpoint_dir);
@@ -583,6 +610,16 @@ function ColumnFamily:clear_commit_hook()
583610
check_result(result, "failed to clear commit hook")
584611
end
585612

613+
function ColumnFamily:sync_wal()
614+
local result = lib.tidesdb_sync_wal(self._cf)
615+
check_result(result, "failed to sync WAL")
616+
end
617+
618+
function ColumnFamily:purge()
619+
local result = lib.tidesdb_purge_cf(self._cf)
620+
check_result(result, "failed to purge column family")
621+
end
622+
586623
function ColumnFamily:range_cost(key_a, key_b)
587624
local cost = ffi.new("double[1]")
588625
local result = lib.tidesdb_range_cost(self._cf, key_a, #key_a, key_b, #key_b, cost)
@@ -1022,6 +1059,43 @@ function TidesDB:get_cache_stats()
10221059
}
10231060
end
10241061

1062+
function TidesDB:purge()
1063+
if self._closed then
1064+
error(TidesDBError.new("Database is closed"))
1065+
end
1066+
1067+
local result = lib.tidesdb_purge(self._db)
1068+
check_result(result, "failed to purge database")
1069+
end
1070+
1071+
function TidesDB:get_db_stats()
1072+
if self._closed then
1073+
error(TidesDBError.new("Database is closed"))
1074+
end
1075+
1076+
local c_stats = ffi.new("tidesdb_db_stats_t")
1077+
local result = lib.tidesdb_get_db_stats(self._db, c_stats)
1078+
check_result(result, "failed to get database stats")
1079+
1080+
return {
1081+
num_column_families = c_stats.num_column_families,
1082+
total_memory = tonumber(c_stats.total_memory),
1083+
available_memory = tonumber(c_stats.available_memory),
1084+
resolved_memory_limit = tonumber(c_stats.resolved_memory_limit),
1085+
memory_pressure_level = c_stats.memory_pressure_level,
1086+
flush_pending_count = c_stats.flush_pending_count,
1087+
total_memtable_bytes = tonumber(c_stats.total_memtable_bytes),
1088+
total_immutable_count = c_stats.total_immutable_count,
1089+
total_sstable_count = c_stats.total_sstable_count,
1090+
total_data_size_bytes = tonumber(c_stats.total_data_size_bytes),
1091+
num_open_sstables = c_stats.num_open_sstables,
1092+
global_seq = tonumber(c_stats.global_seq),
1093+
txn_memory_bytes = tonumber(c_stats.txn_memory_bytes),
1094+
compaction_queue_size = tonumber(c_stats.compaction_queue_size),
1095+
flush_queue_size = tonumber(c_stats.flush_queue_size),
1096+
}
1097+
end
1098+
10251099
function TidesDB:backup(dir)
10261100
if self._closed then
10271101
error(TidesDBError.new("Database is closed"))
@@ -1102,6 +1176,6 @@ function tidesdb.save_config_to_ini(ini_file, section_name, config)
11021176
end
11031177

11041178
-- Version
1105-
tidesdb._VERSION = "0.5.5"
1179+
tidesdb._VERSION = "0.5.6"
11061180

11071181
return tidesdb

tests/test_tidesdb.lua

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,164 @@ function tests.test_max_memory_usage()
910910
print("PASS: test_max_memory_usage")
911911
end
912912

913+
function tests.test_sync_wal()
914+
local path = "./test_db_sync_wal"
915+
cleanup_db(path)
916+
917+
local db = tidesdb.TidesDB.open(path, {
918+
log_level = tidesdb.LogLevel.LOG_WARN,
919+
})
920+
local cf_config = tidesdb.default_column_family_config()
921+
cf_config.sync_mode = tidesdb.SyncMode.SYNC_NONE
922+
db:create_column_family("test_cf", cf_config)
923+
local cf = db:get_column_family("test_cf")
924+
925+
-- Write some data
926+
local txn = db:begin_txn()
927+
txn:put(cf, "key1", "value1")
928+
txn:put(cf, "key2", "value2")
929+
txn:commit()
930+
txn:free()
931+
932+
-- Manually sync WAL
933+
cf:sync_wal()
934+
935+
-- Verify data is still readable after sync
936+
local read_txn = db:begin_txn()
937+
local v1 = read_txn:get(cf, "key1")
938+
local v2 = read_txn:get(cf, "key2")
939+
assert_eq(v1, "value1", "key1 should be readable after sync_wal")
940+
assert_eq(v2, "value2", "key2 should be readable after sync_wal")
941+
read_txn:free()
942+
943+
db:drop_column_family("test_cf")
944+
db:close()
945+
cleanup_db(path)
946+
print("PASS: test_sync_wal")
947+
end
948+
949+
function tests.test_purge_cf()
950+
local path = "./test_db_purge_cf"
951+
cleanup_db(path)
952+
953+
local db = tidesdb.TidesDB.open(path, {
954+
log_level = tidesdb.LogLevel.LOG_WARN,
955+
})
956+
db:create_column_family("test_cf")
957+
local cf = db:get_column_family("test_cf")
958+
959+
-- Write some data
960+
local txn = db:begin_txn()
961+
for i = 1, 10 do
962+
txn:put(cf, string.format("key:%04d", i), string.format("value:%04d", i))
963+
end
964+
txn:commit()
965+
txn:free()
966+
967+
-- Purge column family (synchronous flush + compaction)
968+
cf:purge()
969+
970+
-- Verify data is still readable after purge
971+
local read_txn = db:begin_txn()
972+
local v1 = read_txn:get(cf, "key:0001")
973+
local v10 = read_txn:get(cf, "key:0010")
974+
assert_eq(v1, "value:0001", "key:0001 should be readable after purge_cf")
975+
assert_eq(v10, "value:0010", "key:0010 should be readable after purge_cf")
976+
read_txn:free()
977+
978+
-- After purge, flushing and compacting should be done
979+
assert_eq(cf:is_flushing(), false, "should not be flushing after purge")
980+
assert_eq(cf:is_compacting(), false, "should not be compacting after purge")
981+
982+
db:drop_column_family("test_cf")
983+
db:close()
984+
cleanup_db(path)
985+
print("PASS: test_purge_cf")
986+
end
987+
988+
function tests.test_purge_db()
989+
local path = "./test_db_purge_db"
990+
cleanup_db(path)
991+
992+
local db = tidesdb.TidesDB.open(path, {
993+
log_level = tidesdb.LogLevel.LOG_WARN,
994+
})
995+
db:create_column_family("cf_a")
996+
db:create_column_family("cf_b")
997+
local cf_a = db:get_column_family("cf_a")
998+
local cf_b = db:get_column_family("cf_b")
999+
1000+
-- Write data to both CFs
1001+
local txn = db:begin_txn()
1002+
txn:put(cf_a, "a_key1", "a_value1")
1003+
txn:put(cf_b, "b_key1", "b_value1")
1004+
txn:commit()
1005+
txn:free()
1006+
1007+
-- Purge entire database
1008+
db:purge()
1009+
1010+
-- Verify data is still readable
1011+
local read_txn = db:begin_txn()
1012+
local va = read_txn:get(cf_a, "a_key1")
1013+
local vb = read_txn:get(cf_b, "b_key1")
1014+
assert_eq(va, "a_value1", "cf_a key should be readable after db purge")
1015+
assert_eq(vb, "b_value1", "cf_b key should be readable after db purge")
1016+
read_txn:free()
1017+
1018+
db:drop_column_family("cf_a")
1019+
db:drop_column_family("cf_b")
1020+
db:close()
1021+
cleanup_db(path)
1022+
print("PASS: test_purge_db")
1023+
end
1024+
1025+
function tests.test_get_db_stats()
1026+
local path = "./test_db_db_stats"
1027+
cleanup_db(path)
1028+
1029+
local db = tidesdb.TidesDB.open(path, {
1030+
log_level = tidesdb.LogLevel.LOG_WARN,
1031+
})
1032+
db:create_column_family("cf_a")
1033+
db:create_column_family("cf_b")
1034+
local cf_a = db:get_column_family("cf_a")
1035+
local cf_b = db:get_column_family("cf_b")
1036+
1037+
-- Write some data
1038+
local txn = db:begin_txn()
1039+
txn:put(cf_a, "key1", "value1")
1040+
txn:put(cf_b, "key2", "value2")
1041+
txn:commit()
1042+
txn:free()
1043+
1044+
-- Get database-level stats
1045+
local db_stats = db:get_db_stats()
1046+
1047+
-- Verify fields exist and have sensible values
1048+
assert_true(db_stats.num_column_families >= 2, "should have at least 2 column families")
1049+
assert_true(db_stats.total_memory > 0, "total_memory should be > 0")
1050+
assert_true(db_stats.resolved_memory_limit > 0, "resolved_memory_limit should be > 0")
1051+
assert_true(db_stats.memory_pressure_level >= 0, "memory_pressure_level should be >= 0")
1052+
assert_true(db_stats.global_seq >= 0, "global_seq should be >= 0")
1053+
assert_true(db_stats.flush_queue_size >= 0, "flush_queue_size should be >= 0")
1054+
assert_true(db_stats.compaction_queue_size >= 0, "compaction_queue_size should be >= 0")
1055+
assert_true(db_stats.total_sstable_count >= 0, "total_sstable_count should be >= 0")
1056+
assert_true(db_stats.total_data_size_bytes >= 0, "total_data_size_bytes should be >= 0")
1057+
assert_true(db_stats.num_open_sstables >= 0, "num_open_sstables should be >= 0")
1058+
assert_true(db_stats.txn_memory_bytes ~= nil, "txn_memory_bytes should exist")
1059+
assert_true(db_stats.total_memtable_bytes ~= nil, "total_memtable_bytes should exist")
1060+
assert_true(db_stats.total_immutable_count >= 0, "total_immutable_count should be >= 0")
1061+
assert_true(db_stats.flush_pending_count >= 0, "flush_pending_count should be >= 0")
1062+
assert_true(db_stats.available_memory ~= nil, "available_memory should exist")
1063+
1064+
db:drop_column_family("cf_a")
1065+
db:drop_column_family("cf_b")
1066+
db:close()
1067+
cleanup_db(path)
1068+
print("PASS: test_get_db_stats")
1069+
end
1070+
9131071
-- Run all tests
9141072
local function run_tests()
9151073
print("Running TidesDB Lua tests...")
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package = "tidesdb"
2-
version = "0.5.5-1"
2+
version = "0.5.6-1"
33
source = {
44
url = "git://github.com/tidesdb/tidesdb-lua.git",
5-
tag = "v0.5.5"
5+
tag = "v0.5.6"
66
}
77
description = {
88
summary = "Official Lua bindings for TidesDB - A high-performance embedded key-value storage engine",

0 commit comments

Comments
 (0)