mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-04 17:34:14 +08:00
mdbx: add locking while open/close/drop dbi-handles (avoid dbi-related races).
This avoid races and collisions between threads when opening, closing and deleting DBI-handles. unfortunately, this does not resolve collision in the case an one thread closing the DBI-handle while the another thread performs transaction. Change-Id: I48c3ffb11a8f83739fae1712db3476645f573e09
This commit is contained in:
parent
bd5d092a2b
commit
0f676db491
@ -603,6 +603,7 @@ struct MDBX_env {
|
||||
unsigned me_maxreaders; /* size of the reader table */
|
||||
/* Max MDBX_lockinfo.mti_numreaders of interest to mdbx_env_close() */
|
||||
unsigned me_close_readers;
|
||||
mdbx_fastmutex_t me_dbi_lock;
|
||||
MDBX_dbi me_numdbs; /* number of DBs opened */
|
||||
MDBX_dbi me_maxdbs; /* size of the DB table */
|
||||
mdbx_pid_t me_pid; /* process ID of this env */
|
||||
|
71
src/mdbx.c
71
src/mdbx.c
@ -3814,6 +3814,10 @@ int __cold mdbx_env_create(MDBX_env **penv) {
|
||||
}
|
||||
mdbx_env_setup_limits(env, env->me_os_psize);
|
||||
|
||||
rc = mdbx_fastmutex_init(&env->me_dbi_lock);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
goto bailout;
|
||||
|
||||
VALGRIND_CREATE_MEMPOOL(env, 0, 0);
|
||||
env->me_signature = MDBX_ME_SIGNATURE;
|
||||
*penv = env;
|
||||
@ -4507,6 +4511,7 @@ int __cold mdbx_env_close_ex(MDBX_env *env, int dont_sync) {
|
||||
}
|
||||
|
||||
mdbx_env_close0(env);
|
||||
mdbx_ensure(env, mdbx_fastmutex_destroy(&env->me_dbi_lock) == MDBX_SUCCESS);
|
||||
env->me_signature = 0;
|
||||
free(env);
|
||||
|
||||
@ -9106,7 +9111,8 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
|
||||
}
|
||||
|
||||
/* Fail, if no free slot and max hit */
|
||||
if (unlikely(slot >= txn->mt_env->me_maxdbs))
|
||||
MDBX_env *env = txn->mt_env;
|
||||
if (unlikely(slot >= env->me_maxdbs))
|
||||
return MDBX_DBS_FULL;
|
||||
|
||||
/* Cannot mix named table with some main-table flags */
|
||||
@ -9137,7 +9143,11 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
|
||||
if (unlikely(!namedup))
|
||||
return MDBX_ENOMEM;
|
||||
|
||||
/* FIXME: lock here (to avoid races !!!) */
|
||||
int err = mdbx_fastmutex_acquire(&env->me_dbi_lock);
|
||||
if (unlikely(err != MDBX_SUCCESS)) {
|
||||
free(namedup);
|
||||
return err;
|
||||
}
|
||||
|
||||
unsigned dbflag = DB_NEW | DB_VALID | DB_USRVALID;
|
||||
if (unlikely(rc)) {
|
||||
@ -9165,7 +9175,7 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
|
||||
txn->mt_dbxs[slot].md_cmp = nullptr;
|
||||
txn->mt_dbxs[slot].md_dcmp = nullptr;
|
||||
txn->mt_dbflags[slot] = dbflag;
|
||||
txn->mt_dbiseqs[slot] = (txn->mt_env->me_dbiseqs[slot] += 1);
|
||||
txn->mt_dbiseqs[slot] = (env->me_dbiseqs[slot] += 1);
|
||||
|
||||
txn->mt_dbs[slot] = *(MDBX_db *)data.iov_base;
|
||||
rc = mdbx_dbi_bind(txn, slot, user_flags, keycmp, datacmp);
|
||||
@ -9183,7 +9193,7 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
|
||||
txn->mt_numdbs++;
|
||||
}
|
||||
|
||||
/* FIXME: unlock here (to avoid races !!!) */
|
||||
mdbx_ensure(env, mdbx_fastmutex_release(&env->me_dbi_lock) == MDBX_SUCCESS);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -9218,13 +9228,11 @@ int __cold mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *arg,
|
||||
return mdbx_stat0(txn->mt_env, &txn->mt_dbs[dbi], arg);
|
||||
}
|
||||
|
||||
int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi) {
|
||||
char *ptr;
|
||||
static int mdbx_dbi_close_locked(MDBX_env *env, MDBX_dbi dbi) {
|
||||
if (unlikely(dbi < CORE_DBS || dbi >= env->me_maxdbs))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
/* FIXME: locking to avoid races ? */
|
||||
ptr = env->me_dbxs[dbi].md_name.iov_base;
|
||||
char *ptr = env->me_dbxs[dbi].md_name.iov_base;
|
||||
/* If there was no name, this was already closed */
|
||||
if (unlikely(!ptr))
|
||||
return MDBX_BAD_DBI;
|
||||
@ -9237,6 +9245,18 @@ int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi) {
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi) {
|
||||
if (unlikely(dbi < CORE_DBS || dbi >= env->me_maxdbs))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
int rc = mdbx_fastmutex_acquire(&env->me_dbi_lock);
|
||||
if (likely(rc == MDBX_SUCCESS)) {
|
||||
rc = mdbx_dbi_close_locked(env, dbi);
|
||||
mdbx_ensure(env, mdbx_fastmutex_release(&env->me_dbi_lock) == MDBX_SUCCESS);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int mdbx_dbi_flags(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags) {
|
||||
if (unlikely(!txn || !flags))
|
||||
return MDBX_EINVAL;
|
||||
@ -9344,9 +9364,6 @@ static int mdbx_drop0(MDBX_cursor *mc, int subs) {
|
||||
}
|
||||
|
||||
int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, int del) {
|
||||
MDBX_cursor *mc, *m2;
|
||||
int rc;
|
||||
|
||||
if (unlikely(1 < (unsigned)del || !txn))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
@ -9362,25 +9379,41 @@ int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, int del) {
|
||||
if (unlikely(F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY)))
|
||||
return MDBX_EACCESS;
|
||||
|
||||
rc = mdbx_cursor_open(txn, dbi, &mc);
|
||||
if (unlikely(rc))
|
||||
MDBX_cursor *mc;
|
||||
int rc = mdbx_cursor_open(txn, dbi, &mc);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
/* FIXME: locking to avoid races ? */
|
||||
MDBX_env *env = txn->mt_env;
|
||||
rc = mdbx_fastmutex_acquire(&env->me_dbi_lock);
|
||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||
mdbx_cursor_close(mc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))) {
|
||||
rc = MDBX_EINVAL;
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
if (unlikely(TXN_DBI_CHANGED(txn, dbi))) {
|
||||
rc = MDBX_BAD_DBI;
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
rc = mdbx_drop0(mc, mc->mc_db->md_flags & MDBX_DUPSORT);
|
||||
/* Invalidate the dropped DB's cursors */
|
||||
for (m2 = txn->mt_cursors[dbi]; m2; m2 = m2->mc_next)
|
||||
for (MDBX_cursor *m2 = txn->mt_cursors[dbi]; m2; m2 = m2->mc_next)
|
||||
m2->mc_flags &= ~(C_INITIALIZED | C_EOF);
|
||||
if (unlikely(rc))
|
||||
goto leave;
|
||||
goto bailout;
|
||||
|
||||
/* Can't delete the main DB */
|
||||
if (del && dbi >= CORE_DBS) {
|
||||
rc = mdbx_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, F_SUBDATA);
|
||||
if (likely(!rc)) {
|
||||
txn->mt_dbflags[dbi] = DB_STALE;
|
||||
mdbx_dbi_close(txn->mt_env, dbi);
|
||||
mdbx_dbi_close_locked(env, dbi);
|
||||
} else {
|
||||
txn->mt_flags |= MDBX_TXN_ERROR;
|
||||
}
|
||||
@ -9397,8 +9430,10 @@ int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, int del) {
|
||||
|
||||
txn->mt_flags |= MDBX_TXN_DIRTY;
|
||||
}
|
||||
leave:
|
||||
|
||||
bailout:
|
||||
mdbx_cursor_close(mc);
|
||||
mdbx_ensure(env, mdbx_fastmutex_release(&env->me_dbi_lock) == MDBX_SUCCESS);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user