lmdb: provide both interfaces - advanced 'mdbx' and original 'lmdb'.

This commit is contained in:
Leo Yuriev 2015-10-13 15:46:59 +03:00
parent 09c140c1f4
commit 68171d5f5d
21 changed files with 664 additions and 384 deletions

10
.gitignore vendored
View File

@ -1,11 +1,11 @@
mtest[0123456]
wbench
testdb
mdb_copy
mdb_stat
mdb_dump
mdb_load
mdb_chk
mdbx_copy
mdbx_stat
mdbx_dump
mdbx_load
mdbx_chk
*.lo
*.[ao]
*.so

151
Makefile
View File

@ -20,17 +20,26 @@
CC ?= gcc
CFLAGS ?= -O2 -g -Wall -Werror -Wno-unused-parameter
CFLAGS += -pthread
LDLIBS = -Wl,--no-as-needed -lrt
prefix ?= /usr/local
########################################################################
IHDRS = lmdb.h
ILIBS = liblmdb.a liblmdb.so
IPROGS = mdb_stat mdb_copy mdb_dump mdb_load mdb_chk
IDOCS = mdb_stat.1 mdb_copy.1 mdb_dump.1 mdb_load.1
PROGS = $(IPROGS) mtest0 mtest1 mtest2 mtest3 mtest4 mtest5 mtest6 wbench
all: $(ILIBS) $(PROGS)
IHDRS := lmdb.h mdbx.h
ILIBS := libmdbx.a libmdbx.so
IPROGS := mdbx_stat mdbx_copy mdbx_dump mdbx_load mdbx_chk
IDOCS := mdb_stat.1 mdb_copy.1 mdb_dump.1 mdb_load.1
PROGS := $(IPROGS) mtest0 mtest1 mtest2 mtest3 mtest4 mtest5 mtest6 wbench
SRC_LMDB := mdb.c midl.c lmdb.h midl.h
SRC_MDBX := $(SRC_LMDB) mdbx.h
.PHONY: mdbx lmdb all install clean test coverage
all: $(ILIBS) $(IPROGS)
mdbx: libmdbx.a libmdbx.so
lmdb: liblmdb.a liblmdb.so
install: $(ILIBS) $(IPROGS) $(IHDRS)
mkdir -p $(DESTDIR)$(prefix)/bin
@ -43,73 +52,95 @@ install: $(ILIBS) $(IPROGS) $(IHDRS)
for f in $(IDOCS); do cp $$f $(DESTDIR)$(prefix)/man/man1; done
clean:
rm -rf $(PROGS) *.[ao] *.[ls]o *~ testdb/*
rm -rf $(PROGS) @* *.[ao] *.[ls]o *~ testdb/* *.gcov
test: all
test: mdbx $(PROGS)
[ -d testdb ] || mkdir testdb && rm -f testdb/* \
&& echo "*** LMDB-TEST-0" && ./mtest0 && ./mdb_chk -v testdb \
&& echo "*** LMDB-TEST-1" && ./mtest1 && ./mdb_chk -v testdb \
&& echo "*** LMDB-TEST-2" && ./mtest2 && ./mdb_chk -v testdb \
&& echo "*** LMDB-TEST-3" && ./mtest3 && ./mdb_chk -v testdb \
&& echo "*** LMDB-TEST-4" && ./mtest4 && ./mdb_chk -v testdb \
&& echo "*** LMDB-TEST-5" && ./mtest5 && ./mdb_chk -v testdb \
&& echo "*** LMDB-TEST-6" && ./mtest6 && ./mdb_chk -v testdb \
&& echo "*** LMDB-TEST-0" && ./mtest0 && ./mdbx_chk -v testdb \
&& echo "*** LMDB-TEST-1" && ./mtest1 && ./mdbx_chk -v testdb \
&& echo "*** LMDB-TEST-2" && ./mtest2 && ./mdbx_chk -v testdb \
&& echo "*** LMDB-TEST-3" && ./mtest3 && ./mdbx_chk -v testdb \
&& echo "*** LMDB-TEST-4" && ./mtest4 && ./mdbx_chk -v testdb \
&& echo "*** LMDB-TEST-5" && ./mtest5 && ./mdbx_chk -v testdb \
&& echo "*** LMDB-TEST-6" && ./mtest6 && ./mdbx_chk -v testdb \
&& echo "*** LMDB-TESTs - all done"
liblmdb.a: mdb.o midl.o
$(AR) rs $@ mdb.o midl.o
libmdbx.a: mdbx.o
$(AR) rs $@ $^
liblmdb.so: mdb.lo midl.lo
# $(CC) $(LDFLAGS) -pthread -shared -Wl,-Bsymbolic -o $@ mdb.o midl.o $(SOLIBS)
$(CC) $(LDFLAGS) -pthread -shared -o $@ mdb.lo midl.lo $(SOLIBS)
libmdbx.so: mdbx.lo
$(CC) $(CFLAGS) $(LDFLAGS) -pthread -shared -o $@ $^
mdb_stat: mdb_stat.o liblmdb.a
mdb_copy: mdb_copy.o liblmdb.a
mdb_dump: mdb_dump.o liblmdb.a
mdb_load: mdb_load.o liblmdb.a
mdb_chk: mdb_chk.o liblmdb.a
mtest0: mtest0.o liblmdb.a
mtest1: mtest1.o liblmdb.a
mtest2: mtest2.o liblmdb.a
mtest3: mtest3.o liblmdb.a
mtest4: mtest4.o liblmdb.a
mtest5: mtest5.o liblmdb.a
mtest6: mtest6.o liblmdb.a
wbench: wbench.o liblmdb.a
liblmdb.a: lmdb.o
$(AR) rs $@ $^
mdb.o: mdb.c lmdb.h midl.h
$(CC) $(CFLAGS) $(CPPFLAGS) -c mdb.c
liblmdb.so: lmdb.lo
$(CC) $(CFLAGS) $(LDFLAGS) -pthread -shared -o $@ $^
midl.o: midl.c midl.h
$(CC) $(CFLAGS) $(CPPFLAGS) -c midl.c
mdbx_stat: mdb_stat.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
mdb.lo: mdb.c lmdb.h midl.h
$(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c mdb.c -o $@
mdbx_copy: mdb_copy.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
midl.lo: midl.c midl.h
$(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c midl.c -o $@
mdbx_dump: mdb_dump.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
mdbx_load: mdb_load.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
mdbx_chk: mdb_chk.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ -lrt
mtest0: mtest0.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
mtest1: mtest1.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
mtest2: mtest2.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
mtest3: mtest3.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
mtest4: mtest4.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
mtest5: mtest5.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
mtest6: mtest6.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
wbench: wbench.o mdbx.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ -lrt
mdbx.o: $(SRC_MDBX)
$(CC) $(CFLAGS) -include mdbx.h -c mdb.c -o $@
mdbx.lo: $(SRC_MDBX)
$(CC) $(CFLAGS) -include mdbx.h -fPIC -c mdb.c -o $@
lmdb.o: $(SRC_LMDB)
$(CC) $(CFLAGS) -c mdb.c -o $@
lmdb.lo: $(SRC_LMDB)
$(CC) $(CFLAGS) -fPIC -c mdb.c -o $@
%: %.o
$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
%.o: %.c lmdb.h
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
%.o: %.c lmdb.h mdbx.h
$(CC) $(CFLAGS) -c $<
COV_FLAGS=-fprofile-arcs -ftest-coverage
COV_OBJS=xmdb.o xmidl.o
coverage: xmtest
for i in mtest*.c [0-9]*.c; do j=`basename \$$i .c`; $(MAKE) $$j.o; \
gcc -o x$$j $$j.o $(COV_OBJS) -pthread $(COV_FLAGS); \
rm -rf testdb; mkdir testdb; ./x$$j; done
gcov xmdb.c
gcov xmidl.c
@gcov-mdb.o: $(SRC_MDBX)
$(CC) $(CFLAGS) $(COV_FLAGS) -O0 -include mdbx.h -c mdb.c -o $@
xmtest: mtest.o xmdb.o xmidl.o
gcc -o xmtest mtest.o xmdb.o xmidl.o -pthread $(COV_FLAGS)
xmdb.o: mdb.c lmdb.h midl.h
$(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -O0 $(COV_FLAGS) -c mdb.c -o $@
xmidl.o: midl.c midl.h
$(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -O0 $(COV_FLAGS) -c midl.c -o $@
coverage: @gcov-mdb.o
for t in mtest*.c; do x=`basename \$$t .c`; $(MAKE) $$x.o; \
gcc -o @gcov-$$x $$x.o $^ -pthread $(COV_FLAGS); \
rm -rf testdb; mkdir testdb; ./@gcov-$$x; done
gcov @gcov-mdb

65
lmdb.h
View File

@ -155,6 +155,10 @@
#ifndef _LMDB_H_
#define _LMDB_H_
#ifndef MDBX_MODE_ENABLED
# define MDBX_MODE_ENABLED 0
#endif /* MDBX_MODE_ENABLED */
#include <sys/types.h>
#include <stdarg.h>
#include <stdint.h>
@ -284,11 +288,15 @@ typedef void (MDB_rel_func)(MDB_val *item, void *oldptr, void *newptr, void *rel
#define MDB_NORDAHEAD 0x800000
/** don't initialize malloc'd memory before writing to datafile */
#define MDB_NOMEMINIT 0x1000000
#if MDBX_MODE_ENABLED
/** aim to coalesce FreeDB records */
#define MDB_COALESCE 0x2000000
/** LIFO policy for reclaiming FreeDB records */
#define MDB_LIFORECLAIM 0x4000000
/** make a steady-sync only on close and explicit env-sync */
#endif /* MDBX_MODE_ENABLED */
/** make a steady-sync only on close and explicit env-sync */
#define MDB_UTTERLY_NOSYNC (MDB_NOSYNC|MDB_MAPASYNC)
/** @} */
@ -446,18 +454,31 @@ typedef struct MDB_stat {
size_t ms_entries; /**< Number of data items */
} MDB_stat;
typedef struct MDBX_stat {
MDB_stat base;
#if MDBX_MODE_ENABLED
/* LY: TODO */
#endif /* MDBX_MODE_ENABLED */
} MDBX_stat;
/** @brief Information about the environment */
typedef struct MDB_envinfo {
void *me_mapaddr; /**< Address of map, if fixed */
size_t me_mapsize; /**< Size of the data memory map */
size_t me_last_pgno; /**< ID of the last used page */
size_t me_last_txnid; /**< ID of the last committed transaction */
size_t me_tail_txnid; /**< ID of the last reader transaction */
unsigned me_maxreaders; /**< max reader slots in the environment */
unsigned me_numreaders; /**< max reader slots used in the environment */
} MDB_envinfo;
typedef struct MDBX_envinfo {
MDB_envinfo base;
#if MDBX_MODE_ENABLED
size_t me_tail_txnid; /**< ID of the last reader transaction */
size_t me_meta1_txnid, me_meta1_sign;
size_t me_meta2_txnid, me_meta2_sign;
} MDB_envinfo;
#endif /* MDBX_MODE_ENABLED */
} MDBX_envinfo;
/** @brief Return the LMDB library version information.
*
@ -618,7 +639,9 @@ int mdb_env_create(MDB_env **env);
* </ul>
*/
int mdb_env_open(MDB_env *env, const char *path, unsigned flags, mode_t mode);
int mdb_env_open_ex(MDB_env *env, const char *path, unsigned flags, mode_t mode, int *exclusive);
#if MDBX_MODE_ENABLED
int mdbx_env_open_ex(MDB_env *env, const char *path, unsigned flags, mode_t mode, int *exclusive);
#endif /* MDBX_MODE_ENABLED */
/** @brief Copy an LMDB environment to the specified path.
*
* This function may be used to make a backup of an existing environment.
@ -700,6 +723,9 @@ int mdb_env_copyfd2(MDB_env *env, mdb_filehandle_t fd, unsigned flags);
* where the statistics will be copied
*/
int mdb_env_stat(MDB_env *env, MDB_stat *stat);
#if MDBX_MODE_ENABLED
int mdbx_env_stat(MDB_env *env, MDBX_stat *stat, size_t bytes);
#endif /* MDBX_MODE_ENABLED */
/** @brief Return information about the LMDB environment.
*
@ -708,6 +734,9 @@ int mdb_env_stat(MDB_env *env, MDB_stat *stat);
* where the information will be copied
*/
int mdb_env_info(MDB_env *env, MDB_envinfo *info);
#if MDBX_MODE_ENABLED
int mdbx_env_info(MDB_env *env, MDBX_envinfo *info, size_t bytes);
#endif /* MDBX_MODE_ENABLED */
/** @brief Flush the data buffers to disk.
*
@ -744,7 +773,9 @@ int mdb_env_sync(MDB_env *env, int force);
* checkpoint (meta-page update) will rolledback for consistency guarantee.
*/
void mdb_env_close(MDB_env *env);
void mdb_env_close_ex(MDB_env *env, int dont_sync);
#if MDBX_MODE_ENABLED
void mdbx_env_close_ex(MDB_env *env, int dont_sync);
#endif /* MDBX_MODE_ENABLED */
/** @brief Set environment flags.
*
@ -927,6 +958,7 @@ typedef void MDB_assert_func(MDB_env *env, const char *msg,
*/
int mdb_env_set_assert(MDB_env *env, MDB_assert_func *func);
#if MDBX_MODE_ENABLED
/** @brief Set threshold to force flush the data buffers to disk,
* even of #MDB_NOSYNC, #MDB_NOMETASYNC and #MDB_MAPASYNC flags
* in the environment.
@ -944,7 +976,8 @@ int mdb_env_set_assert(MDB_env *env, MDB_assert_func *func);
* when a synchronous flush would be made.
* @return A non-zero error value on failure and 0 on success.
*/
int mdb_env_set_syncbytes(MDB_env *env, size_t bytes);
int mdbx_env_set_syncbytes(MDB_env *env, size_t bytes);
#endif /* MDBX_MODE_ENABLED */
/** @brief Create a transaction for use with the environment.
*
@ -1149,6 +1182,9 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned flags, MDB_dbi *dbi);
* </ul>
*/
int mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *stat);
#if MDBX_MODE_ENABLED
int mdbx_stat(MDB_txn *txn, MDB_dbi dbi, MDBX_stat *stat, size_t bytes);
#endif /* MDBX_MODE_ENABLED */
/** @brief Retrieve the DB flags for a database handle.
*
@ -1597,6 +1633,7 @@ int mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx);
*/
int mdb_reader_check(MDB_env *env, int *dead);
#if MDBX_MODE_ENABLED
/** @brief Returns a lag of the reading.
*
* Returns an information for estimate how much given read-only
@ -1606,7 +1643,7 @@ int mdb_reader_check(MDB_env *env, int *dead);
* @param[out] percent Percentage of page allocation in the database.
* @return Number of transactions committed after the given was started for read, or -1 on failure.
*/
int mdb_txn_straggler(MDB_txn *txnm, int *percent);
int mdbx_txn_straggler(MDB_txn *txnm, int *percent);
/** @brief A callback function for killing a laggard readers,
* called in case of MDB_MAP_FULL error.
@ -1630,7 +1667,7 @@ typedef int (MDB_oom_func)(MDB_env *env, int pid, void* thread_id, size_t txn, u
* @param[in] env An environment handle returned by #mdb_env_create().
* @param[in] oomfunc A #MDB_oom_func function or NULL to disable.
*/
void mdb_env_set_oomfunc(MDB_env *env, MDB_oom_func *oom_func);
void mdbx_env_set_oomfunc(MDB_env *env, MDB_oom_func *oom_func);
/** @brief Get the current oom_func callback.
*
@ -1640,9 +1677,11 @@ void mdb_env_set_oomfunc(MDB_env *env, MDB_oom_func *oom_func);
* @param[in] env An environment handle returned by #mdb_env_create().
* @return A #MDB_oom_func function or NULL if disabled.
*/
MDB_oom_func* mdb_env_get_oomfunc(MDB_env *env);
MDB_oom_func* mdbx_env_get_oomfunc(MDB_env *env);
#endif /* MDBX_MODE_ENABLED */
/** @} */
#if MDBX_MODE_ENABLED
#define MDB_DBG_ASSERT 1
#define MDB_DBG_PRINT 2
#define MDB_DBG_TRACE 4
@ -1656,12 +1695,13 @@ MDB_oom_func* mdb_env_get_oomfunc(MDB_env *env);
typedef void MDB_debug_func(int type, const char *function, int line,
const char *msg, va_list args);
int mdb_setup_debug(int flags, MDB_debug_func* logger, long edge_txn);
int mdbx_setup_debug(int flags, MDB_debug_func* logger, long edge_txn);
typedef int MDB_pgvisitor_func(size_t pgno, unsigned pgnumber, void* ctx,
const char* dbi, const char *type, int nentries,
int payload_bytes, int header_bytes, int unused_bytes);
int mdb_env_pgwalk(MDB_txn *txn, MDB_pgvisitor_func* visitor, void* ctx);
int mdbx_env_pgwalk(MDB_txn *txn, MDB_pgvisitor_func* visitor, void* ctx);
#endif /* MDBX_MODE_ENABLED */
char* mdb_dkey(MDB_val *key, char *buf);
@ -1669,7 +1709,8 @@ char* mdb_dkey(MDB_val *key, char *buf);
}
#endif
/** @page tools LMDB Command Line Tools
The following describes the command line tools that are available for LMDB.
The following describes the command line tools that are available for LMDBX.
\li \ref mdb_chk_1
\li \ref mdb_copy_1
\li \ref mdb_dump_1
\li \ref mdb_load_1

379
mdb.c
View File

@ -37,8 +37,8 @@
# define MDB_DEBUG 0
#endif
#include "reopen.h"
#include "barriers.h"
#include "./reopen.h"
#include "./barriers.h"
#include <sys/types.h>
#include <sys/stat.h>
@ -96,8 +96,19 @@
# define MISALIGNED_OK 1
#endif
#include "lmdb.h"
#include "midl.h"
#include "./lmdb.h"
#include "./midl.h"
#if ! MDBX_MODE_ENABLED
# define MDB_COALESCE 0
# define MDB_LIFORECLAIM 0
# define MDB_DBG_ASSERT 0
# define MDB_DBG_PRINT 0
# define MDB_DBG_TRACE 0
# define MDB_DBG_EXTRA 0
# define MDB_DBG_AUDIT 0
# define MDB_DBG_EDGE 0
#endif
#if (BYTE_ORDER == LITTLE_ENDIAN) == (BYTE_ORDER == BIG_ENDIAN)
# error "Unknown or unsupported endianness (BYTE_ORDER)"
@ -105,17 +116,6 @@
# error "Two's complement, reasonably sized integer types, please"
#endif
#ifdef __GNUC__
/** Put infrequently used env functions in separate section */
# ifdef __APPLE__
# define ESECT __attribute__ ((section("__TEXT,text_env")))
# else
# define ESECT __attribute__ ((section("text_env")))
# endif
#else
# define ESECT
#endif
/** @defgroup internal LMDB Internals
* @{
*/
@ -955,7 +955,9 @@ struct MDB_env {
#endif
uint64_t me_sync_pending; /**< Total dirty/commited bytes since the last mdb_env_sync() */
uint64_t me_sync_threshold; /**< Treshold of above to force synchronous flush */
#if MDBX_MODE_ENABLED
MDB_oom_func *me_oom_func; /**< Callback for kicking laggard readers */
#endif
#ifdef USE_VALGRIND
int me_valgrind_handle;
#endif
@ -1067,7 +1069,7 @@ static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int_ai, mdb_cmp_int_a2,
/** @endcond */
/** Return the library version info. */
char * ESECT
char * __cold
mdb_version(int *major, int *minor, int *patch)
{
if (major) *major = MDB_VERSION_MAJOR;
@ -1100,7 +1102,7 @@ static char *const mdb_errstr[] = {
"MDB_BAD_DBI: The specified DBI handle was closed/changed unexpectedly",
};
char * ESECT
char * __cold
mdb_strerror(int err)
{
int i;
@ -1115,6 +1117,8 @@ mdb_strerror(int err)
return strerror(err);
}
#if MDBX_MODE_ENABLED
int mdb_runtime_flags = MDB_DBG_PRINT
#if MDB_DEBUG
| MDB_DBG_ASSERT
@ -1132,12 +1136,17 @@ int mdb_runtime_flags = MDB_DBG_PRINT
static MDB_debug_func *mdb_debug_logger;
#else /* MDBX_MODE_ENABLED */
# define mdb_runtime_flags 0
# define mdb_debug_logger ((void (*)(int, ...)) NULL)
#endif /* ! MDBX_MODE_ENABLED */
#if MDB_DEBUG
static txnid_t mdb_debug_edge;
static void mdb_debug_log(int type, const char *function, int line,
const char *fmt, ...);
static void ESECT
static void __cold
mdb_assert_fail(MDB_env *env, const char *msg,
const char *func, int line)
{
@ -1168,8 +1177,9 @@ static MDB_debug_func *mdb_debug_logger;
__assert_fail(msg, __FILE__, line, func)
#endif /* MDB_DEBUG */
int ESECT
mdb_setup_debug(int flags, MDB_debug_func* logger, long edge_txn) {
#if MDBX_MODE_ENABLED
int __cold
mdbx_setup_debug(int flags, MDB_debug_func* logger, long edge_txn) {
unsigned ret = mdb_runtime_flags;
if (flags != (int) MDB_DBG_DNT)
mdb_runtime_flags = flags;
@ -1181,8 +1191,9 @@ mdb_setup_debug(int flags, MDB_debug_func* logger, long edge_txn) {
#endif
return ret;
}
#endif /* MDBX_MODE_ENABLED */
static void ESECT
static void __cold
mdb_debug_log(int type, const char *function, int line,
const char *fmt, ...)
{
@ -1881,17 +1892,14 @@ mdb_find_oldest(MDB_env *env, int *laggard)
return oldest;
}
static int ESECT
static int __cold
mdb_oomkick(MDB_env *env, txnid_t oldest)
{
int retry;
txnid_t snap;
for(retry = 0; ; ++retry) {
MDB_reader *r;
pthread_t tid;
pid_t pid;
int rc, reader;
int reader;
if (mdb_reader_check(env, NULL))
break;
@ -1903,28 +1911,39 @@ mdb_oomkick(MDB_env *env, txnid_t oldest)
if (reader < 0)
return 0;
if (!env->me_oom_func)
break;
#if MDBX_MODE_ENABLED
{
MDB_reader *r;
pthread_t tid;
pid_t pid;
int rc;
r = &env->me_txns->mti_readers[ reader ];
pid = r->mr_pid;
tid = r->mr_tid;
if (r->mr_txnid != oldest || pid <= 0)
continue;
if (!env->me_oom_func)
break;
rc = env->me_oom_func(env, pid, (void*) tid, oldest,
mdb_meta_head_w(env)->mm_txnid - oldest, retry);
if (rc < 0)
break;
r = &env->me_txns->mti_readers[ reader ];
pid = r->mr_pid;
tid = r->mr_tid;
if (r->mr_txnid != oldest || pid <= 0)
continue;
if (rc) {
r->mr_txnid = (txnid_t)-1L;
if (rc > 1) {
r->mr_tid = 0;
r->mr_pid = 0;
mdb_coherent_barrier();
rc = env->me_oom_func(env, pid, (void*) tid, oldest,
mdb_meta_head_w(env)->mm_txnid - oldest, retry);
if (rc < 0)
break;
if (rc) {
r->mr_txnid = (txnid_t)-1L;
if (rc > 1) {
r->mr_tid = 0;
r->mr_pid = 0;
mdb_coherent_barrier();
}
}
}
#else
break;
#endif /* MDBX_MODE_ENABLED */
}
snap = mdb_find_oldest(env, NULL);
@ -2958,7 +2977,7 @@ mdb_dbis_update(MDB_txn *txn, int keep)
}
int
mdb_txn_straggler(MDB_txn *txn, int *percent)
mdbx_txn_straggler(MDB_txn *txn, int *percent)
{
MDB_env *env;
MDB_meta *meta;
@ -3777,7 +3796,7 @@ fail:
return rc;
}
int ESECT
int __cold
mdb_env_set_syncbytes(MDB_env *env, size_t bytes) {
env->me_sync_threshold = bytes;
return env->me_map ? mdb_env_sync(env, 0) : 0;
@ -3789,7 +3808,7 @@ mdb_env_set_syncbytes(MDB_env *env, size_t bytes) {
* @param[out] meta address of where to store the meta information
* @return 0 on success, non-zero on failure.
*/
static int ESECT
static int __cold
mdb_env_read_header(MDB_env *env, MDB_meta *meta)
{
MDB_metabuf pbuf;
@ -3848,7 +3867,7 @@ mdb_env_read_header(MDB_env *env, MDB_meta *meta)
}
/** Fill in most of the zeroed #MDB_meta for an empty database environment */
static void ESECT
static void __cold
mdb_env_init_meta0(MDB_env *env, MDB_meta *meta)
{
meta->mm_magic = MDB_MAGIC;
@ -3868,7 +3887,7 @@ mdb_env_init_meta0(MDB_env *env, MDB_meta *meta)
* @param[in] meta the #MDB_meta to write
* @return 0 on success, non-zero on failure.
*/
static int ESECT
static int __cold
mdb_env_init_meta(MDB_env *env, MDB_meta *meta)
{
MDB_page *p, *q;
@ -4063,7 +4082,7 @@ fail:
return rc;
}
int ESECT
int __cold
mdb_env_create(MDB_env **env)
{
MDB_env *e;
@ -4083,7 +4102,7 @@ mdb_env_create(MDB_env **env)
return MDB_SUCCESS;
}
static int ESECT
static int __cold
mdb_env_map(MDB_env *env, void *addr)
{
unsigned flags = env->me_flags;
@ -4133,7 +4152,7 @@ mdb_env_map(MDB_env *env, void *addr)
return MDB_SUCCESS;
}
int ESECT
int __cold
mdb_env_set_mapsize(MDB_env *env, size_t size)
{
/* If env is already open, caller is responsible for making
@ -4171,7 +4190,7 @@ mdb_env_set_mapsize(MDB_env *env, size_t size)
return MDB_SUCCESS;
}
int ESECT
int __cold
mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs)
{
if (env->me_map)
@ -4180,7 +4199,7 @@ mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs)
return MDB_SUCCESS;
}
int ESECT
int __cold
mdb_env_set_maxreaders(MDB_env *env, unsigned readers)
{
if (env->me_map || readers < 1)
@ -4189,7 +4208,7 @@ mdb_env_set_maxreaders(MDB_env *env, unsigned readers)
return MDB_SUCCESS;
}
int ESECT
int __cold
mdb_env_get_maxreaders(MDB_env *env, unsigned *readers)
{
if (!env || !readers)
@ -4198,7 +4217,7 @@ mdb_env_get_maxreaders(MDB_env *env, unsigned *readers)
return MDB_SUCCESS;
}
static int ESECT
static int __cold
mdb_fsize(HANDLE fd, size_t *size)
{
struct stat st;
@ -4212,7 +4231,7 @@ mdb_fsize(HANDLE fd, size_t *size)
/** Further setup required for opening an LMDB environment
*/
static int ESECT
static int __cold
mdb_env_open2(MDB_env *env, MDB_meta *meta)
{
unsigned flags = env->me_flags;
@ -4319,7 +4338,7 @@ mdb_env_reader_dest(void *ptr)
}
/** Downgrade the exclusive lock on the region back to shared */
static int ESECT
static int __cold
mdb_env_share_locks(MDB_env *env, int *excl, MDB_meta *meta)
{
struct flock lock_info;
@ -4341,7 +4360,7 @@ mdb_env_share_locks(MDB_env *env, int *excl, MDB_meta *meta)
/** Try to get exclusive lock, otherwise shared.
* Maintain *excl = -1: no/unknown lock, 0: shared, 1: exclusive.
*/
static int ESECT
static int __cold
mdb_env_excl_lock(MDB_env *env, int *excl)
{
int rc = 0;
@ -4436,7 +4455,7 @@ mdb_hash_val(MDB_val *val, mdb_hash_t hval)
*/
static const char mdb_a85[]= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
static void ESECT
static void __cold
mdb_pack85(unsigned long l, char *out)
{
int i;
@ -4447,7 +4466,7 @@ mdb_pack85(unsigned long l, char *out)
}
}
static void ESECT
static void __cold
mdb_hash_enc(MDB_val *val, char *encbuf)
{
mdb_hash_t h = mdb_hash_val(val, MDB_HASH_INIT);
@ -4465,7 +4484,7 @@ mdb_hash_enc(MDB_val *val, char *encbuf)
* @param[in,out] excl In -1, out lock type: -1 none, 0 shared, 1 exclusive
* @return 0 on success, non-zero on failure.
*/
static int ESECT
static int __cold
mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
{
int fdflags;
@ -4576,14 +4595,11 @@ fail:
# error "Persistent DB flags & env flags overlap, but both go in mm_flags"
#endif
int ESECT
mdb_env_open(MDB_env *env, const char *path, unsigned flags, mode_t mode)
{
return mdb_env_open_ex(env, path, flags, mode, NULL);
}
int ESECT
mdb_env_open_ex(MDB_env *env, const char *path, unsigned flags, mode_t mode, int *exclusive)
#if !MDBX_MODE_ENABLED
static
#endif /* !MDBX_MODE_ENABLED*/
int __cold
mdbx_env_open_ex(MDB_env *env, const char *path, unsigned flags, mode_t mode, int *exclusive)
{
int oflags, rc, len, excl = -1;
char *lpath, *dpath;
@ -4720,8 +4736,14 @@ leave:
return rc;
}
int __cold
mdb_env_open(MDB_env *env, const char *path, unsigned flags, mode_t mode)
{
return mdbx_env_open_ex(env, path, flags, mode, NULL);
}
/** Destroy resources from mdb_env_open(), clear our readers & DBIs */
static void ESECT
static void __cold
mdb_env_close0(MDB_env *env)
{
int i;
@ -4791,14 +4813,11 @@ mdb_env_close0(MDB_env *env)
env->me_flags &= ~(MDB_ENV_ACTIVE|MDB_ENV_TXKEY);
}
void ESECT
mdb_env_close(MDB_env *env)
{
mdb_env_close_ex(env, 0);
}
void ESECT
mdb_env_close_ex(MDB_env *env, int dont_sync)
#if !MDBX_MODE_ENABLED
static
#endif /* !MDBX_MODE_ENABLED*/
void __cold
mdbx_env_close_ex(MDB_env *env, int dont_sync)
{
MDB_page *dp;
@ -4819,6 +4838,12 @@ mdb_env_close_ex(MDB_env *env, int dont_sync)
free(env);
}
void __cold
mdb_env_close(MDB_env *env)
{
mdbx_env_close_ex(env, 0);
}
/** Compare two items pointing at aligned unsigned int's. */
static long
mdb_cmp_int_ai(const MDB_val *a, const MDB_val *b)
@ -8527,7 +8552,7 @@ typedef struct mdb_copy {
} mdb_copy;
/** Dedicated writer thread for compacting copy. */
static void* ESECT
static void* __cold
mdb_env_copythr(void *arg)
{
mdb_copy *my = arg;
@ -8585,7 +8610,7 @@ again:
}
/** Tell the writer thread there's a buffer ready to write */
static int ESECT
static int __cold
mdb_env_cthr_toggle(mdb_copy *my, int st)
{
int toggle = my->mc_toggle ^ 1;
@ -8604,7 +8629,7 @@ mdb_env_cthr_toggle(mdb_copy *my, int st)
}
/** Depth-first tree traversal for compacting copy. */
static int ESECT
static int __cold
mdb_env_cwalk(mdb_copy *my, pgno_t *pg, int flags)
{
MDB_cursor mc;
@ -8762,7 +8787,7 @@ done:
}
/** Copy environment with compaction. */
static int ESECT
static int __cold
mdb_env_copyfd1(MDB_env *env, HANDLE fd)
{
MDB_meta *mm;
@ -8858,7 +8883,7 @@ mdb_env_copyfd1(MDB_env *env, HANDLE fd)
}
/** Copy environment as-is. */
static int ESECT
static int __cold
mdb_env_copyfd0(MDB_env *env, HANDLE fd)
{
MDB_txn *txn = NULL;
@ -8949,7 +8974,7 @@ leave:
return rc;
}
int ESECT
int __cold
mdb_env_copyfd2(MDB_env *env, HANDLE fd, unsigned flags)
{
if (flags & MDB_CP_COMPACT)
@ -8958,13 +8983,13 @@ mdb_env_copyfd2(MDB_env *env, HANDLE fd, unsigned flags)
return mdb_env_copyfd0(env, fd);
}
int ESECT
int __cold
mdb_env_copyfd(MDB_env *env, HANDLE fd)
{
return mdb_env_copyfd2(env, fd, 0);
}
int ESECT
int __cold
mdb_env_copy2(MDB_env *env, const char *path, unsigned flags)
{
int rc, len;
@ -9019,13 +9044,13 @@ leave:
return rc;
}
int ESECT
int __cold
mdb_env_copy(MDB_env *env, const char *path)
{
return mdb_env_copy2(env, path, 0);
}
int ESECT
int __cold
mdb_env_set_flags(MDB_env *env, unsigned flag, int onoff)
{
if (unlikely(flag & ~CHANGEABLE))
@ -9037,7 +9062,7 @@ mdb_env_set_flags(MDB_env *env, unsigned flag, int onoff)
return MDB_SUCCESS;
}
int ESECT
int __cold
mdb_env_get_flags(MDB_env *env, unsigned *arg)
{
if (unlikely(!env || !arg))
@ -9047,7 +9072,7 @@ mdb_env_get_flags(MDB_env *env, unsigned *arg)
return MDB_SUCCESS;
}
int ESECT
int __cold
mdb_env_set_userctx(MDB_env *env, void *ctx)
{
if (unlikely(!env))
@ -9056,13 +9081,13 @@ mdb_env_set_userctx(MDB_env *env, void *ctx)
return MDB_SUCCESS;
}
void * ESECT
void * __cold
mdb_env_get_userctx(MDB_env *env)
{
return env ? env->me_userctx : NULL;
}
int ESECT
int __cold
mdb_env_set_assert(MDB_env *env, MDB_assert_func *func)
{
if (unlikely(!env))
@ -9073,7 +9098,7 @@ mdb_env_set_assert(MDB_env *env, MDB_assert_func *func)
return MDB_SUCCESS;
}
int ESECT
int __cold
mdb_env_get_path(MDB_env *env, const char **arg)
{
if (unlikely(!env || !arg))
@ -9083,7 +9108,7 @@ mdb_env_get_path(MDB_env *env, const char **arg)
return MDB_SUCCESS;
}
int ESECT
int __cold
mdb_env_get_fd(MDB_env *env, mdb_filehandle_t *arg)
{
if (unlikely(!env || !arg))
@ -9099,7 +9124,7 @@ mdb_env_get_fd(MDB_env *env, mdb_filehandle_t *arg)
* @param[out] arg the address of an #MDB_stat structure to receive the stats.
* @return 0, this function always succeeds.
*/
static int ESECT
static int __cold
mdb_stat0(MDB_env *env, MDB_db *db, MDB_stat *arg)
{
arg->ms_psize = env->me_psize;
@ -9112,61 +9137,99 @@ mdb_stat0(MDB_env *env, MDB_db *db, MDB_stat *arg)
return MDB_SUCCESS;
}
int ESECT
#if !MDBX_MODE_ENABLED
static
#endif /* !MDBX_MODE_ENABLED*/
int __cold
mdbx_env_stat(MDB_env *env, MDBX_stat *arg, size_t bytes)
{
MDB_meta *meta;
if (unlikely(env == NULL || arg == NULL))
return EINVAL;
if (unlikely(bytes != sizeof(MDBX_stat)))
return EINVAL;
meta = mdb_meta_head_r(env);
return mdb_stat0(env, &meta->mm_dbs[MAIN_DBI], &arg->base);
}
int __cold
mdb_env_stat(MDB_env *env, MDB_stat *arg)
{
return mdbx_env_stat(env, (MDBX_stat *) arg, sizeof(MDB_stat));
}
#if !MDBX_MODE_ENABLED
static
#endif /* !MDBX_MODE_ENABLED*/
int __cold mdbx_env_info(MDB_env *env, MDBX_envinfo *arg, size_t bytes)
{
MDB_meta *meta;
if (unlikely(env == NULL || arg == NULL))
return EINVAL;
meta = mdb_meta_head_r(env);
return mdb_stat0(env, &meta->mm_dbs[MAIN_DBI], arg);
}
if (bytes == sizeof(MDB_envinfo)) {
do {
meta = mdb_meta_head_r(env);
arg->base.me_last_txnid = meta->mm_txnid;
arg->base.me_last_pgno = meta->mm_last_pg;
arg->base.me_mapaddr = meta->mm_address;
arg->base.me_mapsize = env->me_mapsize;
arg->base.me_maxreaders = env->me_maxreaders;
arg->base.me_numreaders = env->me_txns->mti_numreaders;
} while (unlikely( arg->base.me_last_txnid != env->me_txns->mti_txnid));
#if MDBX_MODE_ENABLED
} else if (bytes == sizeof(MDBX_envinfo)) {
MDB_meta *m1, *m2;
MDB_reader *r;
int i;
int ESECT
mdb_env_info(MDB_env *env, MDB_envinfo *arg)
{
MDB_meta *meta, *m1, *m2;
m1 = METAPAGE_1(env);
m2 = METAPAGE_2(env);
if (unlikely(env == NULL || arg == NULL))
return EINVAL;
do {
meta = mdb_meta_head_r(env);
arg->base.me_last_txnid = meta->mm_txnid;
arg->base.me_last_pgno = meta->mm_last_pg;
arg->me_meta1_txnid = m1->mm_txnid;
arg->me_meta1_sign = m1->mm_datasync_sign;
arg->me_meta2_txnid = m2->mm_txnid;
arg->me_meta2_sign = m2->mm_datasync_sign;
} while (unlikely( arg->base.me_last_txnid != env->me_txns->mti_txnid
|| arg->me_meta1_sign != m1->mm_datasync_sign
|| arg->me_meta2_sign != m2->mm_datasync_sign ));
m1 = METAPAGE_1(env);
m2 = METAPAGE_2(env);
arg->base.me_mapaddr = meta->mm_address;
arg->base.me_mapsize = env->me_mapsize;
arg->base.me_maxreaders = env->me_maxreaders;
arg->base.me_numreaders = env->me_txns->mti_numreaders;
arg->me_tail_txnid = 0;
arg->me_mapsize = env->me_mapsize;
arg->me_maxreaders = env->me_maxreaders;
arg->me_numreaders = env->me_txns->mti_numreaders;
do {
meta = mdb_meta_head_r(env);
arg->me_meta1_txnid = m1->mm_txnid;
arg->me_meta1_sign = m1->mm_datasync_sign;
arg->me_meta2_txnid = m2->mm_txnid;
arg->me_meta2_sign = m2->mm_datasync_sign;
arg->me_last_pgno = meta->mm_last_pg;
arg->me_last_txnid = meta->mm_txnid;
} while (unlikely( meta->mm_txnid != env->me_txns->mti_txnid
|| arg->me_meta1_sign != m1->mm_datasync_sign
|| arg->me_meta2_sign != m2->mm_datasync_sign ));
arg->me_mapaddr = meta->mm_address;
arg->me_tail_txnid = 0;
MDB_reader *r = env->me_txns->mti_readers;
int i;
arg->me_tail_txnid = arg->me_last_txnid;
for (i = arg->me_numreaders; --i >= 0; ) {
if (r[i].mr_pid) {
txnid_t mr = r[i].mr_txnid;
if (arg->me_tail_txnid > mr)
arg->me_tail_txnid = mr;
r = env->me_txns->mti_readers;
arg->me_tail_txnid = arg->base.me_last_txnid;
for (i = 0; i < arg->base.me_numreaders; ++i ) {
if (r[i].mr_pid) {
txnid_t mr = r[i].mr_txnid;
if (arg->me_tail_txnid > mr)
arg->me_tail_txnid = mr;
}
}
#endif /* MDBX_MODE_ENABLED */
} else {
return EINVAL;
}
return MDB_SUCCESS;
}
int __cold
mdb_env_info(MDB_env *env, MDB_envinfo *arg)
{
return mdbx_env_info(env, (MDBX_envinfo*) arg, sizeof(MDB_envinfo));
}
/** Set the default comparison functions for a database.
* Called immediately after a database is opened to set the defaults.
* The user can then override them with #mdb_set_compare() or
@ -9293,12 +9356,18 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned flags, MDB_dbi *dbi)
return rc;
}
int ESECT
mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg)
#if ! MDBX_MODE_ENABLED
static
#endif
int __cold
mdbx_stat(MDB_txn *txn, MDB_dbi dbi, MDBX_stat *arg, size_t bytes)
{
if (!arg || unlikely(!TXN_DBI_EXIST(txn, dbi, DB_VALID)))
return EINVAL;
if (unlikely(bytes != sizeof(MDBX_stat)))
return EINVAL;
if (unlikely(txn->mt_flags & MDB_TXN_BLOCKED))
return MDB_BAD_TXN;
@ -9308,7 +9377,13 @@ mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg)
/* Stale, must read the DB's root. cursor_init does it for us. */
mdb_cursor_init(&mc, txn, dbi, &mx);
}
return mdb_stat0(txn->mt_env, &txn->mt_dbs[dbi], arg);
return mdb_stat0(txn->mt_env, &txn->mt_dbs[dbi], &arg->base);
}
int __cold
mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg)
{
return mdbx_stat(txn, dbi, (MDBX_stat*) arg, sizeof(MDB_stat));
}
void mdb_dbi_close(MDB_env *env, MDB_dbi dbi)
@ -9511,13 +9586,13 @@ int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx)
return MDB_SUCCESS;
}
int ESECT
int __cold
mdb_env_get_maxkeysize(MDB_env *env)
{
return ENV_MAXKEY(env);
}
int ESECT
int __cold
mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx)
{
unsigned i, rdrs;
@ -9560,7 +9635,7 @@ mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx)
/** Insert pid into list if not already present.
* return -1 if already present.
*/
static int ESECT
static int __cold
mdb_pid_insert(pid_t *ids, pid_t pid)
{
/* binary search of pid in list */
@ -9597,7 +9672,7 @@ mdb_pid_insert(pid_t *ids, pid_t pid)
return 0;
}
int ESECT
int __cold
mdb_reader_check(MDB_env *env, int *dead)
{
if (!env)
@ -9608,7 +9683,7 @@ mdb_reader_check(MDB_env *env, int *dead)
}
/** As #mdb_reader_check(). rlocked = <caller locked the reader mutex>. */
static int ESECT
static int __cold
mdb_reader_check0(MDB_env *env, int rlocked, int *dead)
{
pthread_mutex_t *rmutex = rlocked ? NULL : MDB_MUTEX(env, r);
@ -9662,7 +9737,7 @@ mdb_reader_check0(MDB_env *env, int rlocked, int *dead)
return rc;
}
static int ESECT
static int __cold
mdb_mutex_failed(MDB_env *env, pthread_mutex_t *mutex, int rc)
{
#ifdef EOWNERDEAD
@ -9724,15 +9799,17 @@ static void mdb_mutex_unlock(MDB_env *env, pthread_mutex_t *mutex) {
mdb_assert(env, rc == 0);
}
void ESECT
mdb_env_set_oomfunc(MDB_env *env, MDB_oom_func *oomfunc)
#if MDBX_MODE_ENABLED
void __cold
mdbx_env_set_oomfunc(MDB_env *env, MDB_oom_func *oomfunc)
{
if (env)
env->me_oom_func = oomfunc;
}
MDB_oom_func* ESECT
mdb_env_get_oomfunc(MDB_env *env)
MDB_oom_func* __cold
mdbx_env_get_oomfunc(MDB_env *env)
{
return env ? env->me_oom_func : NULL;
}
@ -9747,7 +9824,7 @@ typedef struct mdb_walk_ctx mdb_walk_ctx_t;
/** Depth-first tree traversal. */
static int ESECT
static int __cold
mdb_env_walk(mdb_walk_ctx_t *ctx, const char* dbi, pgno_t pg, int flags, int deep)
{
MDB_page *mp;
@ -9871,8 +9948,8 @@ mdb_env_walk(mdb_walk_ctx_t *ctx, const char* dbi, pgno_t pg, int flags, int dee
nkeys, payload_size, header_size, unused_size + align_bytes);
}
int ESECT
mdb_env_pgwalk(MDB_txn *txn, MDB_pgvisitor_func* visitor, void* user)
int __cold
mdbx_env_pgwalk(MDB_txn *txn, MDB_pgvisitor_func* visitor, void* user)
{
mdb_walk_ctx_t ctx;
int rc;
@ -9892,4 +9969,8 @@ mdb_env_pgwalk(MDB_txn *txn, MDB_pgvisitor_func* visitor, void* user)
return rc;
}
#endif /* MDBX_MODE_ENABLED */
/** @} */
#include "./midl.c"

174
mdb_chk.c
View File

@ -17,7 +17,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* mdb_chk.c - memory-mapped database check tool */
/* mdbx_chk.c - memory-mapped database check tool */
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
@ -29,8 +29,8 @@
#include <malloc.h>
#include <time.h>
#include "lmdb.h"
#include "midl.h"
#include "mdbx.h"
typedef struct flagbit {
int bit;
@ -79,8 +79,8 @@ int exclusive = 2;
MDB_env *env;
MDB_txn *txn, *locktxn;
MDB_envinfo info;
MDB_stat stat;
MDBX_envinfo info;
MDBX_stat stat;
size_t maxkeysize, reclaimable_pages, freedb_pages, lastpgno;
size_t userdb_count, skipped_subdb;
unsigned verbose, quiet;
@ -215,7 +215,7 @@ static int pgvisitor(size_t pgno, unsigned pgnumber, void* ctx, const char* dbi,
{
if (type) {
size_t page_bytes = payload_bytes + header_bytes + unused_bytes;
size_t page_size = pgnumber * stat.ms_psize;
size_t page_size = pgnumber * stat.base.ms_psize;
int index = pagemap_lookup_dbi(dbi);
if (index < 0)
return ENOMEM;
@ -233,11 +233,11 @@ static int pgvisitor(size_t pgno, unsigned pgnumber, void* ctx, const char* dbi,
if (unused_bytes < 0 || (size_t) unused_bytes > page_size)
problem_add("page", pgno, "illegal unused-bytes", "%zu < %i < %zu",
0, unused_bytes, stat.ms_psize);
0, unused_bytes, stat.base.ms_psize);
if (header_bytes < sizeof(long) || header_bytes >= stat.ms_psize - sizeof(long))
if (header_bytes < sizeof(long) || header_bytes >= stat.base.ms_psize - sizeof(long))
problem_add("page", pgno, "illegal header-length", "%zu < %i < %zu",
sizeof(long), header_bytes, stat.ms_psize - sizeof(long));
sizeof(long), header_bytes, stat.base.ms_psize - sizeof(long));
if (payload_bytes < 1) {
if (nentries > 0) {
problem_add("page", pgno, "zero size-of-entry", "payload %i bytes, %i entries",
@ -298,7 +298,7 @@ static int handle_freedb(size_t record_number, MDB_val *key, MDB_val* data) {
if (key->mv_size != sizeof(txnid))
problem_add("entry", record_number, "wrong txn-id size", "key-size %zi", key->mv_size);
else if (txnid < 1 || txnid > info.me_last_txnid)
else if (txnid < 1 || txnid > info.base.me_last_txnid)
problem_add("entry", record_number, "wrong txn-id", "%zu", txnid);
if (data->mv_size < sizeof(size_t) || data->mv_size % sizeof(size_t))
@ -316,9 +316,9 @@ static int handle_freedb(size_t record_number, MDB_val *key, MDB_val* data) {
reclaimable_pages += number;
for (i = number, prev = 1; --i >= 0; ) {
pg = iptr[i];
if (pg < 2 /* META_PAGE */ || pg > info.me_last_pgno)
if (pg < 2 /* META_PAGE */ || pg > info.base.me_last_pgno)
problem_add("entry", record_number, "wrong idl entry", "2 < %zi < %zi",
pg, info.me_last_pgno);
pg, info.base.me_last_pgno);
else if (pg <= prev) {
bad = " [bad sequence]";
problem_add("entry", record_number, "bad sequence", "%zi <= %zi",
@ -375,7 +375,7 @@ static int handle_maindb(size_t record_number, MDB_val *key, MDB_val* data) {
static int process_db(MDB_dbi dbi, char *name, visitor *handler, int silent)
{
MDB_cursor *mc;
MDB_stat ms;
MDBX_stat ms;
MDB_val key, data;
MDB_val prev_key, prev_data;
unsigned flags;
@ -387,11 +387,11 @@ static int process_db(MDB_dbi dbi, char *name, visitor *handler, int silent)
size_t key_bytes = 0, data_bytes = 0;
if (0 > (int) dbi) {
rc = mdb_dbi_open(txn, name, 0, &dbi);
rc = mdbx_dbi_open(txn, name, 0, &dbi);
if (rc) {
if (!name || rc != MDB_INCOMPATIBLE) /* LY: mainDB's record is not a user's DB. */ {
error(" - mdb_open '%s' failed, error %d %s\n",
name ? name : "main", rc, mdb_strerror(rc));
error(" - mdbx_open '%s' failed, error %d %s\n",
name ? name : "main", rc, mdbx_strerror(rc));
}
return rc;
}
@ -403,7 +403,7 @@ static int process_db(MDB_dbi dbi, char *name, visitor *handler, int silent)
fflush(NULL);
}
skipped_subdb++;
mdb_dbi_close(env, dbi);
mdbx_dbi_close(env, dbi);
return MDB_SUCCESS;
}
@ -412,17 +412,17 @@ static int process_db(MDB_dbi dbi, char *name, visitor *handler, int silent)
fflush(NULL);
}
rc = mdb_dbi_flags(txn, dbi, &flags);
rc = mdbx_dbi_flags(txn, dbi, &flags);
if (rc) {
error(" - mdb_dbi_flags failed, error %d %s\n", rc, mdb_strerror(rc));
mdb_dbi_close(env, dbi);
error(" - mdbx_dbi_flags failed, error %d %s\n", rc, mdbx_strerror(rc));
mdbx_dbi_close(env, dbi);
return rc;
}
rc = mdb_stat(txn, dbi, &ms);
rc = mdbx_stat(txn, dbi, &ms, sizeof(ms));
if (rc) {
error(" - mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
mdb_dbi_close(env, dbi);
error(" - mdbx_stat failed, error %d %s\n", rc, mdbx_strerror(rc));
mdbx_dbi_close(env, dbi);
return rc;
}
@ -437,23 +437,23 @@ static int process_db(MDB_dbi dbi, char *name, visitor *handler, int silent)
}
print(" (0x%02X)\n", flags);
if (verbose > 1) {
print(" - page size %u, entries %zu\n", ms.ms_psize, ms.ms_entries);
print(" - page size %u, entries %zu\n", ms.base.ms_psize, ms.base.ms_entries);
print(" - b-tree depth %u, pages: branch %zu, leaf %zu, overflow %zu\n",
ms.ms_depth, ms.ms_branch_pages, ms.ms_leaf_pages, ms.ms_overflow_pages);
ms.base.ms_depth, ms.base.ms_branch_pages, ms.base.ms_leaf_pages, ms.base.ms_overflow_pages);
}
}
rc = mdb_cursor_open(txn, dbi, &mc);
rc = mdbx_cursor_open(txn, dbi, &mc);
if (rc) {
error(" - mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
mdb_dbi_close(env, dbi);
error(" - mdbx_cursor_open failed, error %d %s\n", rc, mdbx_strerror(rc));
mdbx_dbi_close(env, dbi);
return rc;
}
saved_list = problems_push();
prev_key.mv_data = NULL;
prev_data.mv_size = 0;
rc = mdb_cursor_get(mc, &key, &data, MDB_FIRST);
rc = mdbx_cursor_get(mc, &key, &data, MDB_FIRST);
while (rc == MDB_SUCCESS) {
if (gotsignal) {
print(" - interrupted by signal\n");
@ -485,7 +485,7 @@ static int process_db(MDB_dbi dbi, char *name, visitor *handler, int silent)
"%zu != %zu", prev_data.mv_size, data.mv_size);
}
int cmp = mdb_cmp(txn, dbi, &prev_key, &key);
int cmp = mdbx_cmp(txn, dbi, &prev_key, &key);
if (cmp > 0) {
problem_add("entry", record_count, "broken ordering of entries", NULL);
} else if (cmp == 0) {
@ -493,7 +493,7 @@ static int process_db(MDB_dbi dbi, char *name, visitor *handler, int silent)
if (! (flags & MDB_DUPSORT))
problem_add("entry", record_count, "duplicated entries", NULL);
else if (flags & MDB_INTEGERDUP) {
cmp = mdb_dcmp(txn, dbi, &prev_data, &data);
cmp = mdbx_dcmp(txn, dbi, &prev_data, &data);
if (cmp > 0)
problem_add("entry", record_count, "broken ordering of multi-values", NULL);
}
@ -517,16 +517,16 @@ static int process_db(MDB_dbi dbi, char *name, visitor *handler, int silent)
prev_key = key;
prev_data = data;
rc = mdb_cursor_get(mc, &key, &data, MDB_NEXT);
rc = mdbx_cursor_get(mc, &key, &data, MDB_NEXT);
}
if (rc != MDB_NOTFOUND)
error(" - mdb_cursor_get failed, error %d %s\n", rc, mdb_strerror(rc));
error(" - mdbx_cursor_get failed, error %d %s\n", rc, mdbx_strerror(rc));
else
rc = 0;
if (record_count != ms.ms_entries)
if (record_count != ms.base.ms_entries)
problem_add("entry", record_count, "differentent number of entries",
"%zu != %zu", record_count, ms.ms_entries);
"%zu != %zu", record_count, ms.base.ms_entries);
bailout:
problems_count = problems_pop(saved_list);
if (! silent && verbose) {
@ -535,8 +535,8 @@ bailout:
fflush(NULL);
}
mdb_cursor_close(mc);
mdb_dbi_close(env, dbi);
mdbx_cursor_close(mc);
mdbx_dbi_close(env, dbi);
return rc || problems_count;
}
@ -583,7 +583,7 @@ int main(int argc, char *argv[])
if (clock_gettime(CLOCK_MONOTONIC, &timestamp_start)) {
rc = errno;
error("clock_gettime failed, error %d %s\n", rc, mdb_strerror(rc));
error("clock_gettime failed, error %d %s\n", rc, mdbx_strerror(rc));
return EXIT_FAILURE_SYS;
}
@ -638,97 +638,97 @@ int main(int argc, char *argv[])
signal(SIGTERM, signal_hanlder);
envname = argv[optind];
print("Running mdb_chk for '%s' in %s mode...\n",
print("Running mdbx_chk for '%s' in %s mode...\n",
envname, (envflags & MDB_RDONLY) ? "read-only" : "write-lock");
fflush(NULL);
rc = mdb_env_create(&env);
rc = mdbx_env_create(&env);
if (rc) {
error("mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc));
error("mdbx_env_create failed, error %d %s\n", rc, mdbx_strerror(rc));
return rc < 0 ? EXIT_FAILURE_MDB : EXIT_FAILURE_SYS;
}
rc = mdb_env_get_maxkeysize(env);
rc = mdbx_env_get_maxkeysize(env);
if (rc < 0) {
error("mdb_env_get_maxkeysize failed, error %d %s\n", rc, mdb_strerror(rc));
error("mdbx_env_get_maxkeysize failed, error %d %s\n", rc, mdbx_strerror(rc));
goto bailout;
}
maxkeysize = rc;
mdb_env_set_maxdbs(env, 3);
mdbx_env_set_maxdbs(env, 3);
rc = mdb_env_open_ex(env, envname, envflags, 0664, &exclusive);
rc = mdbx_env_open_ex(env, envname, envflags, 0664, &exclusive);
if (rc) {
error("mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
error("mdbx_env_open failed, error %d %s\n", rc, mdbx_strerror(rc));
goto bailout;
}
if (verbose)
print(" - %s mode\n", exclusive ? "monopolistic" : "cooperative");
if (! (envflags & MDB_RDONLY)) {
rc = mdb_txn_begin(env, NULL, 0, &locktxn);
rc = mdbx_txn_begin(env, NULL, 0, &locktxn);
if (rc) {
error("mdb_txn_begin(lock-write) failed, error %d %s\n", rc, mdb_strerror(rc));
error("mdbx_txn_begin(lock-write) failed, error %d %s\n", rc, mdbx_strerror(rc));
goto bailout;
}
}
rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
rc = mdbx_txn_begin(env, NULL, MDB_RDONLY, &txn);
if (rc) {
error("mdb_txn_begin(read-only) failed, error %d %s\n", rc, mdb_strerror(rc));
error("mdbx_txn_begin(read-only) failed, error %d %s\n", rc, mdbx_strerror(rc));
goto bailout;
}
rc = mdb_env_info(env, &info);
rc = mdbx_env_info(env, &info, sizeof(info));
if (rc) {
error("mdb_env_info failed, error %d %s\n", rc, mdb_strerror(rc));
error("mdbx_env_info failed, error %d %s\n", rc, mdbx_strerror(rc));
goto bailout;
}
rc = mdb_env_stat(env, &stat);
rc = mdbx_env_stat(env, &stat, sizeof(stat));
if (rc) {
error("mdb_env_stat failed, error %d %s\n", rc, mdb_strerror(rc));
error("mdbx_env_stat failed, error %d %s\n", rc, mdbx_strerror(rc));
goto bailout;
}
lastpgno = info.me_last_pgno + 1;
lastpgno = info.base.me_last_pgno + 1;
errno = 0;
if (verbose) {
double k = 1024.0;
const char sf[] = "KMGTPEZY"; /* LY: Kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta! */
for(i = 0; sf[i+1] && info.me_mapsize / k > 1000.0; ++i)
for(i = 0; sf[i+1] && info.base.me_mapsize / k > 1000.0; ++i)
k *= 1024;
print(" - map size %zu (%.2f %cb)\n", info.me_mapsize,
info.me_mapsize / k, sf[i]);
if (info.me_mapaddr)
print(" - mapaddr %p\n", info.me_mapaddr);
print(" - map size %zu (%.2f %cb)\n", info.base.me_mapsize,
info.base.me_mapsize / k, sf[i]);
if (info.base.me_mapaddr)
print(" - mapaddr %p\n", info.base.me_mapaddr);
print(" - pagesize %u, max keysize %zu (%s), max readers %u\n",
stat.ms_psize, maxkeysize,
stat.base.ms_psize, maxkeysize,
(maxkeysize == 511) ? "default" :
(maxkeysize == 0) ? "devel" : "custom",
info.me_maxreaders);
print(" - transactions: last %zu, bottom %zu, lag reading %zi\n", info.me_last_txnid,
info.me_tail_txnid, info.me_last_txnid - info.me_tail_txnid);
info.base.me_maxreaders);
print(" - transactions: last %zu, bottom %zu, lag reading %zi\n", info.base.me_last_txnid,
info.me_tail_txnid, info.base.me_last_txnid - info.me_tail_txnid);
print(" - meta-1: %s %zu, %s",
meta_synctype(info.me_meta1_sign), info.me_meta1_txnid,
meta_lt(info.me_meta1_txnid, info.me_meta1_sign,
info.me_meta2_txnid, info.me_meta2_sign) ? "tail" : "head");
if (info.me_meta1_txnid > info.me_last_txnid)
if (info.me_meta1_txnid > info.base.me_last_txnid)
print(", rolled-back %zu (%zu >>> %zu)\n",
info.me_meta1_txnid - info.me_last_txnid,
info.me_meta1_txnid, info.me_last_txnid);
info.me_meta1_txnid - info.base.me_last_txnid,
info.me_meta1_txnid, info.base.me_last_txnid);
print("\n");
print(" - meta-2: %s %zu, %s",
meta_synctype(info.me_meta2_sign), info.me_meta2_txnid,
meta_lt(info.me_meta2_txnid, info.me_meta2_sign,
info.me_meta1_txnid, info.me_meta1_sign) ? "tail" : "head");
if (info.me_meta2_txnid > info.me_last_txnid)
if (info.me_meta2_txnid > info.base.me_last_txnid)
print(", rolled-back %zu (%zu >>> %zu)\n",
info.me_meta2_txnid - info.me_last_txnid,
info.me_meta2_txnid, info.me_last_txnid);
info.me_meta2_txnid - info.base.me_last_txnid,
info.me_meta2_txnid, info.base.me_last_txnid);
print("\n");
}
@ -738,26 +738,26 @@ int main(int argc, char *argv[])
if (! meta_lt(info.me_meta1_txnid, info.me_meta1_sign,
info.me_meta2_txnid, info.me_meta2_sign)
&& info.me_meta1_txnid != info.me_last_txnid) {
&& info.me_meta1_txnid != info.base.me_last_txnid) {
print(" - meta-1 txn-id mismatch last-txn-id (%zi != %zi)\n",
info.me_meta1_txnid, info.me_last_txnid);
info.me_meta1_txnid, info.base.me_last_txnid);
++problems_meta;
}
if (! meta_lt(info.me_meta2_txnid, info.me_meta2_sign,
info.me_meta1_txnid, info.me_meta1_sign)
&& info.me_meta2_txnid != info.me_last_txnid) {
&& info.me_meta2_txnid != info.base.me_last_txnid) {
print(" - meta-2 txn-id mismatch last-txn-id (%zi != %zi)\n",
info.me_meta2_txnid, info.me_last_txnid);
info.me_meta2_txnid, info.base.me_last_txnid);
++problems_meta;
}
} else if (locktxn) {
if (verbose)
print(" - perform lite check last-txn-id with meta-pages (not a monopolistic mode)\n");
size_t last = (info.me_meta2_txnid > info.me_meta1_txnid) ? info.me_meta2_txnid : info.me_meta1_txnid;
if (last != info.me_last_txnid) {
if (last != info.base.me_last_txnid) {
print(" - last-meta mismatch last-txn-id (%zi != %zi)\n",
last, info.me_last_txnid);
last, info.base.me_last_txnid);
++problems_meta;
}
} else if (verbose) {
@ -774,12 +774,12 @@ int main(int argc, char *argv[])
walk.pagemap = calloc(lastpgno, sizeof(*walk.pagemap));
if (! walk.pagemap) {
rc = errno ? errno : ENOMEM;
error("calloc failed, error %d %s\n", rc, mdb_strerror(rc));
error("calloc failed, error %d %s\n", rc, mdbx_strerror(rc));
goto bailout;
}
saved_list = problems_push();
rc = mdb_env_pgwalk(txn, pgvisitor, NULL);
rc = mdbx_env_pgwalk(txn, pgvisitor, NULL);
traversal_problems = problems_pop(saved_list);
if (rc) {
@ -787,7 +787,7 @@ int main(int argc, char *argv[])
print(" - interrupted by signal\n");
fflush(NULL);
} else {
error("mdb_env_pgwalk failed, error %d %s\n", rc, mdb_strerror(rc));
error("mdbx_env_pgwalk failed, error %d %s\n", rc, mdbx_strerror(rc));
}
goto bailout;
}
@ -803,7 +803,7 @@ int main(int argc, char *argv[])
}
if (verbose) {
size_t total_page_bytes = walk.pgcount * stat.ms_psize;
size_t total_page_bytes = walk.pgcount * stat.base.ms_psize;
print(" - dbi pages: %zu total", walk.pgcount);
if (verbose > 1)
for (i = 1; i < MAX_DBI && walk.dbi_names[i]; ++i)
@ -816,7 +816,7 @@ int main(int argc, char *argv[])
total_page_bytes - walk.total_payload_bytes,
(total_page_bytes - walk.total_payload_bytes) * 100.0 / total_page_bytes);
for (i = 1; i < MAX_DBI && walk.dbi_names[i]; ++i) {
size_t dbi_bytes = walk.dbi_pages[i] * stat.ms_psize;
size_t dbi_bytes = walk.dbi_pages[i] * stat.base.ms_psize;
print(" %s: subtotal %zu bytes (%.1f%%), payload %zu (%.1f%%), unused %zu (%.1f%%)",
walk.dbi_names[i],
dbi_bytes, dbi_bytes * 100.0 / total_page_bytes,
@ -848,13 +848,13 @@ int main(int argc, char *argv[])
problems_freedb = process_db(0 /* FREE_DBI */, "free", handle_freedb, 0);
if (verbose) {
size_t value = info.me_mapsize / stat.ms_psize;
size_t value = info.base.me_mapsize / stat.base.ms_psize;
double percent = value / 100.0;
print(" - pages info: %zu total", value);
print(", allocated %zu (%.1f%%)", lastpgno, lastpgno / percent);
if (verbose > 1) {
value = info.me_mapsize / stat.ms_psize - lastpgno;
value = info.base.me_mapsize / stat.base.ms_psize - lastpgno;
print(", remained %zu (%.1f%%)", value, value / percent);
value = lastpgno - freedb_pages;
@ -868,7 +868,7 @@ int main(int argc, char *argv[])
print(", reclaimable %zu (%.1f%%)", reclaimable_pages, reclaimable_pages / percent);
}
value = info.me_mapsize / stat.ms_psize - lastpgno + reclaimable_pages;
value = info.base.me_mapsize / stat.base.ms_psize - lastpgno + reclaimable_pages;
print(", available %zu (%.1f%%)\n", value, value / percent);
}
@ -892,11 +892,11 @@ int main(int argc, char *argv[])
bailout:
if (txn)
mdb_txn_abort(txn);
mdbx_txn_abort(txn);
if (locktxn)
mdb_txn_abort(locktxn);
mdbx_txn_abort(locktxn);
if (env)
mdb_env_close(env);
mdbx_env_close(env);
free(walk.pagemap);
fflush(NULL);
if (rc) {
@ -907,7 +907,7 @@ bailout:
if (clock_gettime(CLOCK_MONOTONIC, &timestamp_finish)) {
rc = errno;
error("clock_gettime failed, error %d %s\n", rc, mdb_strerror(rc));
error("clock_gettime failed, error %d %s\n", rc, mdbx_strerror(rc));
return EXIT_FAILURE_SYS;
}

View File

@ -20,7 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "lmdb.h"
#include "mdbx.h"
static void
sighandle(int sig)

View File

@ -18,7 +18,7 @@
#include <ctype.h>
#include <unistd.h>
#include <signal.h>
#include "lmdb.h"
#include "mdbx.h"
#ifdef _WIN32
#define Z "I"

View File

@ -17,7 +17,7 @@
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include "lmdb.h"
#include "mdbx.h"
#define PRINT 1
#define NOHDR 2

View File

@ -15,18 +15,18 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "lmdb.h"
#include "mdbx.h"
static void prstat(MDB_stat *ms)
static void prstat(MDBX_stat *ms)
{
#if 0
printf(" Page size: %u\n", ms->ms_psize);
printf(" Page size: %u\n", ms->base.ms_psize);
#endif
printf(" Tree depth: %u\n", ms->ms_depth);
printf(" Branch pages: %zu\n", ms->ms_branch_pages);
printf(" Leaf pages: %zu\n", ms->ms_leaf_pages);
printf(" Overflow pages: %zu\n", ms->ms_overflow_pages);
printf(" Entries: %zu\n", ms->ms_entries);
printf(" Tree depth: %u\n", ms->base.ms_depth);
printf(" Branch pages: %zu\n", ms->base.ms_branch_pages);
printf(" Leaf pages: %zu\n", ms->base.ms_leaf_pages);
printf(" Overflow pages: %zu\n", ms->base.ms_overflow_pages);
printf(" Entries: %zu\n", ms->base.ms_entries);
}
static void usage(char *prog)
@ -41,8 +41,8 @@ int main(int argc, char *argv[])
MDB_env *env;
MDB_txn *txn;
MDB_dbi dbi;
MDB_stat mst;
MDB_envinfo mei;
MDBX_stat mst;
MDBX_envinfo mei;
char *prog = argv[0];
char *envname;
char *subname = NULL;
@ -115,19 +115,19 @@ int main(int argc, char *argv[])
}
if (envinfo) {
(void)mdb_env_stat(env, &mst);
(void)mdb_env_info(env, &mei);
(void)mdbx_env_stat(env, &mst, sizeof(mst));
(void)mdbx_env_info(env, &mei, sizeof(mei));
printf("Environment Info\n");
printf(" Map address: %p\n", mei.me_mapaddr);
printf(" Map size: %zu\n", mei.me_mapsize);
printf(" Page size: %u\n", mst.ms_psize);
printf(" Max pages: %zu\n", mei.me_mapsize / mst.ms_psize);
printf(" Number of pages used: %zu\n", mei.me_last_pgno+1);
printf(" Last transaction ID: %zu\n", mei.me_last_txnid);
printf(" Map address: %p\n", mei.base.me_mapaddr);
printf(" Map size: %zu\n", mei.base.me_mapsize);
printf(" Page size: %u\n", mst.base.ms_psize);
printf(" Max pages: %zu\n", mei.base.me_mapsize / mst.base.ms_psize);
printf(" Number of pages used: %zu\n", mei.base.me_last_pgno+1);
printf(" Last transaction ID: %zu\n", mei.base.me_last_txnid);
printf(" Tail transaction ID: %zu (%zi)\n",
mei.me_tail_txnid, mei.me_tail_txnid - mei.me_last_txnid);
printf(" Max readers: %u\n", mei.me_maxreaders);
printf(" Number of readers used: %u\n", mei.me_numreaders);
mei.me_tail_txnid, mei.me_tail_txnid - mei.base.me_last_txnid);
printf(" Max readers: %u\n", mei.base.me_maxreaders);
printf(" Number of readers used: %u\n", mei.base.me_numreaders);
} else {
/* LY: zap warnings from gcc */
memset(&mst, 0, sizeof(mst));
@ -166,7 +166,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
goto txn_abort;
}
rc = mdb_stat(txn, dbi, &mst);
rc = mdbx_stat(txn, dbi, &mst, sizeof(mst));
if (rc) {
fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
goto txn_abort;
@ -206,18 +206,18 @@ int main(int argc, char *argv[])
}
mdb_cursor_close(cursor);
if (envinfo) {
size_t value = mei.me_mapsize / mst.ms_psize;
size_t value = mei.base.me_mapsize / mst.base.ms_psize;
double percent = value / 100.0;
printf("Page Allocation Info\n");
printf(" Max pages: %9zu 100%%\n", value);
value = mei.me_last_pgno+1;
value = mei.base.me_last_pgno+1;
printf(" Number of pages used: %zu %.1f%%\n", value, value / percent);
value = mei.me_mapsize / mst.ms_psize - (mei.me_last_pgno+1);
value = mei.base.me_mapsize / mst.base.ms_psize - (mei.base.me_last_pgno+1);
printf(" Remained: %zu %.1f%%\n", value, value / percent);
value = mei.me_last_pgno+1 - pages;
value = mei.base.me_last_pgno+1 - pages;
printf(" Used now: %zu %.1f%%\n", value, value / percent);
value = pages;
@ -229,7 +229,7 @@ int main(int argc, char *argv[])
value = reclaimable;
printf(" Reclaimable: %zu %.1f%%\n", value, value / percent);
value = mei.me_mapsize / mst.ms_psize - (mei.me_last_pgno+1) + reclaimable;
value = mei.base.me_mapsize / mst.base.ms_psize - (mei.base.me_last_pgno+1) + reclaimable;
printf(" Available: %zu %.1f%%\n", value, value / percent);
} else
printf(" Free pages: %zu\n", pages);
@ -241,7 +241,7 @@ int main(int argc, char *argv[])
goto txn_abort;
}
rc = mdb_stat(txn, dbi, &mst);
rc = mdbx_stat(txn, dbi, &mst, sizeof(mst));
if (rc) {
fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
goto txn_abort;
@ -271,7 +271,7 @@ int main(int argc, char *argv[])
printf("Status of %s\n", str);
free(str);
if (rc) continue;
rc = mdb_stat(txn, db2, &mst);
rc = mdbx_stat(txn, db2, &mst, sizeof(mst));
if (rc) {
fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
goto txn_abort;

123
mdbx.h Normal file
View File

@ -0,0 +1,123 @@
/*
Copyright (c) 2015 Leonid Yuriev <leo@yuriev.ru>.
Copyright (c) 2015 Peter-Service R&D LLC.
This file is part of ReOpenLDAP.
ReOpenLDAP is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ReOpenLDAP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This is solution to provide flexible compatibility with the original liblmdb.
Yeah, this way is partially ugly and madness...
But, on the other hand, only this way allows provide both API with
minimal changes the source code of an applications, and the source
code of the library itself. Anyway, ideas are welcome!
So,
When needed drop-in replacement for liblmdb you should:
- 'make lmdb' to build liblmdb.so and liblmdb.a;
- #include <lmdb.h> and use mdb_* functions;
- linking with liblmdb.so оr liblmdb.a;
= This provides nearly full compatibility with
original LMDB from Symas Corp.
But you should be noted - such compatibility
is not a goal for MDBX.
When exactly the libmdbx is needed, you should:
- 'make mdbx' to build libmdbx.so and libmdbx.a;
- #include <mdbx.h> and use mdbx_* functions;
- linking with libmdbx.so оr libmdbx.a;
= This allows using (linking) both MDBX and LMDB
simultaneously in the one application, for instance
to benchmarking and/or comparison.
*/
#ifndef _MDBX_H_
#define _MDBX_H_
#define MDBX_MODE_ENABLED 1
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#define mdb_version mdbx_version
#define mdb_strerror mdbx_strerror
#define mdb_env_create mdbx_env_create
#define mdb_env_open mdbx_env_open
#define mdb_env_open_ex mdbx_env_open_ex
#define mdb_env_copy mdbx_env_copy
#define mdb_env_copyfd mdbx_env_copyfd
#define mdb_env_copy2 mdbx_env_copy2
#define mdb_env_copyfd2 mdbx_env_copyfd2
#define mdb_env_sync mdbx_env_sync
#define mdb_env_close mdbx_env_close
#define mdb_env_close_ex mdbx_env_close_ex
#define mdb_env_set_flags mdbx_env_set_flags
#define mdb_env_get_flags mdbx_env_get_flags
#define mdb_env_get_path mdbx_env_get_path
#define mdb_env_get_fd mdbx_env_get_fd
#define mdb_env_set_mapsize mdbx_env_set_mapsize
#define mdb_env_set_maxreaders mdbx_env_set_maxreaders
#define mdb_env_get_maxreaders mdbx_env_get_maxreaders
#define mdb_env_set_maxdbs mdbx_env_set_maxdbs
#define mdb_env_get_maxkeysize mdbx_env_get_maxkeysize
#define mdb_env_set_userctx mdbx_env_set_userctx
#define mdb_env_get_userctx mdbx_env_get_userctx
#define mdb_env_set_assert mdbx_env_set_assert
#define mdb_env_set_syncbytes mdbx_env_set_syncbytes
#define mdb_txn_begin mdbx_txn_begin
#define mdb_txn_env mdbx_txn_env
#define mdb_txn_id mdbx_txn_id
#define mdb_txn_commit mdbx_txn_commit
#define mdb_txn_abort mdbx_txn_abort
#define mdb_txn_reset mdbx_txn_reset
#define mdb_txn_renew mdbx_txn_renew
#define mdb_dbi_open mdbx_dbi_open
#define mdb_dbi_flags mdbx_dbi_flags
#define mdb_dbi_close mdbx_dbi_close
#define mdb_drop mdbx_drop
#define mdb_set_compare mdbx_set_compare
#define mdb_set_dupsort mdbx_set_dupsort
#define mdb_set_relfunc mdbx_set_relfunc
#define mdb_set_relctx mdbx_set_relctx
#define mdb_get mdbx_get
#define mdb_put mdbx_put
#define mdb_del mdbx_del
#define mdb_cursor_open mdbx_cursor_open
#define mdb_cursor_close mdbx_cursor_close
#define mdb_cursor_renew mdbx_cursor_renew
#define mdb_cursor_txn mdbx_cursor_txn
#define mdb_cursor_dbi mdbx_cursor_dbi
#define mdb_cursor_get mdbx_cursor_get
#define mdb_cursor_put mdbx_cursor_put
#define mdb_cursor_del mdbx_cursor_del
#define mdb_cursor_count mdbx_cursor_count
#define mdb_cmp mdbx_cmp
#define mdb_dcmp mdbx_dcmp
#define mdb_reader_list mdbx_reader_list
#define mdb_reader_check mdbx_reader_check
#define mdb_dkey mdbx_dkey
/** Compat with version <= 0.9.4, avoid clash with libmdb from MDB Tools project */
#define mdbx_open(txn,name,flags,dbi) mdbx_dbi_open(txn,name,flags,dbi)
#define mdbx_close(env,dbi) mdbx_dbi_close(env,dbi)
#include "./lmdb.h"
#endif /* _MDBX_H_ */

29
midl.c
View File

@ -30,7 +30,7 @@
*/
#define CMP(x,y) ( (x) < (y) ? -1 : (x) > (y) )
unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id )
static unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id )
{
/*
* binary search of id in ids
@ -66,7 +66,7 @@ unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id )
}
#if 0 /* superseded by append/sort */
int mdb_midl_insert( MDB_IDL ids, MDB_ID id )
static int mdb_midl_insert( MDB_IDL ids, MDB_ID id )
{
unsigned x, i;
@ -100,7 +100,7 @@ int mdb_midl_insert( MDB_IDL ids, MDB_ID id )
}
#endif
MDB_IDL mdb_midl_alloc(int num)
static MDB_IDL mdb_midl_alloc(int num)
{
MDB_IDL ids = malloc((num+2) * sizeof(MDB_ID));
if (ids) {
@ -110,13 +110,13 @@ MDB_IDL mdb_midl_alloc(int num)
return ids;
}
void mdb_midl_free(MDB_IDL ids)
static void mdb_midl_free(MDB_IDL ids)
{
if (ids)
free(ids-1);
}
void mdb_midl_shrink( MDB_IDL *idp )
static void mdb_midl_shrink( MDB_IDL *idp )
{
MDB_IDL ids = *idp;
if (*(--ids) > MDB_IDL_UM_MAX &&
@ -139,7 +139,7 @@ static int mdb_midl_grow( MDB_IDL *idp, int num )
return 0;
}
int mdb_midl_need( MDB_IDL *idp, unsigned num )
static int mdb_midl_need( MDB_IDL *idp, unsigned num )
{
MDB_IDL ids = *idp;
num += ids[0];
@ -153,7 +153,7 @@ int mdb_midl_need( MDB_IDL *idp, unsigned num )
return 0;
}
int mdb_midl_append( MDB_IDL *idp, MDB_ID id )
static int mdb_midl_append( MDB_IDL *idp, MDB_ID id )
{
MDB_IDL ids = *idp;
/* Too big? */
@ -167,7 +167,7 @@ int mdb_midl_append( MDB_IDL *idp, MDB_ID id )
return 0;
}
int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app )
static int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app )
{
MDB_IDL ids = *idp;
/* Too big? */
@ -181,7 +181,7 @@ int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app )
return 0;
}
int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n )
static int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n )
{
MDB_ID *ids = *idp, len = ids[0];
/* Too big? */
@ -197,7 +197,7 @@ int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n )
return 0;
}
void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge )
static void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge )
{
MDB_ID old_id, merge_id, i = merge[0], j = idl[0], k = i+j, total = k;
idl[0] = (MDB_ID)-1; /* delimiter for idl scan below */
@ -216,8 +216,7 @@ void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge )
#define SMALL 8
#define MIDL_SWAP(a,b) { itmp=(a); (a)=(b); (b)=itmp; }
void
mdb_midl_sort( MDB_IDL ids )
static void mdb_midl_sort( MDB_IDL ids )
{
/* Max possible depth of int-indexed tree * 2 items/level */
int istack[sizeof(int)*CHAR_BIT * 2];
@ -277,7 +276,7 @@ mdb_midl_sort( MDB_IDL ids )
}
}
unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id )
static unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id )
{
/*
* binary search of id in ids
@ -312,7 +311,7 @@ unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id )
return cursor;
}
int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id )
static int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id )
{
unsigned x, i;
@ -343,7 +342,7 @@ int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id )
return 0;
}
int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id )
static int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id )
{
/* Too big? */
if (ids[0].mid >= MDB_IDL_UM_MAX) {

30
midl.h
View File

@ -71,6 +71,8 @@ typedef MDB_ID *MDB_IDL;
/** Current max length of an #mdb_midl_alloc()ed IDL */
#define MDB_IDL_ALLOCLEN( ids ) ( (ids)[-1] )
#ifdef MDBX_MODE_ENABLED
/** Append ID to IDL. The IDL must be big enough. */
#define mdb_midl_xappend(idl, id) do { \
MDB_ID *xidl = (idl), xlen = ++(xidl[0]); \
@ -82,45 +84,45 @@ typedef MDB_ID *MDB_IDL;
* @param[in] id The ID to search for.
* @return The index of the first ID greater than or equal to \b id.
*/
unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id );
static unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id );
/** Allocate an IDL.
* Allocates memory for an IDL of the given size.
* @return IDL on success, NULL on failure.
*/
MDB_IDL mdb_midl_alloc(int num);
static MDB_IDL mdb_midl_alloc(int num);
/** Free an IDL.
* @param[in] ids The IDL to free.
*/
void mdb_midl_free(MDB_IDL ids);
static void mdb_midl_free(MDB_IDL ids);
/** Shrink an IDL.
* Return the IDL to the default size if it has grown larger.
* @param[in,out] idp Address of the IDL to shrink.
*/
void mdb_midl_shrink(MDB_IDL *idp);
static void mdb_midl_shrink(MDB_IDL *idp);
/** Make room for num additional elements in an IDL.
* @param[in,out] idp Address of the IDL.
* @param[in] num Number of elements to make room for.
* @return 0 on success, ENOMEM on failure.
*/
int mdb_midl_need(MDB_IDL *idp, unsigned num);
static int mdb_midl_need(MDB_IDL *idp, unsigned num);
/** Append an ID onto an IDL.
* @param[in,out] idp Address of the IDL to append to.
* @param[in] id The ID to append.
* @return 0 on success, ENOMEM if the IDL is too large.
*/
int mdb_midl_append( MDB_IDL *idp, MDB_ID id );
static int mdb_midl_append( MDB_IDL *idp, MDB_ID id );
/** Append an IDL onto an IDL.
* @param[in,out] idp Address of the IDL to append to.
* @param[in] app The IDL to append.
* @return 0 on success, ENOMEM if the IDL is too large.
*/
int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app );
static int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app );
/** Append an ID range onto an IDL.
* @param[in,out] idp Address of the IDL to append to.
@ -128,18 +130,18 @@ int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app );
* @param[in] n Number of IDs to append.
* @return 0 on success, ENOMEM if the IDL is too large.
*/
int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n );
static int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n );
/** Merge an IDL onto an IDL. The destination IDL must be big enough.
* @param[in] idl The IDL to merge into.
* @param[in] merge The IDL to merge.
*/
void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge );
static void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge );
/** Sort an IDL.
* @param[in,out] ids The IDL to sort.
*/
void mdb_midl_sort( MDB_IDL ids );
static void mdb_midl_sort( MDB_IDL ids );
/** An ID2 is an ID/pointer pair.
*/
@ -160,7 +162,7 @@ typedef MDB_ID2 *MDB_ID2L;
* @param[in] id The ID to search for.
* @return The index of the first ID2 whose \b mid member is greater than or equal to \b id.
*/
unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id );
static unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id );
/** Insert an ID2 into a ID2L.
@ -168,14 +170,16 @@ unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id );
* @param[in] id The ID2 to insert.
* @return 0 on success, -1 if the ID was already present in the ID2L.
*/
int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id );
static int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id );
/** Append an ID2 into a ID2L.
* @param[in,out] ids The ID2L to append into.
* @param[in] id The ID2 to append.
* @return 0 on success, -2 if the ID2L is too big.
*/
int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id );
static int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id );
#endif /* #ifdef MDBX_MODE_ENABLED */
/** @} */
/** @} */

