mirror of
https://github.com/isar/libmdbx.git
synced 2025-05-12 16:27:46 +08:00
mdbx: упрощение старта транзакций и исправление возможности double-free при ошибке создания вложенной транзакции.
This commit is contained in:
parent
7db9c40fe0
commit
6627d14edf
@ -235,9 +235,11 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, M
|
|||||||
flags |= parent->flags & (txn_rw_begin_flags | MDBX_TXN_SPILLS | MDBX_NOSTICKYTHREADS | MDBX_WRITEMAP);
|
flags |= parent->flags & (txn_rw_begin_flags | MDBX_TXN_SPILLS | MDBX_NOSTICKYTHREADS | MDBX_WRITEMAP);
|
||||||
rc = txn_nested_create(parent, flags);
|
rc = txn_nested_create(parent, flags);
|
||||||
txn = parent->nested;
|
txn = parent->nested;
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||||
txn_end(txn, TXN_END_FAIL_BEGIN_NESTED);
|
int err = txn_end(txn, TXN_END_FAIL_BEGIN_NESTED);
|
||||||
else if (AUDIT_ENABLED() && ASSERT_ENABLED()) {
|
return err ? err : rc;
|
||||||
|
}
|
||||||
|
if (AUDIT_ENABLED() && ASSERT_ENABLED()) {
|
||||||
txn->signature = txn_signature;
|
txn->signature = txn_signature;
|
||||||
tASSERT(txn, audit_ex(txn, 0, false) == 0);
|
tASSERT(txn, audit_ex(txn, 0, false) == 0);
|
||||||
}
|
}
|
||||||
@ -249,31 +251,30 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, M
|
|||||||
return LOG_IFERR(MDBX_ENOMEM);
|
return LOG_IFERR(MDBX_ENOMEM);
|
||||||
}
|
}
|
||||||
rc = txn_renew(txn, flags);
|
rc = txn_renew(txn, flags);
|
||||||
}
|
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||||
|
if (txn != env->basal_txn)
|
||||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
osal_free(txn);
|
||||||
if (txn != env->basal_txn)
|
return LOG_IFERR(rc);
|
||||||
osal_free(txn);
|
|
||||||
} else {
|
|
||||||
if (flags & (MDBX_TXN_RDONLY_PREPARE - MDBX_TXN_RDONLY))
|
|
||||||
eASSERT(env, txn->flags == (MDBX_TXN_RDONLY | MDBX_TXN_FINISHED));
|
|
||||||
else if (flags & MDBX_TXN_RDONLY)
|
|
||||||
eASSERT(env, (txn->flags & ~(MDBX_NOSTICKYTHREADS | MDBX_TXN_RDONLY | MDBX_WRITEMAP |
|
|
||||||
/* Win32: SRWL flag */ txn_shrink_allowed)) == 0);
|
|
||||||
else {
|
|
||||||
eASSERT(env, (txn->flags & ~(MDBX_NOSTICKYTHREADS | MDBX_WRITEMAP | txn_shrink_allowed | txn_may_have_cursors |
|
|
||||||
MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC | MDBX_TXN_SPILLS)) == 0);
|
|
||||||
assert(!txn->wr.spilled.list && !txn->wr.spilled.least_removed);
|
|
||||||
}
|
}
|
||||||
txn->signature = txn_signature;
|
|
||||||
txn->userctx = context;
|
|
||||||
*ret = txn;
|
|
||||||
DEBUG("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO "/%" PRIaPGNO, txn->txnid,
|
|
||||||
(flags & MDBX_TXN_RDONLY) ? 'r' : 'w', (void *)txn, (void *)env, txn->dbs[MAIN_DBI].root,
|
|
||||||
txn->dbs[FREE_DBI].root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return LOG_IFERR(rc);
|
if (flags & (MDBX_TXN_RDONLY_PREPARE - MDBX_TXN_RDONLY))
|
||||||
|
eASSERT(env, txn->flags == (MDBX_TXN_RDONLY | MDBX_TXN_FINISHED));
|
||||||
|
else if (flags & MDBX_TXN_RDONLY)
|
||||||
|
eASSERT(env, (txn->flags & ~(MDBX_NOSTICKYTHREADS | MDBX_TXN_RDONLY | MDBX_WRITEMAP |
|
||||||
|
/* Win32: SRWL flag */ txn_shrink_allowed)) == 0);
|
||||||
|
else {
|
||||||
|
eASSERT(env, (txn->flags & ~(MDBX_NOSTICKYTHREADS | MDBX_WRITEMAP | txn_shrink_allowed | txn_may_have_cursors |
|
||||||
|
MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC | MDBX_TXN_SPILLS)) == 0);
|
||||||
|
assert(!txn->wr.spilled.list && !txn->wr.spilled.least_removed);
|
||||||
|
}
|
||||||
|
txn->signature = txn_signature;
|
||||||
|
txn->userctx = context;
|
||||||
|
*ret = txn;
|
||||||
|
DEBUG("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO "/%" PRIaPGNO, txn->txnid,
|
||||||
|
(flags & MDBX_TXN_RDONLY) ? 'r' : 'w', (void *)txn, (void *)env, txn->dbs[MAIN_DBI].root,
|
||||||
|
txn->dbs[FREE_DBI].root);
|
||||||
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void latency_gcprof(MDBX_commit_latency *latency, const MDBX_txn *txn) {
|
static void latency_gcprof(MDBX_commit_latency *latency, const MDBX_txn *txn) {
|
||||||
|
@ -348,25 +348,30 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) {
|
|||||||
return LOG_IFERR(MDBX_ENOMEM);
|
return LOG_IFERR(MDBX_ENOMEM);
|
||||||
|
|
||||||
tASSERT(parent, dpl_check(parent));
|
tASSERT(parent, dpl_check(parent));
|
||||||
|
txn->txnid = parent->txnid;
|
||||||
|
txn->front_txnid = parent->front_txnid + 1;
|
||||||
|
txn->canary = parent->canary;
|
||||||
|
parent->flags |= MDBX_TXN_HAS_CHILD;
|
||||||
|
parent->nested = txn;
|
||||||
|
txn->parent = parent;
|
||||||
|
txn->env->txn = txn;
|
||||||
|
txn->owner = parent->owner;
|
||||||
|
txn->wr.troika = parent->wr.troika;
|
||||||
|
|
||||||
#if MDBX_ENABLE_DBI_SPARSE
|
#if MDBX_ENABLE_DBI_SPARSE
|
||||||
txn->dbi_sparse = parent->dbi_sparse;
|
txn->dbi_sparse = parent->dbi_sparse;
|
||||||
#endif /* MDBX_ENABLE_DBI_SPARSE */
|
#endif /* MDBX_ENABLE_DBI_SPARSE */
|
||||||
txn->dbi_seqs = parent->dbi_seqs;
|
txn->dbi_seqs = parent->dbi_seqs;
|
||||||
txn->geo = parent->geo;
|
txn->geo = parent->geo;
|
||||||
|
|
||||||
int err = dpl_alloc(txn);
|
int err = dpl_alloc(txn);
|
||||||
if (likely(err == MDBX_SUCCESS)) {
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
const size_t len = MDBX_PNL_GETSIZE(parent->wr.repnl) + parent->wr.loose_count;
|
|
||||||
txn->wr.repnl = pnl_alloc((len > MDBX_PNL_INITIAL) ? len : MDBX_PNL_INITIAL);
|
|
||||||
if (unlikely(!txn->wr.repnl))
|
|
||||||
err = MDBX_ENOMEM;
|
|
||||||
}
|
|
||||||
if (unlikely(err != MDBX_SUCCESS)) {
|
|
||||||
failed:
|
|
||||||
pnl_free(txn->wr.repnl);
|
|
||||||
dpl_free(txn);
|
|
||||||
osal_free(txn);
|
|
||||||
return LOG_IFERR(err);
|
return LOG_IFERR(err);
|
||||||
}
|
|
||||||
|
const size_t len = MDBX_PNL_GETSIZE(parent->wr.repnl) + parent->wr.loose_count;
|
||||||
|
txn->wr.repnl = pnl_alloc((len > MDBX_PNL_INITIAL) ? len : MDBX_PNL_INITIAL);
|
||||||
|
if (unlikely(!txn->wr.repnl))
|
||||||
|
return LOG_IFERR(MDBX_ENOMEM);
|
||||||
|
|
||||||
/* Move loose pages to reclaimed list */
|
/* Move loose pages to reclaimed list */
|
||||||
if (parent->wr.loose_count) {
|
if (parent->wr.loose_count) {
|
||||||
@ -375,7 +380,7 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) {
|
|||||||
tASSERT(parent, lp->flags == P_LOOSE);
|
tASSERT(parent, lp->flags == P_LOOSE);
|
||||||
err = pnl_insert_span(&parent->wr.repnl, lp->pgno, 1);
|
err = pnl_insert_span(&parent->wr.repnl, lp->pgno, 1);
|
||||||
if (unlikely(err != MDBX_SUCCESS))
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
goto failed;
|
return LOG_IFERR(err);
|
||||||
MDBX_ASAN_UNPOISON_MEMORY_REGION(&page_next(lp), sizeof(page_t *));
|
MDBX_ASAN_UNPOISON_MEMORY_REGION(&page_next(lp), sizeof(page_t *));
|
||||||
VALGRIND_MAKE_MEM_DEFINED(&page_next(lp), sizeof(page_t *));
|
VALGRIND_MAKE_MEM_DEFINED(&page_next(lp), sizeof(page_t *));
|
||||||
parent->wr.loose_pages = page_next(lp);
|
parent->wr.loose_pages = page_next(lp);
|
||||||
@ -388,6 +393,9 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) {
|
|||||||
#endif /* MDBX_ENABLE_REFUND */
|
#endif /* MDBX_ENABLE_REFUND */
|
||||||
tASSERT(parent, dpl_check(parent));
|
tASSERT(parent, dpl_check(parent));
|
||||||
}
|
}
|
||||||
|
#if MDBX_ENABLE_REFUND
|
||||||
|
txn->wr.loose_refund_wl = 0;
|
||||||
|
#endif /* MDBX_ENABLE_REFUND */
|
||||||
txn->wr.dirtyroom = parent->wr.dirtyroom;
|
txn->wr.dirtyroom = parent->wr.dirtyroom;
|
||||||
txn->wr.dirtylru = parent->wr.dirtylru;
|
txn->wr.dirtylru = parent->wr.dirtylru;
|
||||||
|
|
||||||
@ -412,18 +420,6 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) {
|
|||||||
txn->wr.retired_pages = parent->wr.retired_pages;
|
txn->wr.retired_pages = parent->wr.retired_pages;
|
||||||
parent->wr.retired_pages = (void *)(intptr_t)MDBX_PNL_GETSIZE(parent->wr.retired_pages);
|
parent->wr.retired_pages = (void *)(intptr_t)MDBX_PNL_GETSIZE(parent->wr.retired_pages);
|
||||||
|
|
||||||
txn->txnid = parent->txnid;
|
|
||||||
txn->front_txnid = parent->front_txnid + 1;
|
|
||||||
#if MDBX_ENABLE_REFUND
|
|
||||||
txn->wr.loose_refund_wl = 0;
|
|
||||||
#endif /* MDBX_ENABLE_REFUND */
|
|
||||||
txn->canary = parent->canary;
|
|
||||||
parent->flags |= MDBX_TXN_HAS_CHILD;
|
|
||||||
parent->nested = txn;
|
|
||||||
txn->parent = parent;
|
|
||||||
txn->owner = parent->owner;
|
|
||||||
txn->wr.troika = parent->wr.troika;
|
|
||||||
|
|
||||||
txn->cursors[FREE_DBI] = nullptr;
|
txn->cursors[FREE_DBI] = nullptr;
|
||||||
txn->cursors[MAIN_DBI] = nullptr;
|
txn->cursors[MAIN_DBI] = nullptr;
|
||||||
txn->dbi_state[FREE_DBI] = parent->dbi_state[FREE_DBI] & ~(DBI_FRESH | DBI_CREAT | DBI_DIRTY);
|
txn->dbi_state[FREE_DBI] = parent->dbi_state[FREE_DBI] & ~(DBI_FRESH | DBI_CREAT | DBI_DIRTY);
|
||||||
@ -435,7 +431,6 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) {
|
|||||||
(parent->parent ? parent->parent->wr.dirtyroom : parent->env->options.dp_limit));
|
(parent->parent ? parent->parent->wr.dirtyroom : parent->env->options.dp_limit));
|
||||||
tASSERT(txn, txn->wr.dirtyroom + txn->wr.dirtylist->length ==
|
tASSERT(txn, txn->wr.dirtyroom + txn->wr.dirtylist->length ==
|
||||||
(txn->parent ? txn->parent->wr.dirtyroom : txn->env->options.dp_limit));
|
(txn->parent ? txn->parent->wr.dirtyroom : txn->env->options.dp_limit));
|
||||||
parent->env->txn = txn;
|
|
||||||
tASSERT(parent, parent->cursors[FREE_DBI] == nullptr);
|
tASSERT(parent, parent->cursors[FREE_DBI] == nullptr);
|
||||||
return txn_shadow_cursors(parent, MAIN_DBI);
|
return txn_shadow_cursors(parent, MAIN_DBI);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user