Skip to content

Commit bc6b4e5

Browse files
authored
Merge pull request #53 from tidesdb/correction2
Correction2
2 parents 5f532cd + 6c87a8b commit bc6b4e5

2 files changed

Lines changed: 63 additions & 20 deletions

File tree

src/tidesdb.lua

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,19 @@ end
11941194

11951195
tidesdb.Transaction = Transaction
11961196

1197+
-- A committed transaction synchronously invokes the column family's commit hook
1198+
-- (a LuaJIT FFI callback) from inside tidesdb_txn_commit. LuaJIT cannot run an
1199+
-- FFI callback that is reached from JIT-compiled code -- once the commit trace is
1200+
-- hot it aborts with "PANIC: bad callback". Force the commit path to stay
1201+
-- interpreted so the hook is always invoked from the interpreter. Guarded so the
1202+
-- module still loads under a plain (non-JIT) Lua interpreter.
1203+
do
1204+
local ok, jit = pcall(require, "jit")
1205+
if ok and jit and jit.off then
1206+
jit.off(Transaction.commit)
1207+
end
1208+
end
1209+
11971210
-- TidesDB class
11981211
local TidesDB = {}
11991212
TidesDB.__index = TidesDB

tests/test_tidesdb.lua

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,26 +1721,56 @@ function tests.test_db_stats_wa_fields()
17211721
end
17221722

17231723
function tests.test_init_finalize()
1724-
-- The library auto-initializes lazily, so finalize() then init() should
1725-
-- succeed and leave the library usable for subsequent operations.
1726-
tidesdb.finalize()
1727-
local rc = tidesdb.init(nil, nil, nil, nil)
1728-
assert_eq(rc, 0, "init after finalize should return 0 (freshly initialized)")
1729-
local rc2 = tidesdb.init(nil, nil, nil, nil)
1730-
assert_eq(rc2, -1, "second init should return -1 (already initialized)")
1731-
1732-
-- confirm the library still works after re-init
1733-
local path = "./test_db_init"
1734-
cleanup_db(path)
1735-
local db = tidesdb.TidesDB.open(path, { log_level = tidesdb.LogLevel.LOG_WARN })
1736-
db:create_column_family("c")
1737-
local cf = db:get_column_family("c")
1738-
local txn = db:begin_txn()
1739-
txn:put(cf, "k", "v")
1740-
txn:commit()
1741-
txn:free()
1742-
db:close()
1743-
cleanup_db(path)
1724+
-- tidesdb.init installs custom allocator functions (malloc/calloc/realloc/free)
1725+
-- and must run before any other TidesDB call; passing nil keeps the system
1726+
-- allocators. As in the C API it is honored only as the first initialization
1727+
-- and returns -1 once the library is already initialized, because the
1728+
-- allocators cannot be swapped under a live library. init/finalize mutate
1729+
-- process-global state, so we must NOT call them in this shared-process suite
1730+
-- -- doing so would tear down the library and crash the next sibling test.
1731+
1732+
-- The bindings must exist.
1733+
assert_true(type(tidesdb.init) == "function", "tidesdb.init should be a function")
1734+
assert_true(type(tidesdb.finalize) == "function", "tidesdb.finalize should be a function")
1735+
1736+
-- Exercise the real finalize -> init(custom allocators) -> use cycle in an
1737+
-- isolated child process so it cannot disturb other tests, and so the init
1738+
-- return-value contract can be asserted deterministically (ordering is fixed
1739+
-- here: finalize first, so the next init is the first one and succeeds).
1740+
local script = [[
1741+
local tidesdb = require("tidesdb")
1742+
tidesdb.finalize()
1743+
-- nil keeps the system allocators; this is where a real caller would pass custom
1744+
-- malloc/calloc/realloc/free. The first init after finalize installs them...
1745+
assert(tidesdb.init(nil, nil, nil, nil) == 0, "first init after finalize should return 0")
1746+
-- ...and a second init is rejected because allocators are already locked in.
1747+
assert(tidesdb.init(nil, nil, nil, nil) == -1, "init on an already-initialized library should return -1")
1748+
local path = "./test_db_init_child"
1749+
os.execute("rm -rf " .. path)
1750+
local db = tidesdb.TidesDB.open(path, { log_level = tidesdb.LogLevel.LOG_WARN })
1751+
db:create_column_family("c")
1752+
local cf = db:get_column_family("c")
1753+
local txn = db:begin_txn()
1754+
txn:put(cf, "k", "v")
1755+
txn:commit()
1756+
txn:free()
1757+
db:close()
1758+
os.execute("rm -rf " .. path)
1759+
print("CHILD_OK")
1760+
]]
1761+
local tmp = "./_init_finalize_child.lua"
1762+
local fh = assert(io.open(tmp, "w"))
1763+
fh:write(script)
1764+
fh:close()
1765+
1766+
-- Reuse the interpreter and environment the suite is already running under.
1767+
local interp = (arg and arg[-1]) or "luajit"
1768+
local p = assert(io.popen(interp .. " " .. tmp .. " 2>&1"))
1769+
local out = p:read("*a")
1770+
p:close()
1771+
os.execute("rm -f " .. tmp)
1772+
assert_true(out:find("CHILD_OK", 1, true) ~= nil,
1773+
"isolated init/finalize cycle should succeed, got:\n" .. tostring(out))
17441774
print("PASS: test_init_finalize")
17451775
end
17461776

0 commit comments

Comments
 (0)