mdbx: rename internal flags & fields for clarity.

Change-Id: I79d6d8e88b0b4c30cbb8a464ca17f07dc2ab44c6
This commit is contained in:
Leonid Yuriev 2020-07-05 15:22:41 +03:00
parent 0fb127b935
commit 5dbb0b4cfe
3 changed files with 153 additions and 124 deletions

8
mdbx.h
View File

@ -2746,10 +2746,10 @@ LIBMDBX_API int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi,
* discarding result from the last argument.
*
* Returns A non-zero error value on failure and 0 on success. */
#define MDBX_TBL_DIRTY 0x01 /* DB was written in this txn */
#define MDBX_TBL_STALE 0x02 /* Named-DB record is older than txnID */
#define MDBX_TBL_FRESH 0x04 /* Named-DB handle opened in this txn */
#define MDBX_TBL_CREAT 0x08 /* Named-DB handle created in this txn */
#define MDBX_DBI_DIRTY 0x01 /* DB was written in this txn */
#define MDBX_DBI_STALE 0x02 /* Named-DB record is older than txnID */
#define MDBX_DBI_FRESH 0x04 /* Named-DB handle opened in this txn */
#define MDBX_DBI_CREAT 0x08 /* Named-DB handle created in this txn */
LIBMDBX_API int mdbx_dbi_flags_ex(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags,
unsigned *state);
LIBMDBX_API int mdbx_dbi_flags(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags);

View File

