mdbx: переработка mdbx_txn_release_all_cursors_ex() (backport).

This commit is contained in:
Леонид Юрьев (Leonid Yuriev) 2025-03-20 01:42:50 +03:00
parent 682233ba28
commit 5fd319bbc2
2 changed files with 43 additions and 34 deletions

26
mdbx.h
View File

@ -5261,15 +5261,12 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor);
* \retval MDBX_EINVAL An invalid parameter was specified. */ * \retval MDBX_EINVAL An invalid parameter was specified. */
LIBMDBX_API int mdbx_cursor_close2(MDBX_cursor *cursor); LIBMDBX_API int mdbx_cursor_close2(MDBX_cursor *cursor);
/** \brief Unbind or closes all cursors of a given transaction. /** \brief Unbind or closes all cursors of a given transaction and of all
* its parent transactions if ones are.
* \ingroup c_cursors * \ingroup c_cursors
* *
* Unbinds either closes all cursors associated (opened or renewed) with * Unbinds either closes all cursors associated (opened, renewed or binded) with
* a given transaction in a bulk with minimal overhead. * the given transaction in a bulk with minimal overhead.
*
* A transaction should not be nested, since in this case no way to restore
* state if this nested transaction will be aborted, nor impossible to define
* the expected behavior.
* *
* \see mdbx_cursor_unbind() * \see mdbx_cursor_unbind()
* \see mdbx_cursor_close() * \see mdbx_cursor_close()
@ -5284,19 +5281,16 @@ LIBMDBX_API int mdbx_cursor_close2(MDBX_cursor *cursor);
* some possible errors are: * some possible errors are:
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned * \retval MDBX_THREAD_MISMATCH Given transaction is not owned
* by current thread. * by current thread.
* \retval MDBX_BAD_TXN Given transaction is invalid, nested or has * \retval MDBX_BAD_TXN Given transaction is invalid or has
* a child/nested transaction transaction. */ * a child/nested transaction transaction. */
LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count); LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count);
/** \brief Unbind or closes all cursors of a given transaction. /** \brief Unbind or closes all cursors of a given transaction and of all
* its parent transactions if ones are.
* \ingroup c_cursors * \ingroup c_cursors
* *
* Unbinds either closes all cursors associated (opened or renewed) with * Unbinds either closes all cursors associated (opened, renewed or binded) with
* a given transaction in a bulk with minimal overhead. * the given transaction in a bulk with minimal overhead.
*
* A transaction should not be nested, since in this case no way to restore
* state if this nested transaction will be aborted, nor impossible to define
* the expected behavior.
* *
* \see mdbx_cursor_unbind() * \see mdbx_cursor_unbind()
* \see mdbx_cursor_close() * \see mdbx_cursor_close()
@ -5309,7 +5303,7 @@ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind
* some possible errors are: * some possible errors are:
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned * \retval MDBX_THREAD_MISMATCH Given transaction is not owned
* by current thread. * by current thread.
* \retval MDBX_BAD_TXN Given transaction is invalid, nested or has * \retval MDBX_BAD_TXN Given transaction is invalid or has
* a child/nested transaction transaction. */ * a child/nested transaction transaction. */
LIBMDBX_INLINE_API(int, mdbx_txn_release_all_cursors, (const MDBX_txn *txn, bool unbind)) { LIBMDBX_INLINE_API(int, mdbx_txn_release_all_cursors, (const MDBX_txn *txn, bool unbind)) {
return mdbx_txn_release_all_cursors_ex(txn, unbind, NULL); return mdbx_txn_release_all_cursors_ex(txn, unbind, NULL);

View File

@ -233,28 +233,43 @@ int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *co
int rc = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); int rc = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD);
if (unlikely(rc != MDBX_SUCCESS)) if (unlikely(rc != MDBX_SUCCESS))
return LOG_IFERR(rc); return LOG_IFERR(rc);
if (unlikely(txn->parent)) {
rc = MDBX_BAD_TXN;
ERROR("%s, err %d", "must not unbind or close cursors for a nested txn", rc);
return rc;
}
size_t n = 0; size_t n = 0;
TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) { do {
while (txn->cursors[i]) { TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) {
++n; MDBX_cursor *mc = txn->cursors[i], *next = nullptr;
MDBX_cursor *mc = txn->cursors[i]; if (mc) {
ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup); txn->cursors[i] = nullptr;
txn->cursors[i] = mc->next; do {
mc->next = mc; next = mc->next;
mc->signature = cur_signature_ready4dispose; if (mc->signature == cur_signature_live) {
cursor_drown((cursor_couple_t *)mc); mc->signature = cur_signature_wait4eot;
if (!unbind) { cursor_drown((cursor_couple_t *)mc);
mc->signature = 0; } else
osal_free(mc); ENSURE(nullptr, mc->signature == cur_signature_wait4eot);
if (mc->backup) {
MDBX_cursor *bk = mc->backup;
mc->next = bk->next;
mc->backup = bk->backup;
mc->backup = nullptr;
bk->signature = 0;
bk = bk->next;
osal_free(bk);
} else {
mc->signature = cur_signature_ready4dispose;
mc->next = mc;
++n;
if (!unbind) {
mc->signature = 0;
osal_free(mc);
}
}
} while ((mc = next) != nullptr);
} }
} }
} txn = txn->parent;
} while (txn);
if (count) if (count)
*count = n; *count = n;
return MDBX_SUCCESS; return MDBX_SUCCESS;