mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-02 00:54:14 +08:00
mdbx: rework open/import/export of DBI-handles for robustness
Resolve https://github.com/erthink/libmdbx/issues/146 Change-Id: Idd18dc0d038eeba47668983ecf4ff46eabd16de5
This commit is contained in:
parent
166ed1c7d4
commit
cda64ca663
102
src/core.c
102
src/core.c
@ -6816,8 +6816,45 @@ int mdbx_txn_flags(const MDBX_txn *txn) {
|
||||
return txn->mt_flags;
|
||||
}
|
||||
|
||||
/* Check for misused dbi handles */
|
||||
#define TXN_DBI_CHANGED(txn, dbi) \
|
||||
((txn)->mt_dbiseqs[dbi] != (txn)->mt_env->me_dbiseqs[dbi])
|
||||
|
||||
static void dbi_import_locked(MDBX_txn *txn) {
|
||||
MDBX_env *const env = txn->mt_env;
|
||||
const unsigned n = env->me_numdbs;
|
||||
for (unsigned i = CORE_DBS; i < n; ++i) {
|
||||
if (i >= txn->mt_numdbs) {
|
||||
txn->mt_dbistate[i] = 0;
|
||||
if (!(txn->mt_flags & MDBX_TXN_RDONLY))
|
||||
txn->tw.cursors[i] = NULL;
|
||||
}
|
||||
if ((env->me_dbflags[i] & DB_VALID) &&
|
||||
!(txn->mt_dbistate[i] & DBI_USRVALID)) {
|
||||
txn->mt_dbiseqs[i] = env->me_dbiseqs[i];
|
||||
txn->mt_dbs[i].md_flags = env->me_dbflags[i] & DB_PERSISTENT_FLAGS;
|
||||
txn->mt_dbistate[i] = DBI_VALID | DBI_USRVALID | DBI_STALE;
|
||||
mdbx_tassert(txn, txn->mt_dbxs[i].md_cmp != NULL);
|
||||
}
|
||||
}
|
||||
txn->mt_numdbs = n;
|
||||
}
|
||||
|
||||
/* Import DBI which opened after txn started into context */
|
||||
static __cold bool dbi_import(MDBX_txn *txn, MDBX_dbi dbi) {
|
||||
if (dbi < CORE_DBS || dbi >= txn->mt_env->me_numdbs)
|
||||
return false;
|
||||
|
||||
mdbx_ensure(txn->mt_env, mdbx_fastmutex_acquire(&txn->mt_env->me_dbi_lock) ==
|
||||
MDBX_SUCCESS);
|
||||
dbi_import_locked(txn);
|
||||
mdbx_ensure(txn->mt_env, mdbx_fastmutex_release(&txn->mt_env->me_dbi_lock) ==
|
||||
MDBX_SUCCESS);
|
||||
return txn->mt_dbistate[dbi] & DBI_USRVALID;
|
||||
}
|
||||
|
||||
/* Export or close DBI handles opened in this txn. */
|
||||
static void mdbx_dbis_update(MDBX_txn *txn, int keep) {
|
||||
static void dbi_update(MDBX_txn *txn, int keep) {
|
||||
mdbx_tassert(txn, !txn->mt_parent && txn == txn->mt_env->me_txn0);
|
||||
MDBX_dbi n = txn->mt_numdbs;
|
||||
if (n) {
|
||||
@ -6931,7 +6968,7 @@ static int mdbx_txn_end(MDBX_txn *txn, unsigned mode) {
|
||||
if (txn == env->me_txn0) {
|
||||
mdbx_assert(env, txn->mt_parent == NULL);
|
||||
/* Export or close DBI handles created in this txn */
|
||||
mdbx_dbis_update(txn, mode & MDBX_END_UPDATE);
|
||||
dbi_update(txn, mode & MDBX_END_UPDATE);
|
||||
mdbx_pnl_shrink(&txn->tw.retired_pages);
|
||||
mdbx_pnl_shrink(&txn->tw.reclaimed_pglist);
|
||||
/* The writer mutex was locked in mdbx_txn_begin. */
|
||||
@ -8032,42 +8069,13 @@ __hot static int mdbx_page_flush(MDBX_txn *txn, const unsigned keep) {
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Check for misused dbi handles */
|
||||
#define TXN_DBI_CHANGED(txn, dbi) \
|
||||
((txn)->mt_dbiseqs[dbi] != (txn)->mt_env->me_dbiseqs[dbi])
|
||||
|
||||
/* Import DBI which opened after txn started into context */
|
||||
static __cold bool mdbx_txn_import_dbi(MDBX_txn *txn, MDBX_dbi dbi) {
|
||||
MDBX_env *env = txn->mt_env;
|
||||
if (dbi < CORE_DBS || dbi >= env->me_numdbs)
|
||||
return false;
|
||||
|
||||
mdbx_ensure(env, mdbx_fastmutex_acquire(&env->me_dbi_lock) == MDBX_SUCCESS);
|
||||
const unsigned snap_numdbs = env->me_numdbs;
|
||||
mdbx_compiler_barrier();
|
||||
for (unsigned i = CORE_DBS; i < snap_numdbs; ++i) {
|
||||
if (i >= txn->mt_numdbs)
|
||||
txn->mt_dbistate[i] = 0;
|
||||
if (!(txn->mt_dbistate[i] & DBI_USRVALID) &&
|
||||
(env->me_dbflags[i] & DB_VALID)) {
|
||||
txn->mt_dbs[i].md_flags = env->me_dbflags[i] & DB_PERSISTENT_FLAGS;
|
||||
txn->mt_dbistate[i] = DBI_VALID | DBI_USRVALID | DBI_STALE;
|
||||
mdbx_tassert(txn, txn->mt_dbxs[i].md_cmp != NULL);
|
||||
}
|
||||
}
|
||||
txn->mt_numdbs = snap_numdbs;
|
||||
|
||||
mdbx_ensure(env, mdbx_fastmutex_release(&env->me_dbi_lock) == MDBX_SUCCESS);
|
||||
return txn->mt_dbistate[dbi] & DBI_USRVALID;
|
||||
}
|
||||
|
||||
/* Check txn and dbi arguments to a function */
|
||||
static __always_inline bool mdbx_txn_dbi_exists(MDBX_txn *txn, MDBX_dbi dbi,
|
||||
unsigned validity) {
|
||||
if (likely(dbi < txn->mt_numdbs && (txn->mt_dbistate[dbi] & validity)))
|
||||
return true;
|
||||
|
||||
return mdbx_txn_import_dbi(txn, dbi);
|
||||
return dbi_import(txn, dbi);
|
||||
}
|
||||
|
||||
int mdbx_txn_commit(MDBX_txn *txn) { return __inline_mdbx_txn_commit(txn); }
|
||||
@ -17533,18 +17541,8 @@ static int dbi_open(MDBX_txn *txn, const char *table_name, unsigned user_flags,
|
||||
goto early_bailout;
|
||||
}
|
||||
|
||||
if (txn->mt_numdbs < env->me_numdbs) {
|
||||
/* Import handles from env */
|
||||
for (unsigned i = txn->mt_numdbs; i < env->me_numdbs; ++i) {
|
||||
txn->mt_dbistate[i] = 0;
|
||||
if (env->me_dbflags[i] & DB_VALID) {
|
||||
txn->mt_dbs[i].md_flags = env->me_dbflags[i] & DB_PERSISTENT_FLAGS;
|
||||
txn->mt_dbistate[i] = DBI_VALID | DBI_USRVALID | DBI_STALE;
|
||||
mdbx_tassert(txn, txn->mt_dbxs[i].md_cmp != NULL);
|
||||
}
|
||||
}
|
||||
txn->mt_numdbs = env->me_numdbs;
|
||||
}
|
||||
/* Import handles from env */
|
||||
dbi_import_locked(txn);
|
||||
|
||||
/* Rescan after mutex acquisition & import handles */
|
||||
for (slot = scan = txn->mt_numdbs; --scan >= CORE_DBS;) {
|
||||
@ -17604,18 +17602,16 @@ static int dbi_open(MDBX_txn *txn, const char *table_name, unsigned user_flags,
|
||||
txn->mt_dbistate[slot] = (uint8_t)dbiflags;
|
||||
txn->mt_dbxs[slot].md_name.iov_base = namedup;
|
||||
txn->mt_dbxs[slot].md_name.iov_len = len;
|
||||
if ((txn->mt_flags & MDBX_TXN_RDONLY) == 0)
|
||||
txn->tw.cursors[slot] = NULL;
|
||||
txn->mt_numdbs += (slot == txn->mt_numdbs);
|
||||
if ((dbiflags & DBI_CREAT) == 0) {
|
||||
txn->mt_dbiseqs[slot] = ++env->me_dbiseqs[slot];
|
||||
if (!(dbiflags & DBI_CREAT))
|
||||
env->me_dbflags[slot] = txn->mt_dbs[slot].md_flags | DB_VALID;
|
||||
if (txn->mt_numdbs == slot) {
|
||||
mdbx_compiler_barrier();
|
||||
if (env->me_numdbs <= slot)
|
||||
env->me_numdbs = slot + 1;
|
||||
} else {
|
||||
env->me_dbiseqs[slot]++;
|
||||
txn->mt_numdbs = env->me_numdbs = slot + 1;
|
||||
if (!(txn->mt_flags & MDBX_TXN_RDONLY))
|
||||
txn->tw.cursors[slot] = NULL;
|
||||
}
|
||||
txn->mt_dbiseqs[slot] = env->me_dbiseqs[slot];
|
||||
mdbx_assert(env, env->me_numdbs > slot);
|
||||
*dbi = slot;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user