View File

@ -17,7 +17,7 @@
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include "lmdb.h"
#include "mdbx.h"
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))

View File

@ -26,7 +26,7 @@
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include "lmdb.h"
#include "mdbx.h"
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))

View File

@ -20,7 +20,7 @@
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include "lmdb.h"
#include "mdbx.h"
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))

View File

@ -20,7 +20,7 @@
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include "lmdb.h"
#include "mdbx.h"
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))

View File

@ -20,7 +20,7 @@
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include "lmdb.h"
#include "mdbx.h"
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))

View File

@ -20,7 +20,7 @@
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include "lmdb.h"
#include "mdbx.h"
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))

View File

@ -20,7 +20,7 @@
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include "lmdb.h"
#include "mdbx.h"
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))

View File

@ -31,9 +31,7 @@
# define _GNU_SOURCE
#endif
#ifdef HAVE_ANSIDECL_H
# include <ansidecl.h>
#endif
#include <ansidecl.h>
#ifndef __has_attribute
# define __has_attribute(x) (0)
@ -88,6 +86,9 @@
#ifndef __cold
# if defined(__GNUC__) && !defined(__clang__)
# define __cold __attribute__((cold, optimize("Os")))
# elif defined(__GNUC__)
/* cland case, just put infrequently used functions in separate section */
# define __cold __attribute__((section("text.cold")))
# else
# define __cold
# endif

View File

@ -27,7 +27,7 @@
#include <sys/resource.h>
#include <errno.h>
#include "lmdb.h"
#include "mdbx.h"
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))