Skip to content

Commit b001b4b

Browse files
authored
Merge pull request #38 from tidesdb/updates100
column family commit hook implementation; updated rockspec
2 parents b4c93f7 + 9dfab11 commit b001b4b

3 files changed

Lines changed: 116 additions & 3 deletions

File tree

src/tidesdb.lua

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,18 @@ ffi.cdef[[
4242
// Structures
4343
static const int TDB_MAX_CF_NAME_LEN = 128;
4444

45+
typedef struct {
46+
const uint8_t *key;
47+
size_t key_size;
48+
const uint8_t *value;
49+
size_t value_size;
50+
int64_t ttl;
51+
int is_delete;
52+
} tidesdb_commit_op_t;
53+
54+
typedef int (*tidesdb_commit_hook_fn)(const tidesdb_commit_op_t *ops, int num_ops,
55+
uint64_t commit_seq, void *ctx);
56+
4557
typedef struct {
4658
char name[128];
4759
size_t write_buffer_size;
@@ -68,6 +80,8 @@ ffi.cdef[[
6880
int l1_file_count_trigger;
6981
int l0_queue_stall_threshold;
7082
int use_btree;
83+
tidesdb_commit_hook_fn commit_hook_fn;
84+
void *commit_hook_ctx;
7185
} tidesdb_column_family_config_t;
7286

7387
typedef struct {
@@ -161,6 +175,9 @@ ffi.cdef[[
161175
int tidesdb_get_cache_stats(void* db, tidesdb_cache_stats_t* stats);
162176
int tidesdb_range_cost(void* cf, const uint8_t* key_a, size_t key_a_size, const uint8_t* key_b, size_t key_b_size, double* cost);
163177

178+
// Commit hook operations
179+
int tidesdb_cf_set_commit_hook(void* cf, tidesdb_commit_hook_fn fn, void* ctx);
180+
164181
// Backup operations
165182
int tidesdb_backup(void* db, const char* dir);
166183
int tidesdb_checkpoint(void* db, const char* checkpoint_dir);
@@ -553,6 +570,16 @@ function ColumnFamily:update_runtime_config(config, persist_to_disk)
553570
check_result(result, "failed to update runtime config")
554571
end
555572

573+
function ColumnFamily:set_commit_hook(fn, ctx)
574+
local result = lib.tidesdb_cf_set_commit_hook(self._cf, fn, ctx)
575+
check_result(result, "failed to set commit hook")
576+
end
577+
578+
function ColumnFamily:clear_commit_hook()
579+
local result = lib.tidesdb_cf_set_commit_hook(self._cf, nil, nil)
580+
check_result(result, "failed to clear commit hook")
581+
end
582+
556583
function ColumnFamily:range_cost(key_a, key_b)
557584
local cost = ffi.new("double[1]")
558585
local result = lib.tidesdb_range_cost(self._cf, key_a, #key_a, key_b, #key_b, cost)
@@ -1061,6 +1088,6 @@ function tidesdb.save_config_to_ini(ini_file, section_name, config)
10611088
end
10621089

10631090
-- Version
1064-
tidesdb._VERSION = "0.5.3"
1091+
tidesdb._VERSION = "0.5.4"
10651092

10661093
return tidesdb

tests/test_tidesdb.lua

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,92 @@ function tests.test_range_cost()
676676
print("PASS: test_range_cost")
677677
end
678678

679+
function tests.test_commit_hook()
680+
local ffi = require("ffi")
681+
local path = "./test_db_commit_hook"
682+
cleanup_db(path)
683+
684+
local db = tidesdb.TidesDB.open(path)
685+
db:create_column_family("test_cf")
686+
local cf = db:get_column_family("test_cf")
687+
688+
-- Track hook invocations
689+
local hook_called = 0
690+
local hook_ops_count = 0
691+
local hook_seq = 0
692+
local hook_keys = {}
693+
local hook_had_delete = false
694+
695+
local hook = ffi.cast("tidesdb_commit_hook_fn", function(ops, num_ops, commit_seq, ctx)
696+
hook_called = hook_called + 1
697+
hook_ops_count = hook_ops_count + num_ops
698+
hook_seq = tonumber(commit_seq)
699+
for i = 0, num_ops - 1 do
700+
local key = ffi.string(ops[i].key, ops[i].key_size)
701+
table.insert(hook_keys, key)
702+
if ops[i].is_delete ~= 0 then
703+
hook_had_delete = true
704+
end
705+
end
706+
return 0
707+
end)
708+
709+
-- Set commit hook
710+
cf:set_commit_hook(hook, nil)
711+
712+
-- Write data (should trigger the hook)
713+
local txn = db:begin_txn()
714+
txn:put(cf, "key1", "value1")
715+
txn:put(cf, "key2", "value2")
716+
txn:commit()
717+
txn:free()
718+
719+
assert_true(hook_called >= 1, "commit hook should have been called")
720+
assert_true(hook_ops_count >= 2, "hook should have received at least 2 ops")
721+
assert_true(hook_seq > 0, "commit_seq should be > 0")
722+
723+
-- Verify keys were captured
724+
local found_key1 = false
725+
local found_key2 = false
726+
for _, k in ipairs(hook_keys) do
727+
if k == "key1" then found_key1 = true end
728+
if k == "key2" then found_key2 = true end
729+
end
730+
assert_true(found_key1, "hook should have received key1")
731+
assert_true(found_key2, "hook should have received key2")
732+
733+
-- Test delete operation fires hook
734+
hook_had_delete = false
735+
local del_txn = db:begin_txn()
736+
del_txn:delete(cf, "key1")
737+
del_txn:commit()
738+
del_txn:free()
739+
740+
assert_true(hook_had_delete, "hook should have received a delete operation")
741+
742+
-- Save hook_called count before clearing
743+
local calls_before_clear = hook_called
744+
745+
-- Clear commit hook
746+
cf:clear_commit_hook()
747+
748+
-- Write more data (should NOT trigger the hook)
749+
local txn2 = db:begin_txn()
750+
txn2:put(cf, "key3", "value3")
751+
txn2:commit()
752+
txn2:free()
753+
754+
assert_eq(hook_called, calls_before_clear, "hook should not fire after clearing")
755+
756+
-- Clean up the callback to prevent GC issues
757+
hook:free()
758+
759+
db:drop_column_family("test_cf")
760+
db:close()
761+
cleanup_db(path)
762+
print("PASS: test_commit_hook")
763+
end
764+
679765
-- Run all tests
680766
local function run_tests()
681767
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.3-1"
2+
version = "0.5.4-1"
33
source = {
44
url = "git://github.com/tidesdb/tidesdb-lua.git",
5-
tag = "v0.5.3"
5+
tag = "v0.5.4"
66
}
77
description = {
88
summary = "Official Lua bindings for TidesDB - A high-performance embedded key-value storage engine",

0 commit comments

Comments
 (0)