mdbx: Merge branch 'devel' into c++.

Change-Id: Iedfe7e7ae21d08628c24b4dd5a788bc43cced2f5
This commit is contained in:
Leonid Yuriev 2020-09-05 13:48:40 +03:00
commit 2bcd2e510e
5 changed files with 734 additions and 531 deletions

7
mdbx.h
View File

@ -4111,14 +4111,15 @@ mdbx_env_get_oomfunc(const MDBX_env *env);
/** Page types for traverse the b-tree. /** Page types for traverse the b-tree.
* \see mdbx_env_pgwalk() \see MDBX_pgvisitor_func */ * \see mdbx_env_pgwalk() \see MDBX_pgvisitor_func */
enum MDBX_page_type_t { enum MDBX_page_type_t {
MDBX_page_void, MDBX_page_broken,
MDBX_page_meta, MDBX_page_meta,
MDBX_page_large, MDBX_page_large,
MDBX_page_branch, MDBX_page_branch,
MDBX_page_leaf, MDBX_page_leaf,
MDBX_page_dupfixed_leaf, MDBX_page_dupfixed_leaf,
MDBX_subpage_leaf, MDBX_subpage_leaf,
MDBX_subpage_dupfixed_leaf MDBX_subpage_dupfixed_leaf,
MDBX_subpage_broken,
}; };
#ifndef __cplusplus #ifndef __cplusplus
typedef enum MDBX_page_type_t MDBX_page_type_t; typedef enum MDBX_page_type_t MDBX_page_type_t;
@ -4135,7 +4136,7 @@ typedef enum MDBX_page_type_t MDBX_page_type_t;
typedef int MDBX_pgvisitor_func( typedef int MDBX_pgvisitor_func(
const uint64_t pgno, const unsigned number, void *const ctx, const int deep, const uint64_t pgno, const unsigned number, void *const ctx, const int deep,
const char *const dbi, const size_t page_size, const MDBX_page_type_t type, const char *const dbi, const size_t page_size, const MDBX_page_type_t type,
const size_t nentries, const size_t payload_bytes, const MDBX_error_t err, const size_t nentries, const size_t payload_bytes,
const size_t header_bytes, const size_t unused_bytes) cxx17_noexcept; const size_t header_bytes, const size_t unused_bytes) cxx17_noexcept;
/** B-tree traversal function. */ /** B-tree traversal function. */

1058
src/core.c

File diff suppressed because it is too large Load Diff

View File

