mdbx: adds signatures to detect ABI mixup.

This commit is contained in:
Leo Yuriev 2015-10-20 23:59:06 +03:00
parent 68171d5f5d
commit dc3256e91c
2 changed files with 265 additions and 48 deletions

6
lmdb.h
View File

@ -774,7 +774,7 @@ int mdb_env_sync(MDB_env *env, int force);
*/ */
void mdb_env_close(MDB_env *env); void mdb_env_close(MDB_env *env);
#if MDBX_MODE_ENABLED #if MDBX_MODE_ENABLED
void mdbx_env_close_ex(MDB_env *env, int dont_sync); int mdbx_env_close_ex(MDB_env *env, int dont_sync);
#endif /* MDBX_MODE_ENABLED */ #endif /* MDBX_MODE_ENABLED */
/** @brief Set environment flags. /** @brief Set environment flags.
@ -1058,7 +1058,7 @@ int mdb_txn_commit(MDB_txn *txn);
* Only write-transactions free cursors. * Only write-transactions free cursors.
* @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] txn A transaction handle returned by #mdb_txn_begin()
*/ */
void mdb_txn_abort(MDB_txn *txn); int mdb_txn_abort(MDB_txn *txn);
/** @brief Reset a read-only transaction. /** @brief Reset a read-only transaction.
* *
@ -1077,7 +1077,7 @@ void mdb_txn_abort(MDB_txn *txn);
* the database size may grow much more rapidly than otherwise. * the database size may grow much more rapidly than otherwise.
* @param[in] txn A transaction handle returned by #mdb_txn_begin() * @param[in] txn A transaction handle returned by #mdb_txn_begin()
*/ */
void mdb_txn_reset(MDB_txn *txn); int mdb_txn_reset(MDB_txn *txn);
/** @brief Renew a read-only transaction. /** @brief Renew a read-only transaction.
* *

307
mdb.c
View File

@ -737,6 +737,8 @@ typedef struct MDB_dbx {
* Every operation requires a transaction handle. * Every operation requires a transaction handle.
*/ */
struct MDB_txn { struct MDB_txn {
#define MDBX_MT_SIGNATURE 0x706C553B
unsigned mt_signature;
MDB_txn *mt_parent; /**< parent of a nested txn */ MDB_txn *mt_parent; /**< parent of a nested txn */
/** Nested txn under this txn, set together with flag #MDB_TXN_HAS_CHILD */ /** Nested txn under this txn, set together with flag #MDB_TXN_HAS_CHILD */
MDB_txn *mt_child; MDB_txn *mt_child;
@ -840,6 +842,8 @@ struct MDB_xcursor;
* (A node with #F_DUPDATA but no #F_SUBDATA contains a subpage). * (A node with #F_DUPDATA but no #F_SUBDATA contains a subpage).
*/ */
struct MDB_cursor { struct MDB_cursor {
#define MDBX_MC_SIGNATURE 0xFE05D5B1
unsigned mc_signature;
/** Next cursor on this DB in this txn */ /** Next cursor on this DB in this txn */
MDB_cursor *mc_next; MDB_cursor *mc_next;
/** Backup of the original cursor if this cursor is a shadow */ /** Backup of the original cursor if this cursor is a shadow */
@ -905,6 +909,8 @@ struct MDB_rthc {
}; };
/** The database environment. */ /** The database environment. */
struct MDB_env { struct MDB_env {
#define MDBX_ME_SIGNATURE 0x9A899641
unsigned me_signature;
HANDLE me_fd; /**< The main data file */ HANDLE me_fd; /**< The main data file */
HANDLE me_lfd; /**< The lock file */ HANDLE me_lfd; /**< The lock file */
/** Failed to update the meta page. Probably an I/O error. */ /** Failed to update the meta page. Probably an I/O error. */
@ -981,7 +987,7 @@ typedef struct MDB_ntxn {
/** Check \b txn and \b dbi arguments to a function */ /** Check \b txn and \b dbi arguments to a function */
#define TXN_DBI_EXIST(txn, dbi, validity) \ #define TXN_DBI_EXIST(txn, dbi, validity) \
((txn) && (dbi)<(txn)->mt_numdbs && ((txn)->mt_dbflags[dbi] & (validity))) ((dbi)<(txn)->mt_numdbs && ((txn)->mt_dbflags[dbi] & (validity)))
/** Check for misused \b dbi handles */ /** Check for misused \b dbi handles */
#define TXN_DBI_CHANGED(txn, dbi) \ #define TXN_DBI_CHANGED(txn, dbi) \
@ -1447,12 +1453,14 @@ static void mdb_audit(MDB_txn *txn)
int int
mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
{ {
mdb_ensure(NULL, txn->mt_signature == MDBX_MT_SIGNATURE);
return txn->mt_dbxs[dbi].md_cmp(a, b); return txn->mt_dbxs[dbi].md_cmp(a, b);
} }
int int
mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
{ {
mdb_ensure(NULL, txn->mt_signature == MDBX_MT_SIGNATURE);
return txn->mt_dbxs[dbi].md_dcmp(a, b); return txn->mt_dbxs[dbi].md_dcmp(a, b);
} }
@ -2495,9 +2503,15 @@ mdb_env_sync(MDB_env *env, int force)
MDB_meta *head; MDB_meta *head;
unsigned flags; unsigned flags;
if (unlikely(! env || ! env->me_txns)) if (unlikely(! env))
return EINVAL; return EINVAL;
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(! env->me_txns))
return MDB_PANIC;
flags = env->me_flags & ~MDB_NOMETASYNC; flags = env->me_flags & ~MDB_NOMETASYNC;
if (unlikely(flags & (MDB_RDONLY | MDB_FATAL_ERROR))) if (unlikely(flags & (MDB_RDONLY | MDB_FATAL_ERROR)))
return EACCES; return EACCES;
@ -2618,6 +2632,7 @@ mdb_cursors_close(MDB_txn *txn, unsigned merge)
mc = bk; mc = bk;
} }
/* Only malloced cursors are permanently tracked. */ /* Only malloced cursors are permanently tracked. */
mc->mc_signature = 0;
free(mc); free(mc);
} }
cursors[i] = NULL; cursors[i] = NULL;
@ -2820,7 +2835,13 @@ mdb_txn_renew(MDB_txn *txn)
{ {
int rc; int rc;
if (unlikely(!txn || !F_ISSET(txn->mt_flags, MDB_TXN_RDONLY|MDB_TXN_FINISHED))) if (unlikely(!txn))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(!F_ISSET(txn->mt_flags, MDB_TXN_RDONLY|MDB_TXN_FINISHED)))
return EINVAL; return EINVAL;
rc = mdb_txn_renew0(txn); rc = mdb_txn_renew0(txn);
@ -2839,6 +2860,12 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned flags, MDB_txn **ret)
MDB_ntxn *ntxn; MDB_ntxn *ntxn;
int rc, size, tsize; int rc, size, tsize;
if (unlikely(!env || !ret))
return EINVAL;
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDB_VERSION_MISMATCH;
flags &= MDB_TXN_BEGIN_FLAGS; flags &= MDB_TXN_BEGIN_FLAGS;
flags |= env->me_flags & MDB_WRITEMAP; flags |= env->me_flags & MDB_WRITEMAP;
@ -2846,6 +2873,9 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned flags, MDB_txn **ret)
return EACCES; return EACCES;
if (parent) { if (parent) {
if (unlikely(parent->mt_signature != MDBX_MT_SIGNATURE))
return EINVAL;
/* Nested transactions: Max 1 child, write txns only, no writemap */ /* Nested transactions: Max 1 child, write txns only, no writemap */
flags |= parent->mt_flags; flags |= parent->mt_flags;
if (unlikely(flags & (MDB_RDONLY|MDB_WRITEMAP|MDB_TXN_BLOCKED))) { if (unlikely(flags & (MDB_RDONLY|MDB_WRITEMAP|MDB_TXN_BLOCKED))) {
@ -2924,6 +2954,7 @@ renew:
free(txn); free(txn);
} else { } else {
txn->mt_flags |= flags; /* could not change txn=me_txn0 earlier */ txn->mt_flags |= flags; /* could not change txn=me_txn0 earlier */
txn->mt_signature = MDBX_MT_SIGNATURE;
*ret = txn; *ret = txn;
mdb_debug("begin txn %zu%c %p on mdbenv %p, root page %zu", mdb_debug("begin txn %zu%c %p on mdbenv %p, root page %zu",
txn->mt_txnid, (flags & MDB_RDONLY) ? 'r' : 'w', txn->mt_txnid, (flags & MDB_RDONLY) ? 'r' : 'w',
@ -2936,14 +2967,16 @@ renew:
MDB_env * MDB_env *
mdb_txn_env(MDB_txn *txn) mdb_txn_env(MDB_txn *txn)
{ {
if(unlikely(!txn)) return NULL; if(unlikely(!txn || txn->mt_signature != MDBX_MT_SIGNATURE))
return NULL;
return txn->mt_env; return txn->mt_env;
} }
size_t size_t
mdb_txn_id(MDB_txn *txn) mdb_txn_id(MDB_txn *txn)
{ {
if(unlikely(!txn)) return 0; if(unlikely(!txn || txn->mt_signature != MDBX_MT_SIGNATURE))
return 0;
return txn->mt_txnid; return txn->mt_txnid;
} }
@ -2983,7 +3016,13 @@ mdbx_txn_straggler(MDB_txn *txn, int *percent)
MDB_meta *meta; MDB_meta *meta;
txnid_t lag; txnid_t lag;
if (unlikely(! txn || ! txn->mt_u.reader)) if(unlikely(!txn))
return -EINVAL;
if(unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(! txn->mt_u.reader))
return -1; return -1;
env = txn->mt_env; env = txn->mt_env;
@ -3073,33 +3112,43 @@ mdb_txn_end(MDB_txn *txn, unsigned mode)
mdb_midl_free(pghead); mdb_midl_free(pghead);
} }
if (mode & MDB_END_FREE) if (mode & MDB_END_FREE) {
txn->mt_signature = 0;
free(txn); free(txn);
}
} }
void int
mdb_txn_reset(MDB_txn *txn) mdb_txn_reset(MDB_txn *txn)
{ {
if (unlikely(txn == NULL)) if (unlikely(! txn))
return; return EINVAL;
if(unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
/* This call is only valid for read-only txns */ /* This call is only valid for read-only txns */
if (unlikely(!(txn->mt_flags & MDB_TXN_RDONLY))) if (unlikely(!(txn->mt_flags & MDB_TXN_RDONLY)))
return; return EINVAL;
mdb_txn_end(txn, MDB_END_RESET); mdb_txn_end(txn, MDB_END_RESET);
return MDB_SUCCESS;
} }
void int
mdb_txn_abort(MDB_txn *txn) mdb_txn_abort(MDB_txn *txn)
{ {
if (unlikely(txn == NULL)) if (unlikely(! txn))
return; return EINVAL;
if(unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (txn->mt_child) if (txn->mt_child)
mdb_txn_abort(txn->mt_child); mdb_txn_abort(txn->mt_child);
mdb_txn_end(txn, MDB_END_ABORT|MDB_END_SLOT|MDB_END_FREE); mdb_txn_end(txn, MDB_END_ABORT|MDB_END_SLOT|MDB_END_FREE);
return MDB_SUCCESS;
} }
static int static int
@ -3574,6 +3623,9 @@ mdb_txn_commit(MDB_txn *txn)
if (unlikely(txn == NULL)) if (unlikely(txn == NULL))
return EINVAL; return EINVAL;
if(unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
/* mdb_txn_end() mode for a commit which writes nothing */ /* mdb_txn_end() mode for a commit which writes nothing */
end_mode = MDB_END_EMPTY_COMMIT|MDB_END_UPDATE|MDB_END_SLOT|MDB_END_FREE; end_mode = MDB_END_EMPTY_COMMIT|MDB_END_UPDATE|MDB_END_SLOT|MDB_END_FREE;
@ -3718,6 +3770,7 @@ mdb_txn_commit(MDB_txn *txn)
parent->mt_child = NULL; parent->mt_child = NULL;
mdb_midl_free(((MDB_ntxn *)txn)->mnt_pgstate.mf_pghead); mdb_midl_free(((MDB_ntxn *)txn)->mnt_pgstate.mf_pghead);
txn->mt_signature = 0;
free(txn); free(txn);
return rc; return rc;
} }
@ -3797,7 +3850,14 @@ fail:
} }
int __cold int __cold
mdb_env_set_syncbytes(MDB_env *env, size_t bytes) { mdb_env_set_syncbytes(MDB_env *env, size_t bytes)
{
if (unlikely(!env))
return EINVAL;
if(unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDB_VERSION_MISMATCH;
env->me_sync_threshold = bytes; env->me_sync_threshold = bytes;
return env->me_map ? mdb_env_sync(env, 0) : 0; return env->me_map ? mdb_env_sync(env, 0) : 0;
} }
@ -4098,6 +4158,7 @@ mdb_env_create(MDB_env **env)
e->me_pid = getpid(); e->me_pid = getpid();
GET_PAGESIZE(e->me_os_psize); GET_PAGESIZE(e->me_os_psize);
VALGRIND_CREATE_MEMPOOL(e,0,0); VALGRIND_CREATE_MEMPOOL(e,0,0);
e->me_signature = MDBX_ME_SIGNATURE;
*env = e; *env = e;
return MDB_SUCCESS; return MDB_SUCCESS;
} }
@ -4155,6 +4216,15 @@ mdb_env_map(MDB_env *env, void *addr)
int __cold int __cold
mdb_env_set_mapsize(MDB_env *env, size_t size) mdb_env_set_mapsize(MDB_env *env, size_t size)
{ {
if (unlikely(!env))
return EINVAL;
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(size < env->me_psize * 8))
return EINVAL;
/* If env is already open, caller is responsible for making /* If env is already open, caller is responsible for making
* sure there are no active txns. * sure there are no active txns.
*/ */
@ -4193,8 +4263,15 @@ mdb_env_set_mapsize(MDB_env *env, size_t size)
int __cold int __cold
mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs) mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs)
{ {
if (env->me_map) if (unlikely(!env))
return EINVAL; return EINVAL;
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(env->me_map))
return EINVAL;
env->me_maxdbs = dbs + CORE_DBS; env->me_maxdbs = dbs + CORE_DBS;
return MDB_SUCCESS; return MDB_SUCCESS;
} }
@ -4202,8 +4279,15 @@ mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs)
int __cold int __cold
mdb_env_set_maxreaders(MDB_env *env, unsigned readers) mdb_env_set_maxreaders(MDB_env *env, unsigned readers)
{ {
if (env->me_map || readers < 1) if (unlikely(!env || readers < 1))
return EINVAL; return EINVAL;
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(env->me_map))
return EINVAL;
env->me_maxreaders = readers; env->me_maxreaders = readers;
return MDB_SUCCESS; return MDB_SUCCESS;
} }
@ -4213,6 +4297,10 @@ mdb_env_get_maxreaders(MDB_env *env, unsigned *readers)
{ {
if (!env || !readers) if (!env || !readers)
return EINVAL; return EINVAL;
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDB_VERSION_MISMATCH;
*readers = env->me_maxreaders; *readers = env->me_maxreaders;
return MDB_SUCCESS; return MDB_SUCCESS;
} }
@ -4604,7 +4692,13 @@ mdbx_env_open_ex(MDB_env *env, const char *path, unsigned flags, mode_t mode, in
int oflags, rc, len, excl = -1; int oflags, rc, len, excl = -1;
char *lpath, *dpath; char *lpath, *dpath;
if (env->me_fd!=INVALID_HANDLE_VALUE || (flags & ~(CHANGEABLE|CHANGELESS))) if (unlikely(!env || !path))
return EINVAL;
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (env->me_fd != INVALID_HANDLE_VALUE || (flags & ~(CHANGEABLE|CHANGELESS)))
return EINVAL; return EINVAL;
len = strlen(path); len = strlen(path);
@ -4816,16 +4910,19 @@ mdb_env_close0(MDB_env *env)
#if !MDBX_MODE_ENABLED #if !MDBX_MODE_ENABLED
static static
#endif /* !MDBX_MODE_ENABLED*/ #endif /* !MDBX_MODE_ENABLED*/
void __cold int __cold
mdbx_env_close_ex(MDB_env *env, int dont_sync) mdbx_env_close_ex(MDB_env *env, int dont_sync)
{ {
MDB_page *dp; MDB_page *dp;
int rc = MDB_SUCCESS;
if (env == NULL) if (unlikely(!env))
return; return EINVAL;
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (! dont_sync) if (! dont_sync)
mdb_env_sync(env, 1); rc = mdb_env_sync(env, 1);
VALGRIND_DESTROY_MEMPOOL(env); VALGRIND_DESTROY_MEMPOOL(env);
while ((dp = env->me_dpages) != NULL) { while ((dp = env->me_dpages) != NULL) {
@ -4835,7 +4932,10 @@ mdbx_env_close_ex(MDB_env *env, int dont_sync)
} }
mdb_env_close0(env); mdb_env_close0(env);
env->me_signature = 0;
free(env); free(env);
return rc;
} }
void __cold void __cold
@ -5476,7 +5576,13 @@ mdb_get(MDB_txn *txn, MDB_dbi dbi,
mdb_debug("===> get db %u key [%s]", dbi, DKEY(key)); mdb_debug("===> get db %u key [%s]", dbi, DKEY(key));
if (unlikely(!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))) if (unlikely(!key || !data || !txn))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return EINVAL; return EINVAL;
if (unlikely(txn->mt_flags & MDB_TXN_BLOCKED)) if (unlikely(txn->mt_flags & MDB_TXN_BLOCKED))
@ -6001,6 +6107,9 @@ mdb_cursor_get(MDB_cursor *mc, MDB_val *key, MDB_val *data,
if (unlikely(mc == NULL)) if (unlikely(mc == NULL))
return EINVAL; return EINVAL;
if (unlikely(mc->mc_signature != MDBX_MC_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(mc->mc_txn->mt_flags & MDB_TXN_BLOCKED)) if (unlikely(mc->mc_txn->mt_flags & MDB_TXN_BLOCKED))
return MDB_BAD_TXN; return MDB_BAD_TXN;
@ -6216,6 +6325,9 @@ mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data,
if (unlikely(mc == NULL || key == NULL)) if (unlikely(mc == NULL || key == NULL))
return EINVAL; return EINVAL;
if (unlikely(mc->mc_signature != MDBX_MC_SIGNATURE))
return MDB_VERSION_MISMATCH;
env = mc->mc_txn->mt_env; env = mc->mc_txn->mt_env;
/* Check this first so counter will always be zero on any /* Check this first so counter will always be zero on any
@ -6722,6 +6834,12 @@ mdb_cursor_del(MDB_cursor *mc, unsigned flags)
MDB_page *mp; MDB_page *mp;
int rc; int rc;
if (unlikely(!mc))
return EINVAL;
if (unlikely(mc->mc_signature != MDBX_MC_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(mc->mc_txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED))) if (unlikely(mc->mc_txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED)))
return (mc->mc_txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN; return (mc->mc_txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
@ -7213,6 +7331,7 @@ mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node)
if (mx->mx_dbx.md_cmp == mdb_cmp_int && mx->mx_db.md_pad == sizeof(size_t)) if (mx->mx_dbx.md_cmp == mdb_cmp_int && mx->mx_db.md_pad == sizeof(size_t))
mx->mx_dbx.md_cmp = mdb_cmp_clong; mx->mx_dbx.md_cmp = mdb_cmp_clong;
#endif */ #endif */
mc->mc_signature = MDBX_MC_SIGNATURE;
} }
/** Initialize a cursor for a given transaction and database. */ /** Initialize a cursor for a given transaction and database. */
@ -7233,6 +7352,7 @@ mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx)
mc->mc_ki[0] = 0; mc->mc_ki[0] = 0;
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) { if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
mdb_tassert(txn, mx != NULL); mdb_tassert(txn, mx != NULL);
mx->mx_cursor.mc_signature = MDBX_MC_SIGNATURE;
mc->mc_xcursor = mx; mc->mc_xcursor = mx;
mdb_xcursor_init0(mc); mdb_xcursor_init0(mc);
} else { } else {
@ -7241,6 +7361,7 @@ mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx)
if (*mc->mc_dbflag & DB_STALE) { if (*mc->mc_dbflag & DB_STALE) {
mdb_page_search(mc, NULL, MDB_PS_ROOTONLY); mdb_page_search(mc, NULL, MDB_PS_ROOTONLY);
} }
mc->mc_signature = MDBX_MC_SIGNATURE;
} }
int int
@ -7249,7 +7370,13 @@ mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret)
MDB_cursor *mc; MDB_cursor *mc;
size_t size = sizeof(MDB_cursor); size_t size = sizeof(MDB_cursor);
if (unlikely(!ret || !TXN_DBI_EXIST(txn, dbi, DB_VALID))) if (unlikely(!ret || !txn))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_VALID)))
return EINVAL; return EINVAL;
if (unlikely(txn->mt_flags & MDB_TXN_BLOCKED)) if (unlikely(txn->mt_flags & MDB_TXN_BLOCKED))
@ -7280,7 +7407,14 @@ mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret)
int int
mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc) mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc)
{ {
if (unlikely(!mc || !TXN_DBI_EXIST(txn, mc->mc_dbi, DB_VALID))) if (unlikely(!mc || !txn))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE
|| mc->mc_signature != MDBX_MC_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, mc->mc_dbi, DB_VALID)))
return EINVAL; return EINVAL;
if (unlikely((mc->mc_flags & C_UNTRACK) || txn->mt_cursors)) if (unlikely((mc->mc_flags & C_UNTRACK) || txn->mt_cursors))
@ -7302,6 +7436,9 @@ mdb_cursor_count(MDB_cursor *mc, size_t *countp)
if (unlikely(mc == NULL || countp == NULL)) if (unlikely(mc == NULL || countp == NULL))
return EINVAL; return EINVAL;
if (unlikely(mc->mc_signature != MDBX_MC_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(mc->mc_xcursor == NULL)) if (unlikely(mc->mc_xcursor == NULL))
return MDB_INCOMPATIBLE; return MDB_INCOMPATIBLE;
@ -7329,28 +7466,35 @@ mdb_cursor_count(MDB_cursor *mc, size_t *countp)
void void
mdb_cursor_close(MDB_cursor *mc) mdb_cursor_close(MDB_cursor *mc)
{ {
if (mc && !mc->mc_backup) { if (mc) {
/* remove from txn, if tracked */ mdb_ensure(NULL, mc->mc_signature == MDBX_MC_SIGNATURE);
if ((mc->mc_flags & C_UNTRACK) && mc->mc_txn->mt_cursors) { if (!mc->mc_backup) {
MDB_cursor **prev = &mc->mc_txn->mt_cursors[mc->mc_dbi]; /* remove from txn, if tracked */
while (*prev && *prev != mc) prev = &(*prev)->mc_next; if ((mc->mc_flags & C_UNTRACK) && mc->mc_txn->mt_cursors) {
if (*prev == mc) MDB_cursor **prev = &mc->mc_txn->mt_cursors[mc->mc_dbi];
*prev = mc->mc_next; while (*prev && *prev != mc) prev = &(*prev)->mc_next;
if (*prev == mc)
*prev = mc->mc_next;
}
mc->mc_signature = 0;
free(mc);
} }
free(mc);
} }
} }
MDB_txn * MDB_txn *
mdb_cursor_txn(MDB_cursor *mc) mdb_cursor_txn(MDB_cursor *mc)
{ {
if (unlikely(!mc)) return NULL; if (unlikely(!mc || mc->mc_signature != MDBX_MC_SIGNATURE))
return NULL;
return mc->mc_txn; return mc->mc_txn;
} }
MDB_dbi MDB_dbi
mdb_cursor_dbi(MDB_cursor *mc) mdb_cursor_dbi(MDB_cursor *mc)
{ {
if (unlikely(!mc || mc->mc_signature != MDBX_MC_SIGNATURE))
return INT_MIN;
return mc->mc_dbi; return mc->mc_dbi;
} }
@ -8050,7 +8194,13 @@ int
mdb_del(MDB_txn *txn, MDB_dbi dbi, mdb_del(MDB_txn *txn, MDB_dbi dbi,
MDB_val *key, MDB_val *data) MDB_val *key, MDB_val *data)
{ {
if (unlikely(!key || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))) if (unlikely(!key || !txn))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return EINVAL; return EINVAL;
if (unlikely(txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED))) if (unlikely(txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED)))
@ -8516,7 +8666,13 @@ mdb_put(MDB_txn *txn, MDB_dbi dbi,
MDB_cursor mc; MDB_cursor mc;
MDB_xcursor mx; MDB_xcursor mx;
if (unlikely(!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))) if (unlikely(!key || !data || !txn))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return EINVAL; return EINVAL;
if (unlikely(flags & ~(MDB_NOOVERWRITE|MDB_NODUPDATA|MDB_RESERVE|MDB_APPEND|MDB_APPENDDUP))) if (unlikely(flags & ~(MDB_NOOVERWRITE|MDB_NODUPDATA|MDB_RESERVE|MDB_APPEND|MDB_APPENDDUP)))
@ -9262,8 +9418,15 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned flags, MDB_dbi *dbi)
unsigned unused = 0, seq; unsigned unused = 0, seq;
size_t len; size_t len;
if (unlikely(!txn || !dbi))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(flags & ~VALID_FLAGS)) if (unlikely(flags & ~VALID_FLAGS))
return EINVAL; return EINVAL;
if (unlikely(txn->mt_flags & MDB_TXN_BLOCKED)) if (unlikely(txn->mt_flags & MDB_TXN_BLOCKED))
return MDB_BAD_TXN; return MDB_BAD_TXN;
@ -9362,7 +9525,13 @@ static
int __cold int __cold
mdbx_stat(MDB_txn *txn, MDB_dbi dbi, MDBX_stat *arg, size_t bytes) mdbx_stat(MDB_txn *txn, MDB_dbi dbi, MDBX_stat *arg, size_t bytes)
{ {
if (!arg || unlikely(!TXN_DBI_EXIST(txn, dbi, DB_VALID))) if (unlikely(!arg || !txn))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_VALID)))
return EINVAL; return EINVAL;
if (unlikely(bytes != sizeof(MDBX_stat))) if (unlikely(bytes != sizeof(MDBX_stat)))
@ -9404,8 +9573,15 @@ void mdb_dbi_close(MDB_env *env, MDB_dbi dbi)
int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned *flags) int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned *flags)
{ {
if (unlikely(!txn || !flags))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_VALID))) if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_VALID)))
return EINVAL; return EINVAL;
*flags = txn->mt_dbs[dbi].md_flags & PERSISTENT_FLAGS; *flags = txn->mt_dbs[dbi].md_flags & PERSISTENT_FLAGS;
return MDB_SUCCESS; return MDB_SUCCESS;
} }
@ -9504,15 +9680,21 @@ int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del)
MDB_cursor *mc, *m2; MDB_cursor *mc, *m2;
int rc; int rc;
if ((unsigned)del > 1 || unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))) if (unlikely(1 < (unsigned) del || !txn))
return EINVAL; return EINVAL;
if (unlikely(F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))) if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return EACCES; return MDB_VERSION_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return EINVAL;
if (unlikely(TXN_DBI_CHANGED(txn, dbi))) if (unlikely(TXN_DBI_CHANGED(txn, dbi)))
return MDB_BAD_DBI; return MDB_BAD_DBI;
if (unlikely(F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)))
return EACCES;
rc = mdb_cursor_open(txn, dbi, &mc); rc = mdb_cursor_open(txn, dbi, &mc);
if (unlikely(rc)) if (unlikely(rc))
return rc; return rc;
@ -9552,6 +9734,12 @@ leave:
int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp) int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
{ {
if (unlikely(!txn))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))) if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return EINVAL; return EINVAL;
@ -9561,6 +9749,12 @@ int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp) int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
{ {
if (unlikely(!txn))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))) if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return EINVAL; return EINVAL;
@ -9570,6 +9764,12 @@ int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel) int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel)
{ {
if (unlikely(!txn))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))) if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return EINVAL; return EINVAL;
@ -9579,6 +9779,12 @@ int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel)
int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx) int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx)
{ {
if (unlikely(!txn))
return EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))) if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return EINVAL; return EINVAL;
@ -9589,6 +9795,8 @@ int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx)
int __cold int __cold
mdb_env_get_maxkeysize(MDB_env *env) mdb_env_get_maxkeysize(MDB_env *env)
{ {
if (!env || env->me_signature != MDBX_ME_SIGNATURE)
return EINVAL;
return ENV_MAXKEY(env); return ENV_MAXKEY(env);
} }
@ -9600,8 +9808,11 @@ mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx)
char buf[64]; char buf[64];
int rc = 0, first = 1; int rc = 0, first = 1;
if (!env || !func) if (unlikely(!env || !func))
return -1; return -EINVAL;
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDB_VERSION_MISMATCH;
rdrs = env->me_txns->mti_numreaders; rdrs = env->me_txns->mti_numreaders;
mr = env->me_txns->mti_readers; mr = env->me_txns->mti_readers;
@ -9675,7 +9886,7 @@ mdb_pid_insert(pid_t *ids, pid_t pid)
int __cold int __cold
mdb_reader_check(MDB_env *env, int *dead) mdb_reader_check(MDB_env *env, int *dead)
{ {
if (!env) if (unlikely(!env || env->me_signature != MDBX_ME_SIGNATURE))
return EINVAL; return EINVAL;
if (dead) if (dead)
*dead = 0; *dead = 0;
@ -9804,14 +10015,15 @@ static void mdb_mutex_unlock(MDB_env *env, pthread_mutex_t *mutex) {
void __cold void __cold
mdbx_env_set_oomfunc(MDB_env *env, MDB_oom_func *oomfunc) mdbx_env_set_oomfunc(MDB_env *env, MDB_oom_func *oomfunc)
{ {
if (env) if (likely(env && env->me_signature == MDBX_ME_SIGNATURE))
env->me_oom_func = oomfunc; env->me_oom_func = oomfunc;
} }
MDB_oom_func* __cold MDB_oom_func* __cold
mdbx_env_get_oomfunc(MDB_env *env) mdbx_env_get_oomfunc(MDB_env *env)
{ {
return env ? env->me_oom_func : NULL; return likely(env && env->me_signature == MDBX_ME_SIGNATURE)
? env->me_oom_func : NULL;
} }
struct mdb_walk_ctx { struct mdb_walk_ctx {
@ -9954,6 +10166,11 @@ mdbx_env_pgwalk(MDB_txn *txn, MDB_pgvisitor_func* visitor, void* user)
mdb_walk_ctx_t ctx; mdb_walk_ctx_t ctx;
int rc; int rc;
if (unlikely(!txn))
return MDB_BAD_TXN;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDB_VERSION_MISMATCH;
ctx.mw_txn = txn; ctx.mw_txn = txn;
ctx.mw_user = user; ctx.mw_user = user;
ctx.mw_visitor = visitor; ctx.mw_visitor = visitor;