@ -4128,7 +4128,7 @@ mark_done:
if (all) {
/* Mark dirty root pages */
for (i = 0; i < txn->mt_numdbs; i++) {
if (txn->mt_dbstate[i] & DB_DIRTY) {
if (txn->mt_dbistate[i] & DBI_DIRTY) {
pgno_t pgno = txn->mt_dbs[i].md_root;
if (pgno == P_INVALID)
continue;
@ -5711,7 +5711,7 @@ static int mdbx_cursor_shadow(MDBX_txn *src, MDBX_txn *dst) {
* user may not use mc until dst ends. But we need a valid
* txn pointer here for cursor fixups to keep working. */
mc->mc_txn = dst;
mc->mc_dbstate = &dst->mt_dbstate[i];
mc->mc_dbistate = &dst->mt_dbistate[i];
if ((mx = mc->mc_xcursor) != NULL) {
*(MDBX_xcursor *)(bk + 1) = *mx;
mx->mx_cursor.mc_txn = dst;
@ -5750,7 +5750,7 @@ static void mdbx_cursors_eot(MDBX_txn *txn, unsigned merge) {
mc->mc_backup = bk->mc_backup;
mc->mc_txn = bk->mc_txn;
mc->mc_db = bk->mc_db;
mc->mc_dbstate = bk->mc_dbstate;
mc->mc_dbistate = bk->mc_dbistate;
if ((mx = mc->mc_xcursor) != NULL)
mx->mx_cursor.mc_txn = bk->mc_txn;
} else {
@ -6080,13 +6080,13 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
/* Setup db info */
mdbx_compiler_barrier();
for (unsigned i = CORE_DBS; i < txn->mt_numdbs; i++) {
unsigned x = env->me_dbflags[i];
txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS;
txn->mt_dbstate[i] =
(x & MDBX_VALID) ? DB_VALID | DB_USRVALID | DB_STALE : 0;
const unsigned db_flags = env->me_dbflags[i];
txn->mt_dbs[i].md_flags = db_flags & DB_PERSISTENT_FLAGS;
txn->mt_dbistate[i] =
(db_flags & DB_VALID) ? DBI_VALID | DBI_USRVALID | DBI_STALE : 0;
}
txn->mt_dbstate[MAIN_DBI] = DB_VALID | DB_USRVALID;
txn->mt_dbstate[FREE_DBI] = DB_VALID;
txn->mt_dbistate[MAIN_DBI] = DBI_VALID | DBI_USRVALID;
txn->mt_dbistate[FREE_DBI] = DBI_VALID;
if (unlikely(env->me_flags & MDBX_FATAL_ERROR)) {
mdbx_warning("%s", "environment had fatal error, must shutdown!");
@ -6279,7 +6279,7 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
memset(txn, 0, tsize);
txn->mt_dbxs = env->me_dbxs; /* static */
txn->mt_dbs = (MDBX_db *)((char *)txn + tsize);
txn->mt_dbstate = (uint8_t *)txn + size - env->me_maxdbs;
txn->mt_dbistate = (uint8_t *)txn + size - env->me_maxdbs;
txn->mt_flags = flags;
txn->mt_env = env;
@ -6327,9 +6327,9 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
txn->mt_numdbs = parent->mt_numdbs;
txn->mt_owner = parent->mt_owner;
memcpy(txn->mt_dbs, parent->mt_dbs, txn->mt_numdbs * sizeof(MDBX_db));
/* Copy parent's mt_dbstate, but clear DB_NEW */
/* Copy parent's mt_dbistate, but clear DB_NEW */
for (unsigned i = 0; i < txn->mt_numdbs; i++)
txn->mt_dbstate[i] = parent->mt_dbstate[i] & ~(DB_FRESH | DB_CREAT);
txn->mt_dbistate[i] = parent->mt_dbistate[i] & ~(DBI_FRESH | DBI_CREAT);
mdbx_tassert(parent,
parent->mt_parent ||
parent->tw.dirtyroom + parent->tw.dirtylist->length ==
@ -6503,10 +6503,9 @@ static void mdbx_dbis_update(MDBX_txn *txn, int keep) {
if (n) {
bool locked = false;
MDBX_env *env = txn->mt_env;
uint8_t *tdbflags = txn->mt_dbstate;
for (unsigned i = n; --i >= CORE_DBS;) {
if (likely((tdbflags[i] & DB_CREAT) == 0))
if (likely((txn->mt_dbistate[i] & DBI_CREAT) == 0))
continue;
if (!locked) {
mdbx_ensure(env,
@ -6514,7 +6513,7 @@ static void mdbx_dbis_update(MDBX_txn *txn, int keep) {
locked = true;
}
if (keep) {
env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDBX_VALID;
env->me_dbflags[i] = txn->mt_dbs[i].md_flags | DB_VALID;
mdbx_compiler_barrier();
if (env->me_numdbs <= i)
env->me_numdbs = i + 1;
@ -6755,16 +6754,16 @@ static __cold int mdbx_audit_ex(MDBX_txn *txn, unsigned retired_stored,
mdbx_tassert(txn, rc == MDBX_NOTFOUND);
for (MDBX_dbi i = FREE_DBI; i < txn->mt_numdbs; i++)
txn->mt_dbstate[i] &= ~DB_AUDITED;
txn->mt_dbistate[i] &= ~DBI_AUDITED;
pgno_t count = 0;
for (MDBX_dbi i = FREE_DBI; i <= MAIN_DBI; i++) {
if (!(txn->mt_dbstate[i] & DB_VALID))
if (!(txn->mt_dbistate[i] & DBI_VALID))
continue;
rc = mdbx_cursor_init(&cx.outer, txn, i);
if (unlikely(rc != MDBX_SUCCESS))
return rc;
txn->mt_dbstate[i] |= DB_AUDITED;
txn->mt_dbistate[i] |= DBI_AUDITED;
if (txn->mt_dbs[i].md_root == P_INVALID)
continue;
count += txn->mt_dbs[i].md_branch_pages + txn->mt_dbs[i].md_leaf_pages +
@ -6784,14 +6783,14 @@ static __cold int mdbx_audit_ex(MDBX_txn *txn, unsigned retired_stored,
memcpy(db = &db_copy, node_data(node), sizeof(db_copy));
if ((txn->mt_flags & MDBX_RDONLY) == 0) {
for (MDBX_dbi k = txn->mt_numdbs; --k > MAIN_DBI;) {
if ((txn->mt_dbstate[k] & DB_VALID) &&
if ((txn->mt_dbistate[k] & DBI_VALID) &&
/* txn->mt_dbxs[k].md_name.iov_len > 0 && */
node_ks(node) == txn->mt_dbxs[k].md_name.iov_len &&
memcmp(node_key(node), txn->mt_dbxs[k].md_name.iov_base,
node_ks(node)) == 0) {
txn->mt_dbstate[k] |= DB_AUDITED;
if (txn->mt_dbstate[k] & DB_DIRTY) {
mdbx_tassert(txn, (txn->mt_dbstate[k] & DB_STALE) == 0);
txn->mt_dbistate[k] |= DBI_AUDITED;
if (txn->mt_dbistate[k] & DBI_DIRTY) {
mdbx_tassert(txn, (txn->mt_dbistate[k] & DBI_STALE) == 0);
db = txn->mt_dbs + k;
}
break;
@ -6808,9 +6807,10 @@ static __cold int mdbx_audit_ex(MDBX_txn *txn, unsigned retired_stored,
}
for (MDBX_dbi i = FREE_DBI; i < txn->mt_numdbs; i++) {
if ((txn->mt_dbstate[i] & (DB_VALID | DB_AUDITED | DB_STALE)) != DB_VALID)
if ((txn->mt_dbistate[i] & (DBI_VALID | DBI_AUDITED | DBI_STALE)) !=
DBI_VALID)
continue;
if (F_ISSET(txn->mt_dbstate[i], DB_DIRTY | DB_CREAT)) {
if (F_ISSET(txn->mt_dbistate[i], DBI_DIRTY | DBI_CREAT)) {
count += txn->mt_dbs[i].md_branch_pages + txn->mt_dbs[i].md_leaf_pages +
txn->mt_dbs[i].md_overflow_pages;
} else {
@ -6819,7 +6819,7 @@ static __cold int mdbx_audit_ex(MDBX_txn *txn, unsigned retired_stored,
txn->mt_parent ? "nested-" : "", txn->mt_txnid, i,
(int)txn->mt_dbxs[i].md_name.iov_len,
(const char *)txn->mt_dbxs[i].md_name.iov_base,
txn->mt_dbstate[i]);
txn->mt_dbistate[i]);
}
}
@ -7701,24 +7701,24 @@ static __cold bool mdbx_txn_import_dbi(MDBX_txn *txn, MDBX_dbi dbi) {
mdbx_compiler_barrier();
for (unsigned i = CORE_DBS; i < snap_numdbs; ++i) {
if (i >= txn->mt_numdbs)
txn->mt_dbstate[i] = 0;
if (!(txn->mt_dbstate[i] & DB_USRVALID) &&
(env->me_dbflags[i] & MDBX_VALID)) {
txn->mt_dbs[i].md_flags = env->me_dbflags[i] & PERSISTENT_FLAGS;
txn->mt_dbstate[i] = DB_VALID | DB_USRVALID | DB_STALE;
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_dbstate[dbi] & DB_USRVALID;
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_dbstate[dbi] & validity)))
if (likely(dbi < txn->mt_numdbs && (txn->mt_dbistate[dbi] & validity)))
return true;
return mdbx_txn_import_dbi(txn, dbi);
@ -7799,12 +7799,12 @@ int mdbx_txn_commit(MDBX_txn *txn) {
/* Update parent's DB table. */
memcpy(parent->mt_dbs, txn->mt_dbs, txn->mt_numdbs * sizeof(MDBX_db));
parent->mt_numdbs = txn->mt_numdbs;
parent->mt_dbstate[FREE_DBI] = txn->mt_dbstate[FREE_DBI];
parent->mt_dbstate[MAIN_DBI] = txn->mt_dbstate[MAIN_DBI];
parent->mt_dbistate[FREE_DBI] = txn->mt_dbistate[FREE_DBI];
parent->mt_dbistate[MAIN_DBI] = txn->mt_dbistate[MAIN_DBI];
for (unsigned i = CORE_DBS; i < txn->mt_numdbs; i++) {
/* preserve parent's DB_NEW status */
parent->mt_dbstate[i] =
txn->mt_dbstate[i] | (parent->mt_dbstate[i] & (DB_CREAT | DB_FRESH));
parent->mt_dbistate[i] = txn->mt_dbistate[i] | (parent->mt_dbistate[i] &
(DBI_CREAT | DBI_FRESH));
}
/* Remove refunded pages from parent's dirty & spill lists */
@ -8021,7 +8021,7 @@ int mdbx_txn_commit(MDBX_txn *txn) {
if (txn->tw.dirtylist->length == 0 &&
(txn->mt_flags & (MDBX_TXN_DIRTY | MDBX_TXN_SPILLS)) == 0) {
for (int i = txn->mt_numdbs; --i >= 0;)
mdbx_tassert(txn, (txn->mt_dbstate[i] & DB_DIRTY) == 0);
mdbx_tassert(txn, (txn->mt_dbistate[i] & DBI_DIRTY) == 0);
rc = MDBX_SUCCESS;
goto done;
}
@ -8041,7 +8041,7 @@ int mdbx_txn_commit(MDBX_txn *txn) {
if (unlikely(rc != MDBX_SUCCESS))
goto fail;
for (MDBX_dbi i = CORE_DBS; i < txn->mt_numdbs; i++) {
if (txn->mt_dbstate[i] & DB_DIRTY) {
if (txn->mt_dbistate[i] & DBI_DIRTY) {
if (unlikely(TXN_DBI_CHANGED(txn, i))) {
rc = MDBX_BAD_DBI;
goto fail;
@ -8071,7 +8071,7 @@ int mdbx_txn_commit(MDBX_txn *txn) {
rc = mdbx_page_flush(txn, 0);
if (likely(rc == MDBX_SUCCESS)) {
if (txn->mt_dbs[MAIN_DBI].md_flags & DB_DIRTY)
if (txn->mt_dbs[MAIN_DBI].md_flags & DBI_DIRTY)
txn->mt_dbs[MAIN_DBI].md_mod_txnid = txn->mt_txnid;
MDBX_meta meta, *head = mdbx_meta_head(env);
@ -9986,15 +9986,21 @@ __cold int mdbx_is_readahead_reasonable(size_t volume, intptr_t redundancy) {
/* Only a subset of the mdbx_env flags can be changed
* at runtime. Changing other flags requires closing the
* environment and re-opening it with the new flags. */
#define CHANGEABLE \
#define ENV_CHANGEABLE_FLAGS \
(MDBX_SAFE_NOSYNC | MDBX_NOMETASYNC | MDBX_MAPASYNC | MDBX_NOMEMINIT | \
MDBX_COALESCE | MDBX_PAGEPERTURB | MDBX_ACCEDE)
#define CHANGELESS \
#define ENV_CHANGELESS_FLAGS \
(MDBX_NOSUBDIR | MDBX_RDONLY | MDBX_WRITEMAP | MDBX_NOTLS | MDBX_NORDAHEAD | \
MDBX_LIFORECLAIM | MDBX_EXCLUSIVE)
#define ENV_USABLE_FLAGS (ENV_CHANGEABLE_FLAGS | ENV_CHANGELESS_FLAGS)
#if VALID_FLAGS & PERSISTENT_FLAGS & (CHANGEABLE | CHANGELESS)
#error "Persistent DB flags & env flags overlap, but both go in mm_flags"
#if ENV_INTERNAL_FLAGS & ENV_USABLE_FLAGS
#error "Opps, some flags overlapped or wrong"
#endif
#if (MDBX_ACCEDE | MDBX_CREATE) != ((DB_USABLE_FLAGS | DB_INTERNAL_FLAGS) & \
(ENV_USABLE_FLAGS | ENV_INTERNAL_FLAGS))
#error "Opps, some flags overlapped or wrong"
#endif
/* Merge flags and avoid false MDBX_UTTERLY_NOSYNC */
@ -10018,7 +10024,7 @@ int __cold mdbx_env_open(MDBX_env *env, const char *pathname, unsigned flags,
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDBX_EBADSIGN;
if (flags & ~(CHANGEABLE | CHANGELESS))
if (flags & ~ENV_USABLE_FLAGS)
return MDBX_EINVAL;
if (env->me_lazy_fd != INVALID_HANDLE_VALUE ||
@ -10275,7 +10281,7 @@ int __cold mdbx_env_open(MDBX_env *env, const char *pathname, unsigned flags,
txn->mt_dbs = (MDBX_db *)((char *)txn + tsize);
txn->mt_cursors = (MDBX_cursor **)(txn->mt_dbs + env->me_maxdbs);
txn->mt_dbiseqs = (unsigned *)(txn->mt_cursors + env->me_maxdbs);
txn->mt_dbstate = (uint8_t *)(txn->mt_dbiseqs + env->me_maxdbs);
txn->mt_dbistate = (uint8_t *)(txn->mt_dbiseqs + env->me_maxdbs);
txn->mt_env = env;
txn->mt_dbxs = env->me_dbxs;
txn->mt_flags = MDBX_TXN_FINISHED;
@ -10925,7 +10931,7 @@ static int mdbx_fetch_sdb(MDBX_txn *txn, MDBX_dbi dbi) {
/* The txn may not know this DBI, or another process may
* have dropped and recreated the DB with other flags. */
MDBX_db *const db = &txn->mt_dbs[dbi];
if (unlikely((db->md_flags & PERSISTENT_FLAGS) != md_flags))
if (unlikely((db->md_flags & DB_PERSISTENT_FLAGS) != md_flags))
return MDBX_INCOMPATIBLE;
memcpy(db, data.iov_base, sizeof(MDBX_db));
@ -10933,7 +10939,7 @@ static int mdbx_fetch_sdb(MDBX_txn *txn, MDBX_dbi dbi) {
if (unlikely(rc != MDBX_SUCCESS))
return rc;
txn->mt_dbstate[dbi] &= ~DB_STALE;
txn->mt_dbistate[dbi] &= ~DBI_STALE;
return MDBX_SUCCESS;
}
@ -10984,7 +10990,7 @@ __hot static int mdbx_page_search(MDBX_cursor *mc, const MDBX_val *key,
}
/* Make sure we're using an up-to-date root */
if (unlikely(*mc->mc_dbstate & DB_STALE)) {
if (unlikely(*mc->mc_dbistate & DBI_STALE)) {
rc = mdbx_fetch_sdb(mc->mc_txn, mc->mc_dbi);
if (unlikely(rc != MDBX_SUCCESS))
return rc;
@ -11054,7 +11060,7 @@ int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data) {
if (unlikely(!key || !data))
return MDBX_EINVAL;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_USRVALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
return MDBX_EINVAL;
MDBX_cursor_couple cx;
@ -11078,7 +11084,7 @@ int mdbx_get_nearest(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
if (unlikely(!key || !data))
return MDBX_EINVAL;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_USRVALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
return MDBX_EINVAL;
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
@ -11118,7 +11124,7 @@ int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
if (unlikely(!key || !data))
return MDBX_EINVAL;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_USRVALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
return MDBX_EINVAL;
MDBX_cursor_couple cx;
@ -11900,7 +11906,7 @@ static int mdbx_cursor_touch(MDBX_cursor *mc) {
int rc = MDBX_SUCCESS;
if (mc->mc_dbi >= CORE_DBS &&
(*mc->mc_dbstate & (DB_DIRTY | DB_DUPDATA)) == 0) {
(*mc->mc_dbistate & (DBI_DIRTY | DBI_DUPDATA)) == 0) {
mdbx_cassert(mc, (mc->mc_flags & C_RECLAIMING) == 0);
/* Touch DB record of named DB */
MDBX_cursor_couple cx;
@ -11912,7 +11918,7 @@ static int mdbx_cursor_touch(MDBX_cursor *mc) {
rc = mdbx_page_search(&cx.outer, &mc->mc_dbx->md_name, MDBX_PS_MODIFY);
if (unlikely(rc))
return rc;
*mc->mc_dbstate |= DB_DIRTY;
*mc->mc_dbistate |= DBI_DIRTY;
}
mc->mc_top = 0;
if (mc->mc_snum) {
@ -12164,7 +12170,7 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data,
mc->mc_xcursor->mx_dbx.md_klen_min = mc->mc_xcursor->mx_dbx.md_klen_max =
data->iov_len;
}
*mc->mc_dbstate |= DB_DIRTY;
*mc->mc_dbistate |= DBI_DIRTY;
if ((mc->mc_db->md_flags & (MDBX_DUPSORT | MDBX_DUPFIXED)) == MDBX_DUPFIXED)
np->mp_flags |= P_LEAF2;
mc->mc_flags |= C_INITIALIZED;
@ -13113,7 +13119,7 @@ static int mdbx_xcursor_init0(MDBX_cursor *mc) {
mx->mx_cursor.mc_db = &mx->mx_db;
mx->mx_cursor.mc_dbx = &mx->mx_dbx;
mx->mx_cursor.mc_dbi = mc->mc_dbi;
mx->mx_cursor.mc_dbstate = &mx->mx_dbstate;
mx->mx_cursor.mc_dbistate = &mx->mx_dbistate;
mx->mx_cursor.mc_snum = 0;
mx->mx_cursor.mc_top = 0;
mx->mx_cursor.mc_flags = C_SUB | (mc->mc_flags & (C_COPYING | C_SKIPORD));
@ -13181,7 +13187,7 @@ static int mdbx_xcursor_init1(MDBX_cursor *mc, MDBX_node *node) {
mdbx_debug("Sub-db -%u root page %" PRIaPGNO, mx->mx_cursor.mc_dbi,
mx->mx_db.md_root);
mx->mx_dbstate = DB_VALID | DB_USRVALID | DB_DUPDATA;
mx->mx_dbistate = DBI_VALID | DBI_USRVALID | DBI_DUPDATA;
return MDBX_SUCCESS;
}
@ -13203,7 +13209,7 @@ static int mdbx_xcursor_init2(MDBX_cursor *mc, MDBX_xcursor *src_mx,
mx->mx_cursor.mc_top = 0;
mx->mx_cursor.mc_flags |= C_INITIALIZED;
mx->mx_cursor.mc_ki[0] = 0;
mx->mx_dbstate = DB_VALID | DB_USRVALID | DB_DUPDATA;
mx->mx_dbistate = DBI_VALID | DBI_USRVALID | DBI_DUPDATA;
}
mx->mx_dbx.md_klen_min = src_mx->mx_dbx.md_klen_min;
@ -13229,7 +13235,7 @@ static __inline int mdbx_couple_init(MDBX_cursor_couple *couple,
couple->outer.mc_txn = txn;
couple->outer.mc_db = db;
couple->outer.mc_dbx = dbx;
couple->outer.mc_dbstate = dbstate;
couple->outer.mc_dbistate = dbstate;
couple->outer.mc_snum = 0;
couple->outer.mc_top = 0;
couple->outer.mc_pg[0] = 0;
@ -13238,7 +13244,7 @@ static __inline int mdbx_couple_init(MDBX_cursor_couple *couple,
couple->outer.mc_xcursor = NULL;
int rc = MDBX_SUCCESS;
if (unlikely(*couple->outer.mc_dbstate & DB_STALE)) {
if (unlikely(*couple->outer.mc_dbistate & DBI_STALE)) {
rc = mdbx_page_search(&couple->outer, NULL, MDBX_PS_ROOTONLY);
rc = (rc != MDBX_NOTFOUND) ? rc : MDBX_SUCCESS;
} else if (unlikely(couple->outer.mc_dbx->md_klen_max == 0)) {
@ -13263,7 +13269,7 @@ static int mdbx_cursor_init(MDBX_cursor *mc, MDBX_txn *txn, MDBX_dbi dbi) {
STATIC_ASSERT(offsetof(MDBX_cursor_couple, outer) == 0);
return mdbx_couple_init(container_of(mc, MDBX_cursor_couple, outer), dbi, txn,
&txn->mt_dbs[dbi], &txn->mt_dbxs[dbi],
&txn->mt_dbstate[dbi]);
&txn->mt_dbistate[dbi]);
}
int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
@ -13275,7 +13281,7 @@ int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
if (unlikely(rc != MDBX_SUCCESS))
return rc;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_VALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_VALID)))
return MDBX_EINVAL;
if (unlikely(dbi == FREE_DBI && !F_ISSET(txn->mt_flags, MDBX_RDONLY)))
@ -13317,7 +13323,7 @@ int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) {
if (unlikely(rc != MDBX_SUCCESS))
return rc;
if (unlikely(!mdbx_txn_dbi_exists(txn, mc->mc_dbi, DB_VALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, mc->mc_dbi, DBI_VALID)))
return MDBX_EINVAL;
if (unlikely(mc->mc_backup))
@ -14793,7 +14799,7 @@ int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
if (unlikely(!key))
return MDBX_EINVAL;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_USRVALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
return MDBX_EINVAL;
if (unlikely(txn->mt_flags & (MDBX_RDONLY | MDBX_TXN_BLOCKED)))
@ -15335,7 +15341,7 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data,
if (unlikely(!key || !data))
return MDBX_EINVAL;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_USRVALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
return MDBX_EINVAL;
if (unlikely(flags & ~(MDBX_NOOVERWRITE | MDBX_NODUPDATA | MDBX_RESERVE |
@ -16014,7 +16020,7 @@ int __cold mdbx_env_set_flags(MDBX_env *env, unsigned flags, int onoff) {
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(flags & ~CHANGEABLE))
if (unlikely(flags & ~ENV_CHANGEABLE_FLAGS))
return MDBX_EPERM;
if (unlikely(env->me_flags & MDBX_RDONLY))
@ -16043,7 +16049,7 @@ int __cold mdbx_env_get_flags(const MDBX_env *env, unsigned *arg) {
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDBX_EBADSIGN;
*arg = env->me_flags & (CHANGEABLE | CHANGELESS);
*arg = env->me_flags & ENV_USABLE_FLAGS;
return MDBX_SUCCESS;
}
@ -16168,7 +16174,7 @@ int __cold mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi,
if (unlikely(!mask))
return MDBX_EINVAL;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_VALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_VALID)))
return MDBX_EINVAL;
MDBX_cursor_couple cx;
@ -16361,7 +16367,7 @@ static int mdbx_dbi_bind(MDBX_txn *txn, const MDBX_dbi dbi, unsigned user_flags,
* 3) user_flags differs, but table is empty and MDBX_CREATE is provided
* = assume that a properly create request with custom flags;
*/
if ((user_flags ^ txn->mt_dbs[dbi].md_flags) & PERSISTENT_FLAGS) {
if ((user_flags ^ txn->mt_dbs[dbi].md_flags) & DB_PERSISTENT_FLAGS) {
/* flags are differs, check other conditions */
if ((!user_flags && (!keycmp || keycmp == txn->mt_dbxs[dbi].md_cmp) &&
(!datacmp || datacmp == txn->mt_dbxs[dbi].md_dcmp)) ||
@ -16373,7 +16379,7 @@ static int mdbx_dbi_bind(MDBX_txn *txn, const MDBX_dbi dbi, unsigned user_flags,
if (txn->mt_flags & MDBX_RDONLY)
return /* FIXME: return extended info */ MDBX_EACCESS;
/* make sure flags changes get committed */
txn->mt_dbs[dbi].md_flags = user_flags & PERSISTENT_FLAGS;
txn->mt_dbs[dbi].md_flags = user_flags & DB_PERSISTENT_FLAGS;
txn->mt_flags |= MDBX_TXN_DIRTY;
} else {
return /* FIXME: return extended info */ MDBX_INCOMPATIBLE;
@ -16408,7 +16414,7 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
if (unlikely(!dbi))
return rc;
if (unlikely((user_flags & ~VALID_FLAGS) != 0)) {
if (unlikely((user_flags & ~DB_USABLE_FLAGS) != 0)) {
early_bailout:
*dbi = 0;
return rc;
@ -16536,10 +16542,10 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
if (txn->mt_numdbs < env->me_numdbs) {
/* Import handles from env */
for (unsigned i = txn->mt_numdbs; i < env->me_numdbs; ++i) {
txn->mt_dbstate[i] = 0;
if (env->me_dbflags[i] & MDBX_VALID) {
txn->mt_dbs[i].md_flags = env->me_dbflags[i] & PERSISTENT_FLAGS;
txn->mt_dbstate[i] = DB_VALID | DB_USRVALID | DB_STALE;
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);
}
}
@ -16568,14 +16574,14 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
goto later_bailout;
}
unsigned dbflag = DB_FRESH | DB_VALID | DB_USRVALID;
unsigned dbiflags = DBI_FRESH | DBI_VALID | DBI_USRVALID;
MDBX_db db_dummy;
if (unlikely(rc)) {
/* MDBX_NOTFOUND and MDBX_CREATE: Create new DB */
mdbx_tassert(txn, rc == MDBX_NOTFOUND);
memset(&db_dummy, 0, sizeof(db_dummy));
db_dummy.md_root = P_INVALID;
db_dummy.md_flags = user_flags & PERSISTENT_FLAGS;
db_dummy.md_flags = user_flags & DB_PERSISTENT_FLAGS;
data.iov_len = sizeof(db_dummy);
data.iov_base = &db_dummy;
WITH_CURSOR_TRACKING(couple.outer,
@ -16585,7 +16591,7 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
if (unlikely(rc != MDBX_SUCCESS))
goto later_bailout;
dbflag |= DB_DIRTY | DB_CREAT;
dbiflags |= DBI_DIRTY | DBI_CREAT;
}
/* Got info, register DBI in this txn */
@ -16594,18 +16600,18 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
env->me_dbflags[slot] = 0;
rc = mdbx_dbi_bind(txn, slot, user_flags, keycmp, datacmp);
if (unlikely(rc != MDBX_SUCCESS)) {
mdbx_tassert(txn, (dbflag & DB_CREAT) == 0);
mdbx_tassert(txn, (dbiflags & DBI_CREAT) == 0);
later_bailout:
*dbi = 0;
later_exit:
mdbx_free(namedup);
} else {
txn->mt_dbstate[slot] = (uint8_t)dbflag;
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;
txn->mt_numdbs += (slot == txn->mt_numdbs);
if ((dbflag & DB_CREAT) == 0) {
env->me_dbflags[slot] = txn->mt_dbs[slot].md_flags | MDBX_VALID;
if ((dbiflags & DBI_CREAT) == 0) {
env->me_dbflags[slot] = txn->mt_dbs[slot].md_flags | DB_VALID;
mdbx_compiler_barrier();
if (env->me_numdbs <= slot)
env->me_numdbs = slot + 1;
@ -16634,7 +16640,7 @@ int __cold mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest,
if (unlikely(!dest))
return MDBX_EINVAL;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_VALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_VALID)))
return MDBX_EINVAL;
const size_t size_before_modtxnid = offsetof(MDBX_stat, ms_mod_txnid);
@ -16644,7 +16650,7 @@ int __cold mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest,
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
return MDBX_BAD_TXN;
if (unlikely(txn->mt_dbstate[dbi] & DB_STALE)) {
if (unlikely(txn->mt_dbistate[dbi] & DBI_STALE)) {
rc = mdbx_fetch_sdb(txn, dbi);
if (unlikely(rc != MDBX_SUCCESS))
return rc;
@ -16698,11 +16704,12 @@ int mdbx_dbi_flags_ex(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags,
if (unlikely(!flags || !state))
return MDBX_EINVAL;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_VALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_VALID)))
return MDBX_EINVAL;
*flags = txn->mt_dbs[dbi].md_flags & PERSISTENT_FLAGS;
*state = txn->mt_dbstate[dbi] & (DB_FRESH | DB_CREAT | DB_DIRTY | DB_STALE);
*flags = txn->mt_dbs[dbi].md_flags & DB_PERSISTENT_FLAGS;
*state =
txn->mt_dbistate[dbi] & (DBI_FRESH | DBI_CREAT | DBI_DIRTY | DBI_STALE);
return MDBX_SUCCESS;
}
@ -16812,7 +16819,7 @@ int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, int del) {
if (unlikely(1 < (unsigned)del))
return MDBX_EINVAL;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_USRVALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
return MDBX_EINVAL;
if (unlikely(TXN_DBI_CHANGED(txn, dbi)))
@ -16823,7 +16830,7 @@ int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, int del) {
if (unlikely(rc != MDBX_SUCCESS))
return rc;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_USRVALID))) {
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID))) {
rc = MDBX_EINVAL;
goto bailout;
}
@ -16844,7 +16851,7 @@ int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, int del) {
if (del && dbi >= CORE_DBS) {
rc = mdbx_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, F_SUBDATA);
if (likely(rc == MDBX_SUCCESS)) {
txn->mt_dbstate[dbi] = DB_STALE;
txn->mt_dbistate[dbi] = DBI_STALE;
MDBX_env *env = txn->mt_env;
rc = mdbx_fastmutex_acquire(&env->me_dbi_lock);
if (unlikely(rc != MDBX_SUCCESS)) {
@ -16860,7 +16867,7 @@ int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, int del) {
}
} else {
/* reset the DB record, mark it dirty */
txn->mt_dbstate[dbi] |= DB_DIRTY;
txn->mt_dbistate[dbi] |= DBI_DIRTY;
txn->mt_dbs[dbi].md_depth = 0;
txn->mt_dbs[dbi].md_branch_pages = 0;
txn->mt_dbs[dbi].md_leaf_pages = 0;
@ -16881,7 +16888,7 @@ int mdbx_set_compare(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
if (unlikely(rc != MDBX_SUCCESS))
return rc;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_USRVALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
return MDBX_EINVAL;
txn->mt_dbxs[dbi].md_cmp = cmp;
@ -16893,7 +16900,7 @@ int mdbx_set_dupsort(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
if (unlikely(rc != MDBX_SUCCESS))
return rc;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_USRVALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
return MDBX_EINVAL;
txn->mt_dbxs[dbi].md_dcmp = cmp;
@ -17584,8 +17591,8 @@ static int __cold mdbx_walk_sdb(mdbx_walk_ctx_t *ctx, MDBX_db *const db,
MDBX_cursor_couple couple;
MDBX_dbx dbx = {.md_klen_min = INT_MAX};
uint8_t dbstate = DB_VALID | DB_AUDITED;
int rc = mdbx_couple_init(&couple, ~0u, ctx->mw_txn, db, &dbx, &dbstate);
uint8_t dbistate = DBI_VALID | DBI_AUDITED;
int rc = mdbx_couple_init(&couple, ~0u, ctx->mw_txn, db, &dbx, &dbistate);
if (unlikely(rc != MDBX_SUCCESS))
return rc;
@ -17966,7 +17973,7 @@ int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
if (unlikely(begin_key == MDBX_EPSILON && end_key == MDBX_EPSILON))
return MDBX_EINVAL;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_USRVALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
return MDBX_EINVAL;
MDBX_cursor_couple begin;
@ -18139,7 +18146,7 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
if (unlikely(new_data == NULL && !(flags & MDBX_CURRENT)))
return MDBX_EINVAL;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_USRVALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
return MDBX_EINVAL;
if (unlikely(flags & ~(MDBX_NOOVERWRITE | MDBX_NODUPDATA | MDBX_RESERVE |
@ -18335,13 +18342,13 @@ int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result,
if (unlikely(rc != MDBX_SUCCESS))
return rc;
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DB_USRVALID)))
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
return MDBX_EINVAL;
if (unlikely(TXN_DBI_CHANGED(txn, dbi)))
return MDBX_BAD_DBI;
if (unlikely(txn->mt_dbstate[dbi] & DB_STALE)) {
if (unlikely(txn->mt_dbistate[dbi] & DBI_STALE)) {
rc = mdbx_fetch_sdb(txn, dbi);
if (unlikely(rc != MDBX_SUCCESS))
return rc;
@ -18362,7 +18369,7 @@ int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result,
mdbx_tassert(txn, new > dbs->md_seq);
dbs->md_seq = new;
txn->mt_flags |= MDBX_TXN_DIRTY;
txn->mt_dbstate[dbi] |= DB_DIRTY;
txn->mt_dbistate[dbi] |= DBI_DIRTY;
}
return MDBX_SUCCESS;

View File

@ -716,6 +716,9 @@ struct MDBX_txn {
#define MDBX_TXN_BEGIN_FLAGS \
(MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC | MDBX_MAPASYNC | MDBX_RDONLY | \
MDBX_TRYTXN)
/* Additional flag for mdbx_sync_locked() */
#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
/* internal txn flags */
#define MDBX_TXN_FINISHED 0x01 /* txn is finished or never began */
#define MDBX_TXN_ERROR 0x02 /* txn is unusable after an error */
@ -725,6 +728,16 @@ struct MDBX_txn {
/* most operations on the txn are currently illegal */
#define MDBX_TXN_BLOCKED \
(MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_HAS_CHILD)
#define TXN_FLAGS \
(MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS | \
MDBX_TXN_HAS_CHILD)
#if (TXN_FLAGS & MDBX_TXN_BEGIN_FLAGS) || \
((MDBX_TXN_BEGIN_FLAGS | TXN_FLAGS) & MDBX_SHRINK_ALLOWED)
#error "Opps, some flags overlapped or wrong"
#endif
unsigned mt_flags;
/* The ID of this transaction. IDs are integers incrementing from 1.
* Only committed write transactions increment the ID. If a transaction
@ -740,17 +753,17 @@ struct MDBX_txn {
/* In write txns, array of cursors for each DB */
MDBX_cursor **mt_cursors;
/* Transaction DB Flags */
#define DB_DIRTY MDBX_TBL_DIRTY /* DB was written in this txn */
#define DB_STALE MDBX_TBL_STALE /* Named-DB record is older than txnID */
#define DB_FRESH MDBX_TBL_FRESH /* Named-DB handle opened in this txn */
#define DB_CREAT MDBX_TBL_CREAT /* Named-DB handle created in this txn */
#define DB_VALID 0x10 /* DB handle is valid, see also MDBX_VALID */
#define DB_USRVALID 0x20 /* As DB_VALID, but not set for FREE_DBI */
#define DB_DUPDATA 0x40 /* DB is MDBX_DUPSORT data */
#define DB_AUDITED 0x80 /* Internal flag for accounting during audit */
/* Transaction DBI Flags */
#define DBI_DIRTY MDBX_DBI_DIRTY /* DB was written in this txn */
#define DBI_STALE MDBX_DBI_STALE /* Named-DB record is older than txnID */
#define DBI_FRESH MDBX_DBI_FRESH /* Named-DB handle opened in this txn */
#define DBI_CREAT MDBX_DBI_CREAT /* Named-DB handle created in this txn */
#define DBI_VALID 0x10 /* DB handle is valid, see also DB_VALID */
#define DBI_USRVALID 0x20 /* As DB_VALID, but not set for FREE_DBI */
#define DBI_DUPDATA 0x40 /* DB is MDBX_DUPSORT data */
#define DBI_AUDITED 0x80 /* Internal flag for accounting during audit */
/* Array of flags for each DB */
uint8_t *mt_dbstate;
uint8_t *mt_dbistate;
/* Number of DB records in use, or 0 when the txn is finished.
* This number only ever increments until the txn finishes; we
* don't decrement it when individual DB handles are closed. */
@ -833,8 +846,8 @@ struct MDBX_cursor {
MDBX_db *mc_db;
/* The database auxiliary record for this cursor */
MDBX_dbx *mc_dbx;
/* The mt_dbstate for this database */
uint8_t *mc_dbstate;
/* The mt_dbistate for this database */
uint8_t *mc_dbistate;
unsigned mc_snum; /* number of pushed pages */
unsigned mc_top; /* index of top page, normally mc_snum-1 */
@ -869,8 +882,8 @@ typedef struct MDBX_xcursor {
MDBX_db mx_db;
/* The auxiliary DB record for this Dup DB */
MDBX_dbx mx_dbx;
/* The mt_dbstate for this Dup DB */
uint8_t mx_dbstate;
/* The mt_dbistate for this Dup DB */
uint8_t mx_dbistate;
} MDBX_xcursor;
typedef struct MDBX_cursor_couple {
@ -884,12 +897,11 @@ struct MDBX_env {
uint32_t me_signature;
/* Failed to update the meta page. Probably an I/O error. */
#define MDBX_FATAL_ERROR UINT32_C(0x80000000)
/* Additional flag for mdbx_sync_locked() */
#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
/* Some fields are initialized. */
#define MDBX_ENV_ACTIVE UINT32_C(0x20000000)
/* me_txkey is set */
#define MDBX_ENV_TXKEY UINT32_C(0x10000000)
#define ENV_INTERNAL_FLAGS (MDBX_FATAL_ERROR | MDBX_ENV_ACTIVE | MDBX_ENV_TXKEY)
uint32_t me_flags;
mdbx_mmap_t me_dxb_mmap; /* The main data file */
#define me_map me_dxb_mmap.dxb
@ -1287,12 +1299,22 @@ typedef struct MDBX_node {
uint8_t mn_data[/* C99 */]; /* key and data are appended here */
} MDBX_node;
#define MDBX_VALID 0x8000 /* DB handle is valid, for me_dbflags */
#define PERSISTENT_FLAGS (0xffff & ~(MDBX_VALID | MDBX_NOSUBDIR))
/* mdbx_dbi_open() flags */
#define VALID_FLAGS \
#define DB_PERSISTENT_FLAGS \
(MDBX_REVERSEKEY | MDBX_DUPSORT | MDBX_INTEGERKEY | MDBX_DUPFIXED | \
MDBX_INTEGERDUP | MDBX_REVERSEDUP | MDBX_CREATE | MDBX_ACCEDE)
MDBX_INTEGERDUP | MDBX_REVERSEDUP)
/* mdbx_dbi_open() flags */
#define DB_USABLE_FLAGS (DB_PERSISTENT_FLAGS | MDBX_CREATE | MDBX_ACCEDE)
#define DB_VALID 0x8000 /* DB handle is valid, for me_dbflags */
#define DB_INTERNAL_FLAGS DB_VALID
#if DB_INTERNAL_FLAGS & DB_USABLE_FLAGS
#error "Opps, some flags overlapped or wrong"
#endif
#if DB_PERSISTENT_FLAGS & ~DB_USABLE_FLAGS
#error "Opps, some flags overlapped or wrong"
#endif
/* max number of pages to commit in one writev() call */
#define MDBX_COMMIT_PAGES 64