@ -64,8 +64,8 @@
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
# if _MSC_VER < 1400 # if _MSC_FULL_VER < 190024234
# error "Microsoft Visual C++ 8.0 (Visual Studio 2005) or later version is required" # error "At least \"Microsoft C/C++ Compiler\" version 19.00.24234 (Visual Studio 2015 Update 3) is required."
# endif # endif
# ifndef _CRT_SECURE_NO_WARNINGS # ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS # define _CRT_SECURE_NO_WARNINGS
@ -975,10 +975,8 @@ struct MDBX_env {
/* Number of freelist items that can fit in a single overflow page */ /* Number of freelist items that can fit in a single overflow page */
unsigned me_maxgc_ov1page; unsigned me_maxgc_ov1page;
unsigned me_branch_nodemax; /* max size of a branch-node */ unsigned me_branch_nodemax; /* max size of a branch-node */
uint16_t me_maxkey_nd, me_maxkey_ds; uint32_t me_live_reader; /* have liveness lock in reader table */
unsigned me_maxval_nd, me_maxval_ds; void *me_userctx; /* User-settable context */
uint32_t me_live_reader; /* have liveness lock in reader table */
void *me_userctx; /* User-settable context */
volatile uint64_t *me_sync_timestamp; volatile uint64_t *me_sync_timestamp;
volatile uint64_t *me_autosync_period; volatile uint64_t *me_autosync_period;
volatile pgno_t *me_unsynced_pages; volatile pgno_t *me_unsynced_pages;
@ -1039,9 +1037,14 @@ extern uint8_t mdbx_runtime_flags;
extern uint8_t mdbx_loglevel; extern uint8_t mdbx_loglevel;
extern MDBX_debug_func *mdbx_debug_logger; extern MDBX_debug_func *mdbx_debug_logger;
MDBX_INTERNAL_FUNC void mdbx_debug_log(int type, const char *function, int line, MDBX_INTERNAL_FUNC void __printf_args(4, 5)
const char *fmt, ...) mdbx_debug_log(int level, const char *function, int line, const char *fmt,
__printf_args(4, 5); ...) __printf_args(4, 5);
MDBX_INTERNAL_FUNC void mdbx_debug_log_va(int level, const char *function,
int line, const char *fmt,
va_list args);
#define mdbx_log_enabled(msg) unlikely(msg <= mdbx_loglevel)
#if MDBX_DEBUG #if MDBX_DEBUG
@ -1049,13 +1052,6 @@ MDBX_INTERNAL_FUNC void mdbx_debug_log(int type, const char *function, int line,
#define mdbx_audit_enabled() unlikely(mdbx_runtime_flags &MDBX_DBG_AUDIT) #define mdbx_audit_enabled() unlikely(mdbx_runtime_flags &MDBX_DBG_AUDIT)
#ifdef MDBX_LOGLEVEL_BUILD
#define mdbx_log_enabled(msg) \
(msg <= MDBX_LOGLEVEL_BUILD && unlikely(msg <= mdbx_loglevel))
#else
#define mdbx_log_enabled(msg) unlikely(msg <= mdbx_loglevel)
#endif /* MDBX_LOGLEVEL_BUILD */
#else /* MDBX_DEBUG */ #else /* MDBX_DEBUG */
#define mdbx_audit_enabled() (0) #define mdbx_audit_enabled() (0)
@ -1066,12 +1062,6 @@ MDBX_INTERNAL_FUNC void mdbx_debug_log(int type, const char *function, int line,
#define mdbx_assert_enabled() (0) #define mdbx_assert_enabled() (0)
#endif /* NDEBUG */ #endif /* NDEBUG */
#ifdef MDBX_LOGLEVEL_BUILD
#define mdbx_log_enabled(msg) (msg <= MDBX_LOGLEVEL_BUILD)
#else
#define mdbx_log_enabled(msg) (0)
#endif /* MDBX_LOGLEVEL_BUILD */
#endif /* MDBX_DEBUG */ #endif /* MDBX_DEBUG */
#if defined(__ANDROID_API__) #if defined(__ANDROID_API__)
@ -1091,33 +1081,33 @@ void mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func,
#define mdbx_debug_extra(fmt, ...) \ #define mdbx_debug_extra(fmt, ...) \
do { \ do { \
if (mdbx_log_enabled(MDBX_LOG_EXTRA)) \ if (MDBX_DEBUG && mdbx_log_enabled(MDBX_LOG_EXTRA)) \
mdbx_debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__); \ mdbx_debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__); \
} while (0) } while (0)
#define mdbx_debug_extra_print(fmt, ...) \ #define mdbx_debug_extra_print(fmt, ...) \
do { \ do { \
if (mdbx_log_enabled(MDBX_LOG_EXTRA)) \ if (MDBX_DEBUG && mdbx_log_enabled(MDBX_LOG_EXTRA)) \
mdbx_debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__); \ mdbx_debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__); \
} while (0) } while (0)
#define mdbx_trace(fmt, ...) \ #define mdbx_trace(fmt, ...) \
do { \ do { \
if (mdbx_log_enabled(MDBX_LOG_TRACE)) \ if (MDBX_DEBUG && mdbx_log_enabled(MDBX_LOG_TRACE)) \
mdbx_debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n", \ mdbx_debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n", \
__VA_ARGS__); \ __VA_ARGS__); \
} while (0) } while (0)
#define mdbx_debug(fmt, ...) \ #define mdbx_debug(fmt, ...) \
do { \ do { \
if (mdbx_log_enabled(MDBX_LOG_DEBUG)) \ if (MDBX_DEBUG && mdbx_log_enabled(MDBX_LOG_DEBUG)) \
mdbx_debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n", \ mdbx_debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n", \
__VA_ARGS__); \ __VA_ARGS__); \
} while (0) } while (0)
#define mdbx_verbose(fmt, ...) \ #define mdbx_verbose(fmt, ...) \
do { \ do { \
if (mdbx_log_enabled(MDBX_LOG_VERBOSE)) \ if (MDBX_DEBUG && mdbx_log_enabled(MDBX_LOG_VERBOSE)) \
mdbx_debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n", \ mdbx_debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n", \
__VA_ARGS__); \ __VA_ARGS__); \
} while (0) } while (0)

