mdbx: add MDBX_ACCEDE environment opening flag.

Change-Id: If0a08d6fce127f35ff2992988715b7dc1fdb70a9
This commit is contained in:
Leonid Yuriev 2019-11-14 20:45:39 +03:00
parent cb8fac6f5f
commit 42d9e06598
5 changed files with 79 additions and 36 deletions

16
mdbx.h
View File

@ -921,6 +921,22 @@ LIBMDBX_API const char *mdbx_dump_val(const MDBX_val *key, char *const buf,
* This flag affects only at environment opening but can't be changed after. */
#define MDBX_EXCLUSIVE 0x400000u
/* MDBX_ACCEDE = using database which already opened by another process(es).
*
* The MDBX_ACCEDE flag avoid MDBX_INCOMPATIBLE error while opening If the
* database is already used by another process(es) and environment mode/flags
* isn't compatible. In such cases, when using the MDBX_ACCEDE flag, instead of
* the specified incompatible options, the mode in which the database is already
* opened by other processes will be used, including MDBX_LIFORECLAIM,
* MDBX_COALESCE and MDBX_NORDAHEAD. The MDBX_ACCEDE flag is useful to open a
* database that already used by another process(es) and used mode/flags isn't
* known.
*
* MDBX_ACCEDE has no effect if the current process is the only one either
* opening the DB in read-only mode or other process(es) uses the DB in
* read-only mode. */
#define MDBX_ACCEDE 0x40000000u
/* MDBX_WRITEMAP = map data into memory with write permission.
*
* Use a writeable memory map unless MDBX_RDONLY is set. This uses fewer mallocs

View File

@ -4666,6 +4666,8 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
STATIC_ASSERT(offsetof(MDBX_lockinfo, mti_readers) % MDBX_CACHELINE_SIZE ==
0);
mdbx_assert(env, (flags & ~(MDBX_TXN_BEGIN_FLAGS | MDBX_TXN_SPILLS |
MDBX_WRITEMAP)) == 0);
if (flags & MDBX_RDONLY) {
txn->mt_flags = MDBX_RDONLY | (env->me_flags & MDBX_NOTLS);
MDBX_reader *r = txn->to.reader;
@ -5018,8 +5020,7 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
return MDBX_EPERM;
#endif /* Windows */
flags |= parent->mt_flags &
(MDBX_TXN_BEGIN_FLAGS | MDBX_SHRINK_ALLOWED | MDBX_TXN_SPILLS);
flags |= parent->mt_flags & (MDBX_TXN_BEGIN_FLAGS | MDBX_TXN_SPILLS);
/* Child txns save MDBX_pgstate and use own copy of cursors */
size = env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + 1);
size += tsize = sizeof(MDBX_txn);
@ -6515,7 +6516,7 @@ int mdbx_txn_commit(MDBX_txn *txn) {
parent->mt_geo = txn->mt_geo;
parent->mt_canary = txn->mt_canary;
parent->mt_flags = txn->mt_flags;
parent->mt_flags = txn->mt_flags | (parent->mt_flags & MDBX_SHRINK_ALLOWED);
/* Merge our cursors into parent's and close them */
mdbx_cursors_eot(txn, 1);
@ -8660,7 +8661,7 @@ __cold int mdbx_is_readahead_reasonable(size_t volume, intptr_t redundancy) {
* environment and re-opening it with the new flags. */
#define CHANGEABLE \
(MDBX_NOSYNC | MDBX_NOMETASYNC | MDBX_MAPASYNC | MDBX_NOMEMINIT | \
MDBX_COALESCE | MDBX_PAGEPERTURB)
MDBX_COALESCE | MDBX_PAGEPERTURB | MDBX_ACCEDE)
#define CHANGELESS \
(MDBX_NOSUBDIR | MDBX_RDONLY | MDBX_WRITEMAP | MDBX_NOTLS | MDBX_NORDAHEAD | \
MDBX_LIFORECLAIM | MDBX_EXCLUSIVE)
@ -8711,17 +8712,21 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
/* LY: silently ignore irrelevant flags when
* we're only getting read access */
flags &= ~(MDBX_WRITEMAP | MDBX_MAPASYNC | MDBX_NOSYNC | MDBX_NOMETASYNC |
MDBX_COALESCE | MDBX_LIFORECLAIM | MDBX_NOMEMINIT);
MDBX_COALESCE | MDBX_LIFORECLAIM | MDBX_NOMEMINIT | MDBX_ACCEDE);
} else {
#ifdef __OpenBSD__
/* Temporary `workaround` for OpenBSD kernel's bug.
* See https://github.com/leo-yuriev/libmdbx/issues/67 */
if ((flags & MDBX_WRITEMAP) == 0) {
mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__,
"OpenBSD requires MDBX_WRITEMAP because of an internal "
"bug(s) in a file/buffer/page cache.\n");
rc = 42 /* ENOPROTOOPT */;
goto bailout;
if (flags & MDBX_ACCEDE)
flags |= MDBX_WRITEMAP;
else {
mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__,
"OpenBSD requires MDBX_WRITEMAP because of an internal "
"bug(s) in a file/buffer/page cache.\n");
rc = 42 /* ENOPROTOOPT */;
goto bailout;
}
}
#endif /* __OpenBSD__ */
env->me_dirtylist = mdbx_calloc(MDBX_DPL_TXNFULL + 1, sizeof(MDBX_DP));
@ -8793,6 +8798,36 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
goto bailout;
}
const unsigned rigorous_flags = MDBX_WRITEMAP | MDBX_NOSYNC | MDBX_MAPASYNC;
const unsigned mode_flags = rigorous_flags | MDBX_NOMETASYNC |
MDBX_LIFORECLAIM | MDBX_COALESCE | MDBX_NORDAHEAD;
if (env->me_lck && lck_rc != MDBX_RESULT_TRUE &&
(env->me_flags & MDBX_RDONLY) == 0) {
while (env->me_lck->mti_envmode == MDBX_RDONLY) {
if (atomic_cas32(&env->me_lck->mti_envmode, MDBX_RDONLY,
env->me_flags & mode_flags))
break;
atomic_yield();
}
if (env->me_flags & MDBX_ACCEDE) {
/* pickup current mode-flags, including MDBX_LIFORECLAIM |
* MDBX_COALESCE | MDBX_NORDAHEAD */
const unsigned diff =
(env->me_lck->mti_envmode ^ env->me_flags) & mode_flags;
mdbx_notice("accede mode-flags: 0x%X, 0x%X -> 0x%X", diff, env->me_flags,
env->me_flags ^ diff);
env->me_flags ^= diff;
}
if ((env->me_lck->mti_envmode ^ env->me_flags) & rigorous_flags) {
mdbx_error("%s", "current mode/flags incompatible with requested");
rc = MDBX_INCOMPATIBLE;
goto bailout;
}
}
const int dxb_rc = mdbx_setup_dxb(env, lck_rc);
if (MDBX_IS_ERROR(dxb_rc)) {
rc = dxb_rc;
@ -8801,8 +8836,6 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
mdbx_debug("opened dbenv %p", (void *)env);
if (env->me_lck) {
const unsigned mode_flags =
MDBX_WRITEMAP | MDBX_NOSYNC | MDBX_NOMETASYNC | MDBX_MAPASYNC;
if (lck_rc == MDBX_RESULT_TRUE) {
env->me_lck->mti_envmode = env->me_flags & (mode_flags | MDBX_RDONLY);
rc = mdbx_lck_downgrade(env);
@ -8814,19 +8847,6 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
rc = mdbx_reader_check0(env, false, NULL);
if (MDBX_IS_ERROR(rc))
goto bailout;
if ((env->me_flags & MDBX_RDONLY) == 0) {
while (env->me_lck->mti_envmode == MDBX_RDONLY) {
if (atomic_cas32(&env->me_lck->mti_envmode, MDBX_RDONLY,
env->me_flags & mode_flags))
break;
atomic_yield();
}
if ((env->me_lck->mti_envmode ^ env->me_flags) & mode_flags) {
mdbx_error("%s", "current mode/flags incompatible with requested");
rc = MDBX_INCOMPATIBLE;
goto bailout;
}
}
}
if ((env->me_flags & MDBX_NOTLS) == 0) {

View File

@ -968,7 +968,7 @@ int main(int argc, char *argv[]) {
envflags &= ~MDBX_RDONLY;
break;
case 'c':
envflags &= ~MDBX_EXCLUSIVE;
envflags = (envflags & ~MDBX_EXCLUSIVE) | MDBX_ACCEDE;
break;
case 'd':
dont_traversal = true;
@ -1031,7 +1031,7 @@ int main(int argc, char *argv[]) {
#endif
)) {
envflags &= ~MDBX_EXCLUSIVE;
rc = mdbx_env_open(env, envname, envflags, 0664);
rc = mdbx_env_open(env, envname, envflags | MDBX_ACCEDE, 0664);
}
if (rc) {

View File

@ -294,14 +294,21 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option,
//-----------------------------------------------------------------------------
const struct option_verb mode_bits[] = {
{"rdonly", MDBX_RDONLY}, {"mapasync", MDBX_MAPASYNC},
{"utterly", MDBX_UTTERLY_NOSYNC}, {"nosubdir", MDBX_NOSUBDIR},
{"nosync", MDBX_NOSYNC}, {"nometasync", MDBX_NOMETASYNC},
{"writemap", MDBX_WRITEMAP}, {"notls", MDBX_NOTLS},
{"nordahead", MDBX_NORDAHEAD}, {"nomeminit", MDBX_NOMEMINIT},
{"coalesce", MDBX_COALESCE}, {"lifo", MDBX_LIFORECLAIM},
{"perturb", MDBX_PAGEPERTURB}, {nullptr, 0}};
const struct option_verb mode_bits[] = {{"rdonly", MDBX_RDONLY},
{"mapasync", MDBX_MAPASYNC},
{"utterly", MDBX_UTTERLY_NOSYNC},
{"nosubdir", MDBX_NOSUBDIR},
{"nosync", MDBX_NOSYNC},
{"nometasync", MDBX_NOMETASYNC},
{"writemap", MDBX_WRITEMAP},
{"notls", MDBX_NOTLS},
{"nordahead", MDBX_NORDAHEAD},
{"nomeminit", MDBX_NOMEMINIT},
{"coalesce", MDBX_COALESCE},
{"lifo", MDBX_LIFORECLAIM},
{"perturb", MDBX_PAGEPERTURB},
{"accede", MDBX_ACCEDE},
{nullptr, 0}};
const struct option_verb table_bits[] = {
{"key.reverse", MDBX_REVERSEKEY},

View File

@ -124,7 +124,7 @@ void actor_params::set_defaults(const std::string &tmpdir) {
pathname_db = tmpdir + "mdbx-test.db";
mode_flags = MDBX_NOSUBDIR | MDBX_WRITEMAP | MDBX_MAPASYNC | MDBX_NOMEMINIT |
MDBX_COALESCE | MDBX_LIFORECLAIM;
MDBX_COALESCE | MDBX_LIFORECLAIM | MDBX_ACCEDE;
table_flags = MDBX_DUPSORT;
size_lower = -1;