mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-20 00:48:20 +08:00
mdbx: упрощение/выпрямление/рефакторинг txn_end()
и затронутых зависимостей.
This commit is contained in:
parent
a5bb555db3
commit
c60f6afe5f
@ -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))
|
||||||
|
@ -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);
|
||||||
|
@ -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 &&
|
||||||
|
92
src/txn.c
92
src/txn.c
@ -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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user