View File

@ -699,8 +699,8 @@ static int __cold mdbx_ipclock_failed(MDBX_env *env, mdbx_ipclock_t *ipc,
rc = MDBX_PANIC; rc = MDBX_PANIC;
} }
} }
mdbx_notice("%clock owner died, %s", (rlocked ? 'r' : 'w'), mdbx_warning("%clock owner died, %s", (rlocked ? 'r' : 'w'),
(rc ? "this process' env is hosed" : "recovering")); (rc ? "this process' env is hosed" : "recovering"));
int check_rc = mdbx_reader_check0(env, rlocked, NULL); int check_rc = mdbx_reader_check0(env, rlocked, NULL);
check_rc = (check_rc == MDBX_SUCCESS) ? MDBX_RESULT_TRUE : check_rc; check_rc = (check_rc == MDBX_SUCCESS) ? MDBX_RESULT_TRUE : check_rc;

View File

@ -58,7 +58,7 @@ static void signal_handler(int sig) {
#define EXIT_INTERRUPTED (EXIT_FAILURE + 4) #define EXIT_INTERRUPTED (EXIT_FAILURE + 4)
#define EXIT_FAILURE_SYS (EXIT_FAILURE + 3) #define EXIT_FAILURE_SYS (EXIT_FAILURE + 3)
#define EXIT_FAILURE_MDB (EXIT_FAILURE + 2) #define EXIT_FAILURE_MDBX (EXIT_FAILURE + 2)
#define EXIT_FAILURE_CHECK_MAJOR (EXIT_FAILURE + 1) #define EXIT_FAILURE_CHECK_MAJOR (EXIT_FAILURE + 1)
#define EXIT_FAILURE_CHECK_MINOR EXIT_FAILURE #define EXIT_FAILURE_CHECK_MINOR EXIT_FAILURE
@ -117,19 +117,47 @@ static void __printf_args(1, 2) print(const char *msg, ...) {
} }
} }
static void __printf_args(1, 2) error(const char *msg, ...) { static void va_log(MDBX_log_level_t level, const char *msg, va_list args) {
total_problems++; static const char *const prefixes[] = {
"!!!fatal: ", " ! " /* error */, " ! " /* warning */,
" " /* notice */, " //" /* verbose */, " ///" /* debug */,
" ////" /* trace */
};
if (!quiet) { FILE *out = stdout;
va_list args; if (level <= MDBX_LOG_ERROR) {
total_problems++;
out = stderr;
}
if (!quiet && verbose + 1 >= (unsigned)level) {
fflush(nullptr); fflush(nullptr);
va_start(args, msg); fputs(prefixes[level], out);
fputs(" ! ", stderr); vfprintf(out, msg, args);
vfprintf(stderr, msg, args); if (msg[strlen(msg) - 1] != '\n')
va_end(args); fputc('\n', out);
fflush(nullptr); fflush(nullptr);
} }
if (level == MDBX_LOG_FATAL) {
exit(EXIT_FAILURE_MDBX);
abort();
}
}
static void __printf_args(1, 2) error(const char *msg, ...) {
va_list args;
va_start(args, msg);
va_log(MDBX_LOG_ERROR, msg, args);
va_end(args);
}
static void logger(MDBX_log_level_t level, const char *function, int line,
const char *msg, va_list args) {
(void)line;
(void)function;
if (level < MDBX_LOG_EXTRA)
va_log(level, msg, args);
} }
static int check_user_break(void) { static int check_user_break(void) {
@ -260,18 +288,15 @@ static size_t problems_pop(struct problem *list) {
static int pgvisitor(const uint64_t pgno, const unsigned pgnumber, static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
void *const ctx, const int deep, void *const ctx, const int deep,
const char *const dbi_name_or_tag, const size_t page_size, const char *const dbi_name_or_tag, const size_t page_size,
const MDBX_page_type_t pagetype, const size_t nentries, const MDBX_page_type_t pagetype, const MDBX_error_t err,
const size_t payload_bytes, const size_t header_bytes, const size_t nentries, const size_t payload_bytes,
const size_t unused_bytes) { const size_t header_bytes, const size_t unused_bytes) {
(void)ctx; (void)ctx;
if (deep > 42) { if (deep > 42) {
problem_add("deep", deep, "too large", nullptr); problem_add("deep", deep, "too large", nullptr);
return MDBX_CORRUPTED /* avoid infinite loop/recursion */; return MDBX_CORRUPTED /* avoid infinite loop/recursion */;
} }
if (pagetype == MDBX_page_void)
return MDBX_SUCCESS;
walk_dbi_t *dbi = pagemap_lookup_dbi(dbi_name_or_tag, false); walk_dbi_t *dbi = pagemap_lookup_dbi(dbi_name_or_tag, false);
if (!dbi) if (!dbi)
return MDBX_ENOMEM; return MDBX_ENOMEM;
@ -288,6 +313,13 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
pagetype_caption = "unknown"; pagetype_caption = "unknown";
dbi->pages.other += pgnumber; dbi->pages.other += pgnumber;
break; break;
case MDBX_page_broken:
pagetype_caption = "broken";
dbi->pages.other += pgnumber;
break;
case MDBX_subpage_broken:
pagetype_caption = "broken-subpage";
break;
case MDBX_page_meta: case MDBX_page_meta:
pagetype_caption = "meta"; pagetype_caption = "meta";
dbi->pages.other += pgnumber; dbi->pages.other += pgnumber;
@ -356,47 +388,51 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
: MDBX_SUCCESS; : MDBX_SUCCESS;
} }
if (unused_bytes > page_size) if (MDBX_IS_ERROR(err)) {
problem_add("page", pgno, "illegal unused-bytes", problem_add("page", pgno, "invalid/corrupted", "%s-page", pagetype_caption);
"%s-page: %u < %" PRIuPTR " < %u", pagetype_caption, 0, } else {
unused_bytes, envstat.ms_psize); if (unused_bytes > page_size)
problem_add("page", pgno, "illegal unused-bytes",
"%s-page: %u < %" PRIuPTR " < %u", pagetype_caption, 0,
unused_bytes, envstat.ms_psize);
if (header_bytes < (int)sizeof(long) || if (header_bytes < (int)sizeof(long) ||
(size_t)header_bytes >= envstat.ms_psize - sizeof(long)) (size_t)header_bytes >= envstat.ms_psize - sizeof(long))
problem_add("page", pgno, "illegal header-length", problem_add("page", pgno, "illegal header-length",
"%s-page: %" PRIuPTR " < %" PRIuPTR " < %" PRIuPTR, "%s-page: %" PRIuPTR " < %" PRIuPTR " < %" PRIuPTR,
pagetype_caption, sizeof(long), header_bytes, pagetype_caption, sizeof(long), header_bytes,
envstat.ms_psize - sizeof(long)); envstat.ms_psize - sizeof(long));
if (payload_bytes < 1) { if (payload_bytes < 1) {
if (nentries > 1) { if (nentries > 1) {
problem_add("page", pgno, "zero size-of-entry", problem_add("page", pgno, "zero size-of-entry",
"%s-page: payload %" PRIuPTR " bytes, %" PRIuPTR " entries", "%s-page: payload %" PRIuPTR " bytes, %" PRIuPTR " entries",
pagetype_caption, payload_bytes, nentries); pagetype_caption, payload_bytes, nentries);
/* if ((size_t)header_bytes + unused_bytes < page_size) { /* if ((size_t)header_bytes + unused_bytes < page_size) {
// LY: hush a misuse error // LY: hush a misuse error
page_bytes = page_size; page_bytes = page_size;
} */ } */
} else { } else {
problem_add("page", pgno, "empty", problem_add("page", pgno, "empty",
"%s-page: payload %" PRIuPTR " bytes, %" PRIuPTR "%s-page: payload %" PRIuPTR " bytes, %" PRIuPTR
" entries, deep %i", " entries, deep %i",
pagetype_caption, payload_bytes, nentries, deep); pagetype_caption, payload_bytes, nentries, deep);
dbi->pages.empty += 1; dbi->pages.empty += 1;
}
} }
}
if (pgnumber) { if (pgnumber) {
if (page_bytes != page_size) { if (page_bytes != page_size) {
problem_add("page", pgno, "misused", problem_add("page", pgno, "misused",
"%s-page: %" PRIuPTR " != %" PRIuPTR " (%" PRIuPTR "%s-page: %" PRIuPTR " != %" PRIuPTR " (%" PRIuPTR
"h + %" PRIuPTR "p + %" PRIuPTR "u), deep %i", "h + %" PRIuPTR "p + %" PRIuPTR "u), deep %i",
pagetype_caption, page_size, page_bytes, header_bytes, pagetype_caption, page_size, page_bytes, header_bytes,
payload_bytes, unused_bytes, deep); payload_bytes, unused_bytes, deep);
if (page_size > page_bytes) if (page_size > page_bytes)
dbi->lost_bytes += page_size - page_bytes; dbi->lost_bytes += page_size - page_bytes;
} else { } else {
dbi->payload_bytes += payload_bytes + header_bytes; dbi->payload_bytes += payload_bytes + header_bytes;
walk.total_payload_bytes += payload_bytes + header_bytes; walk.total_payload_bytes += payload_bytes + header_bytes;
}
} }
} }
@ -764,7 +800,7 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
rc = 0; rc = 0;
if (record_count != ms.ms_entries) if (record_count != ms.ms_entries)
problem_add("entry", record_count, "differentent number of entries", problem_add("entry", record_count, "different number of entries",
"%" PRIu64 " != %" PRIu64, record_count, ms.ms_entries); "%" PRIu64 " != %" PRIu64, record_count, ms.ms_entries);
bailout: bailout:
problems_count = problems_pop(saved_list); problems_count = problems_pop(saved_list);
@ -1026,11 +1062,15 @@ int main(int argc, char *argv[]) {
mdbx_version.git.tree, envname, mdbx_version.git.tree, envname,
(envflags & MDBX_RDONLY) ? "only" : "write"); (envflags & MDBX_RDONLY) ? "only" : "write");
fflush(nullptr); fflush(nullptr);
mdbx_setup_debug((verbose < MDBX_LOG_TRACE - 1)
? (MDBX_log_level_t)(verbose + 1)
: MDBX_LOG_TRACE,
MDBX_DBG_LEGACY_OVERLAP, logger);
rc = mdbx_env_create(&env); rc = mdbx_env_create(&env);
if (rc) { if (rc) {
error("mdbx_env_create failed, error %d %s\n", rc, mdbx_strerror(rc)); error("mdbx_env_create failed, error %d %s\n", rc, mdbx_strerror(rc));
return rc < 0 ? EXIT_FAILURE_MDB : EXIT_FAILURE_SYS; return rc < 0 ? EXIT_FAILURE_MDBX : EXIT_FAILURE_SYS;
} }
rc = mdbx_env_set_maxdbs(env, MDBX_MAX_DBI); rc = mdbx_env_set_maxdbs(env, MDBX_MAX_DBI);
@ -1460,7 +1500,7 @@ bailout:
if (rc) { if (rc) {
if (rc < 0) if (rc < 0)
return user_break ? EXIT_INTERRUPTED : EXIT_FAILURE_SYS; return user_break ? EXIT_INTERRUPTED : EXIT_FAILURE_SYS;
return EXIT_FAILURE_MDB; return EXIT_FAILURE_MDBX;
} }
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)