Merge branch 'master' into devel

This commit is contained in:
Leo Yuriev 2015-10-21 00:24:44 +03:00
commit 60387be4a5
3 changed files with 269 additions and 50 deletions

View File

@ -33,7 +33,7 @@ PROGS := $(IPROGS) mtest0 mtest1 mtest2 mtest3 mtest4 mtest5 mtest6 wbench
SRC_LMDB := mdb.c midl.c lmdb.h midl.h SRC_LMDB := mdb.c midl.c lmdb.h midl.h
SRC_MDBX := $(SRC_LMDB) mdbx.h SRC_MDBX := $(SRC_LMDB) mdbx.h
.PHONY: mdbx lmdb all install clean test coverage .PHONY: mdbx lmdb all install clean check tests coverage
all: $(ILIBS) $(IPROGS) all: $(ILIBS) $(IPROGS)
@ -54,7 +54,9 @@ install: $(ILIBS) $(IPROGS) $(IHDRS)
clean: clean:
rm -rf $(PROGS) @* *.[ao] *.[ls]o *~ testdb/* *.gcov rm -rf $(PROGS) @* *.[ao] *.[ls]o *~ testdb/* *.gcov
test: mdbx $(PROGS) tests: mdbx $(PROGS)
check: tests
[ -d testdb ] || mkdir testdb && rm -f testdb/* \ [ -d testdb ] || mkdir testdb && rm -f testdb/* \
&& echo "*** LMDB-TEST-0" && ./mtest0 && ./mdbx_chk -v testdb \ && echo "*** LMDB-TEST-0" && ./mtest0 && ./mdbx_chk -v testdb \
&& echo "*** LMDB-TEST-1" && ./mtest1 && ./mdbx_chk -v testdb \ && echo "*** LMDB-TEST-1" && ./mtest1 && ./mdbx_chk -v testdb \

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) \
@ -1448,12 +1454,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);
} }
@ -2496,9 +2504,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;
@ -2619,6 +2633,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;
@ -2821,7 +2836,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);
@ -2840,6 +2861,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;
@ -2847,6 +2874,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))) {
@ -2925,6 +2955,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',
@ -2937,14 +2968,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;
} }
@ -2984,7 +3017,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;
@ -3074,33 +3113,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
@ -3575,6 +3624,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;
@ -3719,6 +3771,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;
} }
@ -3798,7 +3851,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;
} }
@ -4099,6 +4159,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;
} }
@ -4156,6 +4217,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.
*/ */
@ -4194,8 +4264,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;
} }
@ -4203,8 +4280,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;
} }
@ -4214,6 +4298,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;
} }
@ -4605,7 +4693,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);
@ -4817,16 +4911,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) {
@ -4836,7 +4933,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
@ -5477,7 +5577,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))
@ -6002,6 +6108,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;
@ -6217,6 +6326,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
@ -6734,6 +6846,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;
@ -7232,6 +7350,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;
} }
@ -7284,6 +7403,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 {
@ -7292,6 +7412,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
@ -7300,7 +7421,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))
@ -7331,7 +7458,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))
@ -7353,6 +7487,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;
@ -7380,28 +7517,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;
} }
@ -8101,7 +8245,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)))
@ -8567,7 +8717,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)))
@ -9313,8 +9469,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;
@ -9413,7 +9576,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)))
@ -9455,8 +9624,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;
} }
@ -9555,15 +9731,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;
@ -9603,6 +9785,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;
@ -9612,6 +9800,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;
@ -9621,6 +9815,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;
@ -9630,6 +9830,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;
@ -9640,6 +9846,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);
} }
@ -9651,8 +9859,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;
@ -9726,7 +9937,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;
@ -9855,14 +10066,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 {
@ -10005,6 +10217,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;