Tags: erigontech/mdbx-go
Tags
mdbx: fix cursor leak on Close after write-txn end + cursor lifecycle… … hardening (#229) * mdbx: fix cursor leak on Close after write-txn end, nil-txn panics, stale txn after Unbind In libmdbx (unlike LMDB) cursors are never freed when their transaction ends: txn end only marks them ready4dispose (see cursor_eot in mdbx.c), and mdbx_cursor_close explicitly handles that state. Cursor.Close was skipping mdbx_cursor_close for cursors whose write transaction had already terminated, leaking the C-side cursor allocation every time. Also: - Close/Get/PutReserve no longer nil-panic on a cursor that was never bound to a transaction (CreateCursor/CursorFromPool); Get/PutReserve return MDBX_EINVAL like Put already does. - Unbind clears the stale c.txn reference so a later Close cannot consult a dead transaction and the Txn object is not kept reachable. * mdbx: document ReleaseAllCursors(false) freeing C handles, fix cursor-lifecycle doc claims /code-review follow-up: with unbind=false libmdbx osal_frees the cursors, so Go wrappers must be discarded without Close; the always- close contract otherwise stands. Also: Close doc no longer implies cross-thread safety for live write-txn cursors, Unbind doc notes Txn() reports nil, Checkpoint/CommitEmbarkRead/Rollback warnings now say cursors stay closable after the call (skipping Close is exactly the leak this PR fixes), and CursorToPool documents the closed-cursor and pool-eviction caveats. * mdbx: clarify Unbind doc (grammar, Txn/DBI behavior while unbound) * mdbx: CursorToPool clears the txn reference and drops closed cursors A pooled cursor kept its stale Go txn pointer, bypassing the new unbound-cursor guard in Get/PutReserve and pinning the ended Txn object; pooling an already-closed cursor handed out a permanently dead handle. * mdbx: drop the Go-side closed/unbound guard from Cursor.Get Redundant since the Get rewrite: Get no longer touches c.txn, and libmdbx's cursor_check returns EINVAL for both NULL (mdbx.c:16647) and unbound ready4dispose cursors (mdbx.c:16653), which is exactly what the guard produced. TestCursor_UseNeverBound still passes via the C path. PutReserve keeps its guard: it dereferences c.txn.val before the call. * mdbx: Cursor.PutReserve returns the reserved buffer by value, guard dropped New mdbxgo_cursor_put_reserve helper returns the MDBX_RESERVE buffer in mdbxgo_val_result, so PutReserve no longer needs the per-Txn scratch MDBX_val nor the closed/unbound guard (cursor_check handles both with EINVAL, as with Get). TestCursor_UseNeverBound covers the unbound path. * mdbx: drop nolint directive left unused by the PutReserve rewrite * mdbx: note at the PutReserve call site that the helper enforces MDBX_RESERVE * mdbx: CursorToPool unbinds so a pooled cursor cannot read via a stale binding Since Get no longer checks c.txn, clearing only the Go-side c.txn left a pooled cursor able to read through its previous libmdbx binding (a cross-txn/cross-goroutine hazard). CursorToPool now Unbinds the C cursor (a no-op once the txn ended, an active unbind while it is still live), so a reused cursor returns EINVAL from Get until Bind/Renew. Broken handles are closed instead of pooled. Adds a regression test. * mdbx: CursorToPool tolerates a nil cursor, like sync.Pool.Put(nil)
backport(v0.40.3.1): fix Cursor.Close leaking the C cursor after a wr… …ite txn ends (#246) mdbx: fix Cursor.Close leaking the C cursor after a write txn ends (backport) Backport of the Cursor.Close leak fix (PR #229) to the v0.40.3 release line. Cursor.Close skipped mdbx_cursor_close when the write transaction had already terminated, on the LMDB-era assumption that libmdbx frees the cursor at txn end. It does not (txn end only marks cursors reusable; mdbx_cursor_close frees them), so every cursor closed after its write txn ended leaked its C allocation. Close now always frees the cursor, which is safe before or after txn end. Adds focused regression tests.
backport(v0.39.19.1): fix Cursor.Close leaking the C cursor after a w… …rite txn ends (#247) mdbx: fix Cursor.Close leaking the C cursor after a write txn ends (backport) Backport of the Cursor.Close leak fix (PR #229) to the v0.39.19 release line. Cursor.Close skipped mdbx_cursor_close when the write transaction had already terminated, on the LMDB-era assumption that libmdbx frees the cursor at txn end. It does not (txn end only marks cursors reusable; mdbx_cursor_close frees them), so every cursor closed after its write txn ended leaked its C allocation. Close now always frees the cursor, which is safe before or after txn end. Adds focused regression tests.
mdbx: expose Env.SyncForce and Env.SyncPoll (#227) Add thin wrappers around the mdbx_env_sync / mdbx_env_sync_poll shortcuts of mdbx_env_sync_ex, complementing the existing Env.Sync(force, nonblock): - SyncForce() -> force=true, nonblock=false: synchronous flush, ignoring NoMetaSync/SafeNoSync/UtterlyNoSync. - SyncPoll() -> force=false, nonblock=true: lazy/polling flush that only writes when SetSyncBytes/SetSyncPeriod thresholds are reached and does not block on a concurrent writer. MDBX_RESULT_TRUE ("nothing pending") maps to a nil error. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mdbx: expose range estimation + cursor distribution/deletion APIs (#225) * mdbx: expose range estimation + cursor distribution/deletion APIs Expose the libmdbx range-estimation (c_rqest) and B-tree cursor navigation (c_cursors) groups, aimed at splitting a key range into balanced chunks for parallel workers (e.g. concurrent range deletion or warm-up): - Txn.EstimateRange -> mdbx_estimate_range - Cursor.EstimateDistance -> mdbx_estimate_distance - Cursor.EstimateMove -> mdbx_estimate_move - Cursor.Distance -> mdbx_cursor_distance (deepness-controlled, exact) - Cursor.Scroll -> mdbx_cursor_scroll - DistributeCursors -> mdbx_cursor_distribute (equally-sized ranges) - Cursor.DeleteRange -> mdbx_cursor_delete_range (mass range delete) DistributeCursors positions N cursors at evenly-spaced positions across a range so consecutive cursors delimit approximately equal sub-ranges. Includes tests covering even distribution, explicit bounds, the not-enough-positions case (allSet=false), an end-to-end chunked-delete workflow, and error handling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * save * save * mdbx: doc fixes for EstimateDistance/DistributeCursors (#226) mdbx: fix EstimateDistance/DistributeCursors doc inaccuracies - EstimateDistance: mdbx_estimate_distance requires both cursors and has no nil end-of-table sentinel (unlike Distance). State that nil last is not valid here. - DistributeCursors: drop the invented 'cursors must contain a cursor that is neither first nor last' claim — mdbx_cursor_distribute has no such requirement. Describe the actual constraint on the cursors slice. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: awskii <awskii@users.noreply.github.com>
PreviousNext