mdbx: упрощение/выпрямление/рефакторинг txn_end() и затронутых зависимостей.

This commit is contained in:
Леонид Юрьев (Leonid Yuriev) 2025-01-08 13:25:55 +03:00
parent a5bb555db3
commit c60f6afe5f
4 changed files with 75 additions and 72 deletions

View File

@ -356,6 +356,10 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) {
} }
if (unlikely(txn->flags & MDBX_TXN_RDONLY)) { if (unlikely(txn->flags & MDBX_TXN_RDONLY)) {
if (unlikely(txn->parent || (txn->flags & MDBX_TXN_HAS_CHILD) || txn == env->txn || txn == env->basal_txn)) {
ERROR("attempt to commit %s txn %p", "strange read-only", (void *)txn);
return MDBX_PROBLEM;
}
if (txn->flags & MDBX_TXN_ERROR) { if (txn->flags & MDBX_TXN_ERROR) {
rc = MDBX_RESULT_TRUE; rc = MDBX_RESULT_TRUE;
goto fail; goto fail;
@ -383,15 +387,13 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) {
if (unlikely(txn != env->txn)) { if (unlikely(txn != env->txn)) {
ERROR("attempt to commit %s txn %p", "unknown", (void *)txn); ERROR("attempt to commit %s txn %p", "unknown", (void *)txn);
rc = MDBX_EINVAL; return MDBX_EINVAL;
return LOG_IFERR(rc);
} }
if (txn->parent) { if (txn->parent) {
if (unlikely(txn->parent->nested != txn || txn->parent->env != env)) { if (unlikely(txn->parent->nested != txn || txn->parent->env != env)) {
ERROR("attempt to commit %s txn %p", "strange nested", (void *)txn); ERROR("attempt to commit %s txn %p", "strange nested", (void *)txn);
rc = MDBX_PROBLEM; return MDBX_PROBLEM;
return LOG_IFERR(rc);
} }
rc = txn_nested_join(txn, latency ? &ts : nullptr); rc = txn_nested_join(txn, latency ? &ts : nullptr);
if (likely(rc == MDBX_SUCCESS)) if (likely(rc == MDBX_SUCCESS))

View File

@ -176,7 +176,7 @@ int dbi_defer_release(MDBX_env *const env, defer_free_item_t *const chain) {
} }
/* Export or close DBI handles opened in this txn. */ /* Export or close DBI handles opened in this txn. */
int dbi_update(MDBX_txn *txn, int keep) { int dbi_update(MDBX_txn *txn, bool keep) {
MDBX_env *const env = txn->env; MDBX_env *const env = txn->env;
tASSERT(txn, !txn->parent && txn == env->basal_txn); tASSERT(txn, !txn->parent && txn == env->basal_txn);
bool locked = false; bool locked = false;
@ -216,6 +216,7 @@ int dbi_update(MDBX_txn *txn, int keep) {
if (locked) { if (locked) {
size_t i = env->n_dbi; size_t i = env->n_dbi;
eASSERT(env, env->n_dbi >= CORE_DBS);
while ((env->dbs_flags[i - 1] & DB_VALID) == 0) { while ((env->dbs_flags[i - 1] & DB_VALID) == 0) {
--i; --i;
eASSERT(env, i >= CORE_DBS); eASSERT(env, i >= CORE_DBS);

View File

@ -81,7 +81,7 @@ struct dbi_snap_result {
}; };
MDBX_INTERNAL struct dbi_snap_result dbi_snap(const MDBX_env *env, const size_t dbi); MDBX_INTERNAL struct dbi_snap_result dbi_snap(const MDBX_env *env, const size_t dbi);
MDBX_INTERNAL int dbi_update(MDBX_txn *txn, int keep); MDBX_INTERNAL int dbi_update(MDBX_txn *txn, bool keep);
static inline uint8_t dbi_state(const MDBX_txn *txn, const size_t dbi) { static inline uint8_t dbi_state(const MDBX_txn *txn, const size_t dbi) {
STATIC_ASSERT((int)DBI_DIRTY == MDBX_DBI_DIRTY && (int)DBI_STALE == MDBX_DBI_STALE && STATIC_ASSERT((int)DBI_DIRTY == MDBX_DBI_DIRTY && (int)DBI_STALE == MDBX_DBI_STALE &&

View File

@ -893,90 +893,90 @@ static int txn_ro_end(MDBX_txn *txn, unsigned mode) {
} }
int txn_end(MDBX_txn *txn, unsigned mode) { int txn_end(MDBX_txn *txn, unsigned mode) {
MDBX_env *const env = txn->env;
static const char *const names[] = TXN_END_NAMES; static const char *const names[] = TXN_END_NAMES;
DEBUG("%s txn %" PRIaTXN "%c-0x%X %p on env %p, root page %" PRIaPGNO "/%" PRIaPGNO, names[mode & TXN_END_OPMASK], DEBUG("%s txn %" PRIaTXN "%c-0x%X %p on env %p, root page %" PRIaPGNO "/%" PRIaPGNO, names[mode & TXN_END_OPMASK],
txn->txnid, (txn->flags & MDBX_TXN_RDONLY) ? 'r' : 'w', txn->flags, (void *)txn, (void *)env, txn->txnid, (txn->flags & MDBX_TXN_RDONLY) ? 'r' : 'w', txn->flags, (void *)txn, (void *)txn->env,
txn->dbs[MAIN_DBI].root, txn->dbs[FREE_DBI].root); txn->dbs[MAIN_DBI].root, txn->dbs[FREE_DBI].root);
tASSERT(txn, txn->signature == txn_signature && !txn->nested && !(txn->flags & MDBX_TXN_HAS_CHILD));
if (txn->flags & txn_may_have_cursors) { if (txn->flags & txn_may_have_cursors) {
txn->flags |= /* avoid merge cursors' state */ MDBX_TXN_ERROR; txn->flags |= /* avoid merge cursors' state */ MDBX_TXN_ERROR;
txn_done_cursors(txn); txn_done_cursors(txn);
} }
if (txn->flags & MDBX_TXN_RDONLY) MDBX_env *const env = txn->env;
return txn_ro_end(txn, mode); MDBX_txn *const parent = txn->parent;
if (txn == env->basal_txn) {
tASSERT(txn, !parent && !(txn->flags & MDBX_TXN_RDONLY));
tASSERT(txn, (txn->flags & MDBX_TXN_FINISHED) == 0 && txn->owner);
if (unlikely(txn->flags & MDBX_TXN_FINISHED))
return MDBX_SUCCESS;
int rc = MDBX_SUCCESS; ENSURE(env, txn->txnid >= /* paranoia is appropriate here */ env->lck->cached_oldest.weak);
if (!(txn->flags & MDBX_TXN_FINISHED)) {
ENSURE(env, txn->txnid >=
/* paranoia is appropriate here */ env->lck->cached_oldest.weak);
if (txn == env->basal_txn)
dxb_sanitize_tail(env, nullptr); dxb_sanitize_tail(env, nullptr);
MDBX_txn *const parent = txn->parent;
txn->flags = MDBX_TXN_FINISHED; txn->flags = MDBX_TXN_FINISHED;
env->txn = parent; env->txn = nullptr;
pnl_free(txn->tw.spilled.list); pnl_free(txn->tw.spilled.list);
txn->tw.spilled.list = nullptr; txn->tw.spilled.list = nullptr;
if (txn == env->basal_txn) {
eASSERT(env, txn->parent == nullptr); eASSERT(env, txn->parent == nullptr);
/* Export or close DBI handles created in this txn */
rc = dbi_update(txn, mode & TXN_END_UPDATE);
pnl_shrink(&txn->tw.retired_pages); pnl_shrink(&txn->tw.retired_pages);
pnl_shrink(&txn->tw.repnl); pnl_shrink(&txn->tw.repnl);
if (!(env->flags & MDBX_WRITEMAP)) if (!(env->flags & MDBX_WRITEMAP))
dpl_release_shadows(txn); dpl_release_shadows(txn);
/* Export or close DBI handles created in this txn */
int err = dbi_update(txn, (mode & TXN_END_UPDATE) != 0);
if (unlikely(err != MDBX_SUCCESS)) {
ERROR("unexpected error %d during export the state of dbi-handles to env", err);
err = MDBX_PROBLEM;
}
/* The writer mutex was locked in mdbx_txn_begin. */ /* The writer mutex was locked in mdbx_txn_begin. */
lck_txn_unlock(env); lck_txn_unlock(env);
} else { return err;
if (unlikely(!parent || parent->signature != txn_signature || parent->nested != txn || }
!(parent->flags & MDBX_TXN_HAS_CHILD))) {
if (txn->flags & MDBX_TXN_RDONLY) {
tASSERT(txn, txn != env->txn && !parent);
return txn_ro_end(txn, mode);
}
if (unlikely(!parent || txn != env->txn || parent->signature != txn_signature || parent->nested != txn ||
!(parent->flags & MDBX_TXN_HAS_CHILD) || txn == env->basal_txn)) {
ERROR("parent txn %p is invalid or mismatch for nested txn %p", (void *)parent, (void *)txn); ERROR("parent txn %p is invalid or mismatch for nested txn %p", (void *)parent, (void *)txn);
return MDBX_PROBLEM; return MDBX_PROBLEM;
} }
tASSERT(txn, pnl_check_allocated(txn->tw.repnl, txn->geo.first_unallocated - MDBX_ENABLE_REFUND)); tASSERT(txn, pnl_check_allocated(txn->tw.repnl, txn->geo.first_unallocated - MDBX_ENABLE_REFUND));
tASSERT(txn, memcmp(&txn->tw.troika, &parent->tw.troika, sizeof(troika_t)) == 0); tASSERT(txn, memcmp(&txn->tw.troika, &parent->tw.troika, sizeof(troika_t)) == 0);
tASSERT(txn, mode & TXN_END_FREE); tASSERT(txn, mode & TXN_END_FREE);
env->txn = parent;
const pgno_t nested_now = txn->geo.now, nested_upper = txn->geo.upper;
txn_nested_abort(txn);
const bool need_undo_resize = (parent->geo.upper != txn->geo.upper || parent->geo.now != txn->geo.now) && if (unlikely(parent->geo.upper != nested_upper || parent->geo.now != nested_now) &&
!(parent->flags & MDBX_TXN_ERROR) && !(env->flags & ENV_FATAL_ERROR); !(parent->flags & MDBX_TXN_ERROR) && !(env->flags & ENV_FATAL_ERROR)) {
if (need_undo_resize) { /* undo resize performed by nested txn */
/* undo resize performed by child txn */ int err = dxb_resize(env, parent->geo.first_unallocated, parent->geo.now, parent->geo.upper, impilict_shrink);
rc = dxb_resize(env, parent->geo.first_unallocated, parent->geo.now, parent->geo.upper, impilict_shrink); if (err == MDBX_EPERM) {
if (rc == MDBX_EPERM) {
/* unable undo resize (it is regular for Windows), /* unable undo resize (it is regular for Windows),
* therefore promote size changes from child to the parent txn */ * therefore promote size changes from nested to the parent txn */
WARNING("unable undo resize performed by child txn, promote to " WARNING("unable undo resize performed by nested txn, promote to "
"the parent (%u->%u, %u->%u)", "the parent (%u->%u, %u->%u)",
txn->geo.now, parent->geo.now, txn->geo.upper, parent->geo.upper); nested_now, parent->geo.now, nested_upper, parent->geo.upper);
parent->geo.now = txn->geo.now; parent->geo.now = nested_now;
parent->geo.upper = txn->geo.upper;
parent->flags |= MDBX_TXN_DIRTY; parent->flags |= MDBX_TXN_DIRTY;
rc = MDBX_SUCCESS; } else if (unlikely(err != MDBX_SUCCESS)) {
} else if (unlikely(rc != MDBX_SUCCESS)) { ERROR("error %d while undo resize performed by nested txn, fail the parent", err);
ERROR("error %d while undo resize performed by child txn, fail " mdbx_txn_break(env->basal_txn);
"the parent",
rc);
parent->flags |= MDBX_TXN_ERROR; parent->flags |= MDBX_TXN_ERROR;
if (!env->dxb_mmap.base) if (!env->dxb_mmap.base)
env->flags |= ENV_FATAL_ERROR; env->flags |= ENV_FATAL_ERROR;
return err;
} }
} }
txn_nested_abort(txn); return MDBX_SUCCESS;
return rc;
}
}
eASSERT(env, txn == env->basal_txn || txn->owner == 0);
if ((mode & TXN_END_FREE) != 0 && txn != env->basal_txn) {
txn->signature = 0;
osal_free(txn);
}
return rc;
} }
int txn_check_badbits_parked(const MDBX_txn *txn, int bad_bits) { int txn_check_badbits_parked(const MDBX_txn *txn, int bad_bits) {