mdbx: добавление mdbx_cursor_unbind() в API.

This commit is contained in:
Леонид Юрьев (Leonid Yuriev) 2023-10-13 17:36:21 +03:00
parent 5f274eb4c6
commit d28a397b2d
3 changed files with 68 additions and 25 deletions

22
mdbx.h
View File

@ -4732,6 +4732,28 @@ mdbx_cursor_get_userctx(const MDBX_cursor *cursor);
LIBMDBX_API int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *cursor,
MDBX_dbi dbi);
/** \brief Unbind cursor from a transaction.
* \ingroup c_cursors
*
* Unbinded cursor is disassociated with any transactions but still holds
* the original DBI-handle internally. Thus it could be renewed with any running
* transaction or closed.
*
* \see mdbx_cursor_renew()
* \see mdbx_cursor_bind()
* \see mdbx_cursor_close()
*
* \note In contrast to LMDB, the MDBX required that any opened cursors can be
* reused and must be freed explicitly, regardless ones was opened in a
* read-only or write transaction. The REASON for this is eliminates ambiguity
* which helps to avoid errors such as: use-after-free, double-free, i.e.
* memory corruption and segfaults.
*
* \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open().
*
* \returns A non-zero error value on failure and 0 on success. */
LIBMDBX_API int mdbx_cursor_unbind(MDBX_cursor *cursor);
/** \brief Create a cursor handle for the specified transaction and DBI handle.
* \ingroup c_cursors
*

View File

@ -4223,6 +4223,9 @@ public:
/// map handle.
inline void bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle);
/// \brief Unbind cursor from a transaction.
inline void unbind();
/// \brief Returns the cursor's transaction.
inline ::mdbx::txn txn() const;
inline map_handle map() const;
@ -6110,6 +6113,10 @@ inline void cursor::bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle) {
error::success_or_throw(::mdbx_cursor_bind(txn, handle_, map_handle.dbi));
}
inline void cursor::unbind() {
error::success_or_throw(::mdbx_cursor_unbind(handle_));
}
inline txn cursor::txn() const {
MDBX_txn *txn = ::mdbx_cursor_txn(handle_);
error::throw_on_nullptr(txn, MDBX_EINVAL);

View File

@ -18846,6 +18846,38 @@ void *mdbx_cursor_get_userctx(const MDBX_cursor *mc) {
return couple->mc_userctx;
}
int mdbx_cursor_unbind(MDBX_cursor *mc) {
if (unlikely(!mc))
return MDBX_EINVAL;
if (unlikely(mc->mc_signature != MDBX_MC_LIVE))
return (mc->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_SUCCESS
: MDBX_EBADSIGN;
if (unlikely(mc->mc_backup)) /* Cursor from parent transaction */
return MDBX_EINVAL;
eASSERT(nullptr, mc->mc_txn && mc->mc_txn->mt_signature == MDBX_MT_SIGNATURE);
cASSERT(mc, mc->mc_signature == MDBX_MC_LIVE);
cASSERT(mc, !mc->mc_backup);
if (unlikely(!mc->mc_txn || mc->mc_txn->mt_signature != MDBX_MT_SIGNATURE)) {
ERROR("Wrong cursor's transaction %p 0x%x",
__Wpedantic_format_voidptr(mc->mc_txn),
mc->mc_txn ? mc->mc_txn->mt_signature : 0);
return MDBX_PROBLEM;
}
if (mc->mc_flags & C_UNTRACK) {
MDBX_cursor **prev = &mc->mc_txn->mt_cursors[mc->mc_dbi];
while (*prev && *prev != mc)
prev = &(*prev)->mc_next;
cASSERT(mc, *prev == mc);
*prev = mc->mc_next;
}
mc->mc_signature = MDBX_MC_READY4CLOSE;
mc->mc_flags = 0;
return MDBX_SUCCESS;
}
int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) {
if (unlikely(!mc))
return MDBX_EINVAL;
@ -18871,10 +18903,10 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) {
mc->mc_txn != txn))
return MDBX_EINVAL;
assert(mc->mc_db == &txn->mt_dbs[dbi]);
assert(mc->mc_dbx == &txn->mt_dbxs[dbi]);
assert(mc->mc_dbi == dbi);
assert(mc->mc_dbistate == &txn->mt_dbistate[dbi]);
cASSERT(mc, mc->mc_db == &txn->mt_dbs[dbi]);
cASSERT(mc, mc->mc_dbx == &txn->mt_dbxs[dbi]);
cASSERT(mc, mc->mc_dbi == dbi);
cASSERT(mc, mc->mc_dbistate == &txn->mt_dbistate[dbi]);
return likely(mc->mc_dbi == dbi &&
/* paranoia */ mc->mc_signature == MDBX_MC_LIVE &&
mc->mc_txn == txn)
@ -18883,27 +18915,9 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) {
}
if (mc->mc_signature == MDBX_MC_LIVE) {
if (unlikely(!mc->mc_txn ||
mc->mc_txn->mt_signature != MDBX_MT_SIGNATURE)) {
ERROR("Wrong cursor's transaction %p 0x%x",
__Wpedantic_format_voidptr(mc->mc_txn),
mc->mc_txn ? mc->mc_txn->mt_signature : 0);
return MDBX_PROBLEM;
}
if (mc->mc_flags & C_UNTRACK) {
MDBX_cursor **prev = &mc->mc_txn->mt_cursors[mc->mc_dbi];
while (*prev && *prev != mc)
prev = &(*prev)->mc_next;
cASSERT(mc, *prev == mc);
*prev = mc->mc_next;
}
mc->mc_signature = MDBX_MC_READY4CLOSE;
mc->mc_flags = 0;
mc->mc_dbi = UINT_MAX;
mc->mc_next = NULL;
mc->mc_db = NULL;
mc->mc_dbx = NULL;
mc->mc_dbistate = NULL;
rc = mdbx_cursor_unbind(mc);
if (unlikely(rc != MDBX_SUCCESS))
return rc;
}
cASSERT(mc, !(mc->mc_flags & C_UNTRACK));