diff --git a/mdbx/mdbx.c b/mdbx/mdbx.c index 634fcc2..23cb316 100644 --- a/mdbx/mdbx.c +++ b/mdbx/mdbx.c @@ -12,7 +12,7 @@ * . */ #define xMDBX_ALLOY 1 -#define MDBX_BUILD_SOURCERY 748ccee885a921bfe8ef7b24e71957dd3922fe37083ceb8048cb89c28c5d8f9b_v0_12_7_20_g2b0eae08 +#define MDBX_BUILD_SOURCERY d7603e99410126db376215bd0ceb9c2e32eba2af6c4988c85272497a38e29e56_v0_12_8_6_ged8c7ead #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -2051,8 +2051,7 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; /** Controls using Unix' mincore() to determine whether DB-pages * are resident in memory. */ #ifndef MDBX_ENABLE_MINCORE -#if MDBX_ENABLE_PREFAULT && \ - (defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64))) +#if defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64)) #define MDBX_ENABLE_MINCORE 1 #else #define MDBX_ENABLE_MINCORE 0 @@ -20916,11 +20915,13 @@ static __hot int cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, } break; case MDBX_GET_MULTIPLE: - if (unlikely(data == NULL || !(mc->mc_flags & C_INITIALIZED))) + if (unlikely(!data)) return MDBX_EINVAL; - if (unlikely(!(mc->mc_db->md_flags & MDBX_DUPFIXED))) + if (unlikely((mc->mc_db->md_flags & MDBX_DUPFIXED) == 0)) return MDBX_INCOMPATIBLE; - rc = MDBX_SUCCESS; + rc = (mc->mc_flags & C_INITIALIZED) + ? MDBX_SUCCESS + : cursor_set(mc, key, data, MDBX_SET).err; if ((mc->mc_xcursor->mx_cursor.mc_flags & (C_INITIALIZED | C_EOF)) != C_INITIALIZED) break; @@ -27101,30 +27102,6 @@ int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, bool del) { return rc; } -int mdbx_set_compare(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR); - if (unlikely(rc != MDBX_SUCCESS)) - return rc; - - if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID))) - return MDBX_BAD_DBI; - - txn->mt_dbxs[dbi].md_cmp = cmp; - return MDBX_SUCCESS; -} - -int mdbx_set_dupsort(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR); - if (unlikely(rc != MDBX_SUCCESS)) - return rc; - - if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID))) - return MDBX_BAD_DBI; - - txn->mt_dbxs[dbi].md_dcmp = cmp; - return MDBX_SUCCESS; -} - __cold int mdbx_reader_list(const MDBX_env *env, MDBX_reader_list_func *func, void *ctx) { int rc = check_env(env, true); @@ -33363,10 +33340,10 @@ __dll_export const struct MDBX_version_info mdbx_version = { 0, 12, - 7, - 20, - {"2023-10-09T22:12:06+03:00", "1f76e0a48d39074b6ca2a30b74c31b858d09cb2b", "2b0eae08f565b55d035d08cb87dea89566cf0747", - "v0.12.7-20-g2b0eae08"}, + 8, + 6, + {"2023-10-29T12:20:54+03:00", "551a22197e35ee5c5902f8fe0c4dbf4da99722a4", "ed8c7ead4e0f7afc50491d34918eae85dff64b86", + "v0.12.8-6-ged8c7ead"}, sourcery}; __dll_export diff --git a/mdbx/mdbx.h b/mdbx/mdbx.h index 575961b..ece77ed 100644 --- a/mdbx/mdbx.h +++ b/mdbx/mdbx.h @@ -1876,7 +1876,8 @@ enum MDBX_error_t { MDBX_BAD_RSLOT = -30783, /** Transaction is not valid for requested operation, - * e.g. had errored and be must aborted, has a child, or is invalid */ + * e.g. had errored and be must aborted, has a child/nested transaction, + * or is invalid */ MDBX_BAD_TXN = -30782, /** Invalid size or alignment of key or data for target database, @@ -1936,7 +1937,7 @@ enum MDBX_error_t { MDBX_DUPLICATED_CLK = -30413, /* The last of MDBX-added error codes */ - MDBX_LAST_ADDED_ERRCODE = MDBX_TXN_OVERLAPPING, + MDBX_LAST_ADDED_ERRCODE = MDBX_DUPLICATED_CLK, #if defined(_WIN32) || defined(_WIN64) MDBX_ENODATA = ERROR_HANDLE_EOF, @@ -2699,11 +2700,12 @@ MDBX_DEPRECATED LIBMDBX_INLINE_API(int, mdbx_env_info, * success. The \ref MDBX_RESULT_TRUE means no data pending for flush * to disk, and 0 otherwise. Some possible errors are: * - * \retval MDBX_EACCES the environment is read-only. - * \retval MDBX_BUSY the environment is used by other thread + * \retval MDBX_EACCES The environment is read-only. + * \retval MDBX_BUSY The environment is used by other thread * and `nonblock=true`. - * \retval MDBX_EINVAL an invalid parameter was specified. - * \retval MDBX_EIO an error occurred during synchronization. */ + * \retval MDBX_EINVAL An invalid parameter was specified. + * \retval MDBX_EIO An error occurred during the flushing/writing data + * to a storage medium/disk. */ LIBMDBX_API int mdbx_env_sync_ex(MDBX_env *env, bool force, bool nonblock); /** \brief The shortcut to calling \ref mdbx_env_sync_ex() with @@ -2878,7 +2880,8 @@ LIBMDBX_INLINE_API(int, mdbx_env_get_syncperiod, * is expected, i.e. \ref MDBX_env instance was freed in * proper manner. * - * \retval MDBX_EIO An error occurred during synchronization. */ + * \retval MDBX_EIO An error occurred during the flushing/writing data + * to a storage medium/disk. */ LIBMDBX_API int mdbx_env_close_ex(MDBX_env *env, bool dont_sync); /** \brief The shortcut to calling \ref mdbx_env_close_ex() with @@ -3918,7 +3921,8 @@ LIBMDBX_API int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency); * by current thread. * \retval MDBX_EINVAL Transaction handle is NULL. * \retval MDBX_ENOSPC No more disk space. - * \retval MDBX_EIO A system-level I/O error occurred. + * \retval MDBX_EIO An error occurred during the flushing/writing + * data to a storage medium/disk. * \retval MDBX_ENOMEM Out of memory. */ LIBMDBX_INLINE_API(int, mdbx_txn_commit, (MDBX_txn * txn)) { return mdbx_txn_commit_ex(txn, NULL); @@ -4084,9 +4088,9 @@ LIBMDBX_API int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary); * \see mdbx_get_datacmp \see mdbx_dcmp() * * \anchor avoid_custom_comparators - * It is recommend not using custom comparison functions, but instead - * converting the keys to one of the forms that are suitable for built-in - * comparators (for instance take look to the \ref value2key). + * \deprecated It is recommend not using custom comparison functions, but + * instead converting the keys to one of the forms that are suitable for + * built-in comparators (for instance take look to the \ref value2key). * The reasons to not using custom comparators are: * - The order of records could not be validated without your code. * So `mdbx_chk` utility will reports "wrong order" errors @@ -4316,7 +4320,7 @@ LIBMDBX_API int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi, enum MDBX_dbi_state_t { /** DB was written in this txn */ MDBX_DBI_DIRTY = 0x01, - /** Named-DB record is older than txnID */ + /** Cached Named-DB record is older than txnID */ MDBX_DBI_STALE = 0x02, /** Named-DB handle opened in this txn */ MDBX_DBI_FRESH = 0x04, @@ -4655,7 +4659,7 @@ LIBMDBX_API int mdbx_replace_ex(MDBX_txn *txn, MDBX_dbi dbi, LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, const MDBX_val *data); -/** \brief Create a cursor handle but not bind it to transaction nor DBI handle. +/** \brief Create a cursor handle but not bind it to transaction nor DBI-handle. * \ingroup c_cursors * * A cursor cannot be used when its database handle is closed. Nor when its @@ -4679,7 +4683,7 @@ LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, * \returns Created cursor handle or NULL in case out of memory. */ LIBMDBX_API MDBX_cursor *mdbx_cursor_create(void *context); -/** \brief Set application information associated with the \ref MDBX_cursor. +/** \brief Set application information associated with the cursor. * \ingroup c_cursors * \see mdbx_cursor_get_userctx() * @@ -4702,11 +4706,11 @@ LIBMDBX_API int mdbx_cursor_set_userctx(MDBX_cursor *cursor, void *ctx); MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void * mdbx_cursor_get_userctx(const MDBX_cursor *cursor); -/** \brief Bind cursor to specified transaction and DBI handle. +/** \brief Bind cursor to specified transaction and DBI-handle. * \ingroup c_cursors * * Using of the `mdbx_cursor_bind()` is equivalent to calling - * \ref mdbx_cursor_renew() but with specifying an arbitrary dbi handle. + * \ref mdbx_cursor_renew() but with specifying an arbitrary DBI-handle. * * A cursor may be associated with a new transaction, and referencing a new or * the same database handle as it was created with. This may be done whether the @@ -4720,7 +4724,7 @@ mdbx_cursor_get_userctx(const MDBX_cursor *cursor); * * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). * \param [in] dbi A database handle returned by \ref mdbx_dbi_open(). - * \param [out] cursor A cursor handle returned by \ref mdbx_cursor_create(). + * \param [in] cursor A cursor handle returned by \ref mdbx_cursor_create(). * * \returns A non-zero error value on failure and 0 on success, * some possible errors are: @@ -4779,15 +4783,14 @@ LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, * or \ref mdbx_cursor_create(). */ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); -/** \brief Renew a cursor handle. +/** \brief Renew a cursor handle for use within the given transaction. * \ingroup c_cursors * - * The cursor may be associated with a new transaction, and referencing a new or - * the same database handle as it was created with. This may be done whether the - * previous transaction is live or dead. + * A cursor may be associated with a new transaction whether the previous + * transaction is running or finished. * * Using of the `mdbx_cursor_renew()` is equivalent to calling - * \ref mdbx_cursor_bind() with the DBI handle that previously + * \ref mdbx_cursor_bind() with the DBI-handle that previously * the cursor was used with. * * \note In contrast to LMDB, the MDBX allow any cursor to be re-used by using @@ -4801,7 +4804,9 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. - * \retval MDBX_EINVAL An invalid parameter was specified. */ + * \retval MDBX_EINVAL An invalid parameter was specified. + * \retval MDBX_BAD_DBI The cursor was not bound to a DBI-handle + * or such a handle became invalid. */ LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor); /** \brief Return the cursor's transaction handle. diff --git a/mdbxdist/CMakeLists.txt b/mdbxdist/CMakeLists.txt index d7a939d..33e6233 100644 --- a/mdbxdist/CMakeLists.txt +++ b/mdbxdist/CMakeLists.txt @@ -1,5 +1,5 @@ ## -## Copyright 2020-2022 Leonid Yuriev +## Copyright 2020-2023 Leonid Yuriev ## and other libmdbx authors: please see AUTHORS file. ## All rights reserved. ## @@ -34,7 +34,9 @@ ## The Future will (be) Positive. Всё будет хорошо. ## -if(CMAKE_VERSION VERSION_LESS 3.12) +if(CMAKE_VERSION VERSION_LESS 3.8.2) + cmake_minimum_required(VERSION 3.0.2) +elseif(CMAKE_VERSION VERSION_LESS 3.12) cmake_minimum_required(VERSION 3.8.2) else() cmake_minimum_required(VERSION 3.12) @@ -233,6 +235,7 @@ if(SUBPROJECT) if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE) option(CMAKE_POSITION_INDEPENDENT_CODE "Generate position independent (PIC)" ON) endif() + set(MDBX_MANAGE_BUILD_FLAGS_DEFAULT OFF) else() option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)" ON) option(CMAKE_POSITION_INDEPENDENT_CODE "Generate position independent (PIC)" ON) @@ -240,34 +243,42 @@ else() option(BUILD_FOR_NATIVE_CPU "Generate code for the compiling machine CPU" OFF) endif() - if(CMAKE_CONFIGURATION_TYPES OR NOT CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG") - set(INTERPROCEDURAL_OPTIMIZATION_DEFAULT ON) - else() - set(INTERPROCEDURAL_OPTIMIZATION_DEFAULT OFF) - endif() - if(CMAKE_INTERPROCEDURAL_OPTIMIZATION_AVAILABLE - OR GCC_LTO_AVAILABLE OR MSVC_LTO_AVAILABLE OR - (CLANG_LTO_AVAILABLE AND - ((DEFINED MDBX_ENABLE_TESTS AND NOT MDBX_ENABLE_TESTS) - OR NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0))) - option(INTERPROCEDURAL_OPTIMIZATION "Enable interprocedural/LTO optimization" ${INTERPROCEDURAL_OPTIMIZATION_DEFAULT}) - else() - set(INTERPROCEDURAL_OPTIMIZATION OFF) + OR GCC_LTO_AVAILABLE OR MSVC_LTO_AVAILABLE OR CLANG_LTO_AVAILABLE) + if((CMAKE_CONFIGURATION_TYPES OR NOT CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG") AND + ((MSVC_LTO_AVAILABLE AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 19) OR + (GCC_LTO_AVAILABLE AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7) OR + (CLANG_LTO_AVAILABLE AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5))) + set(INTERPROCEDURAL_OPTIMIZATION_DEFAULT ON) + else() + set(INTERPROCEDURAL_OPTIMIZATION_DEFAULT OFF) + endif() + option(INTERPROCEDURAL_OPTIMIZATION "Enable interprocedural/LTO optimization." ${INTERPROCEDURAL_OPTIMIZATION_DEFAULT}) endif() if(INTERPROCEDURAL_OPTIMIZATION) if(GCC_LTO_AVAILABLE) set(LTO_ENABLED TRUE) set(CMAKE_AR ${CMAKE_GCC_AR} CACHE PATH "Path to ar program with LTO-plugin" FORCE) + set(CMAKE_C_COMPILER_AR ${CMAKE_AR} CACHE PATH "Path to ar program with LTO-plugin" FORCE) + set(CMAKE_CXX_COMPILER_AR ${CMAKE_AR} CACHE PATH "Path to ar program with LTO-plugin" FORCE) set(CMAKE_NM ${CMAKE_GCC_NM} CACHE PATH "Path to nm program with LTO-plugin" FORCE) set(CMAKE_RANLIB ${CMAKE_GCC_RANLIB} CACHE PATH "Path to ranlib program with LTO-plugin" FORCE) + set(CMAKE_C_COMPILER_RANLIB ${CMAKE_RANLIB} CACHE PATH "Path to ranlib program with LTO-plugin" FORCE) + set(CMAKE_CXX_COMPILER_RANLIB ${CMAKE_RANLIB} CACHE PATH "Path to ranlib program with LTO-plugin" FORCE) message(STATUS "MDBX indulge Link-Time Optimization by GCC") elseif(CLANG_LTO_AVAILABLE) set(LTO_ENABLED TRUE) + if(CMAKE_CLANG_LD) + set(CMAKE_LINKER ${CMAKE_CLANG_LD} CACHE PATH "Path to lld or ld program with LTO-plugin" FORCE) + endif() set(CMAKE_AR ${CMAKE_CLANG_AR} CACHE PATH "Path to ar program with LTO-plugin" FORCE) + set(CMAKE_C_COMPILER_AR ${CMAKE_AR} CACHE PATH "Path to ar program with LTO-plugin" FORCE) + set(CMAKE_CXX_COMPILER_AR ${CMAKE_AR} CACHE PATH "Path to ar program with LTO-plugin" FORCE) set(CMAKE_NM ${CMAKE_CLANG_NM} CACHE PATH "Path to nm program with LTO-plugin" FORCE) set(CMAKE_RANLIB ${CMAKE_CLANG_RANLIB} CACHE PATH "Path to ranlib program with LTO-plugin" FORCE) + set(CMAKE_C_COMPILER_RANLIB ${CMAKE_RANLIB} CACHE PATH "Path to ranlib program with LTO-plugin" FORCE) + set(CMAKE_CXX_COMPILER_RANLIB ${CMAKE_RANLIB} CACHE PATH "Path to ranlib program with LTO-plugin" FORCE) message(STATUS "MDBX indulge Link-Time Optimization by CLANG") elseif(MSVC_LTO_AVAILABLE) set(LTO_ENABLED TRUE) @@ -341,9 +352,14 @@ else() endif() endif(NOT MDBX_AMALGAMATED_SOURCE) - setup_compile_flags() + set(MDBX_MANAGE_BUILD_FLAGS_DEFAULT ON) endif(SUBPROJECT) +option(MDBX_MANAGE_BUILD_FLAGS "Allow libmdbx to configure/manage/override its own build flags" ${MDBX_MANAGE_BUILD_FLAGS_DEFAULT}) +if(MDBX_MANAGE_BUILD_FLAGS) + setup_compile_flags() +endif() + list(FIND CMAKE_C_COMPILE_FEATURES c_std_11 HAS_C11) list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_11 HAS_CXX11) list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_14 HAS_CXX14) @@ -369,6 +385,8 @@ if(NOT DEFINED MDBX_CXX_STANDARD) set(MDBX_CXX_STANDARD 14) elseif(NOT HAS_CXX11 LESS 0) set(MDBX_CXX_STANDARD 11) + elseif(CXX_FALLBACK_GNU11 OR CXX_FALLBACK_11) + set(MDBX_CXX_STANDARD 11) else() set(MDBX_CXX_STANDARD 98) endif() @@ -488,16 +506,31 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if(MDBX_NTDLL_EXTRA_IMPLIB) add_mdbx_option(MDBX_WITHOUT_MSVC_CRT "Avoid dependence from MSVC CRT and use ntdll.dll instead" OFF) endif() + set(MDBX_AVOID_MSYNC_DEFAULT ON) else() add_mdbx_option(MDBX_USE_OFDLOCKS "Use Open file description locks (aka OFD locks, non-POSIX)" AUTO) mark_as_advanced(MDBX_USE_OFDLOCKS) + set(MDBX_AVOID_MSYNC_DEFAULT OFF) endif() -add_mdbx_option(MDBX_LOCKING "Locking method (Win32=-1, SysV=5, POSIX=1988, POSIX=2001, POSIX=2008, Futexes=1995)" AUTO) +add_mdbx_option(MDBX_AVOID_MSYNC "Controls dirty pages tracking, spilling and persisting in MDBX_WRITEMAP mode" ${MDBX_AVOID_MSYNC_DEFAULT}) +add_mdbx_option(MDBX_LOCKING "Locking method (Windows=-1, SysV=5, POSIX=1988, POSIX=2001, POSIX=2008, Futexes=1995)" AUTO) mark_as_advanced(MDBX_LOCKING) add_mdbx_option(MDBX_TRUST_RTC "Does a system have battery-backed Real-Time Clock or just a fake" AUTO) mark_as_advanced(MDBX_TRUST_RTC) -option(MDBX_FORCE_ASSERTIONS "Force enable assertion checking" OFF) -option(MDBX_DISABLE_VALIDATION "Disable some checks to reduce an overhead and detection probability of database corruption to a values closer to the LMDB" OFF) +add_mdbx_option(MDBX_FORCE_ASSERTIONS "Force enable assertion checking" OFF) +add_mdbx_option(MDBX_DISABLE_VALIDATION "Disable some checks to reduce an overhead and detection probability of database corruption to a values closer to the LMDB" OFF) +mark_as_advanced(MDBX_DISABLE_VALIDATION) +add_mdbx_option(MDBX_ENABLE_REFUND "Zerocost auto-compactification during write-transactions" ON) +add_mdbx_option(MDBX_ENABLE_MADVISE "Using POSIX' madvise() and/or similar hints" ON) +if (CMAKE_TARGET_BITNESS GREATER 32) + set(MDBX_BIGFOOT_DEFAULT ON) +else() + set(MDBX_BIGFOOT_DEFAULT OFF) +endif() +add_mdbx_option(MDBX_ENABLE_BIGFOOT "Chunking long list of retired pages during huge transactions commit to avoid use sequences of pages" ${MDBX_BIGFOOT_DEFAULT}) +add_mdbx_option(MDBX_ENABLE_PGOP_STAT "Gathering statistics for page operations" ON) +add_mdbx_option(MDBX_ENABLE_PROFGC "Profiling of GC search and updates" OFF) +mark_as_advanced(MDBX_ENABLE_PROFGC) if(NOT MDBX_AMALGAMATED_SOURCE) if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG") @@ -514,7 +547,7 @@ else() unset(MDBX_LINK_TOOLS_NONSTATIC CACHE) endif() -if(CMAKE_CXX_COMPILER_LOADED AND MDBX_CXX_STANDARD GREATER_EQUAL 11 AND MDBX_CXX_STANDARD LESS 83) +if(CMAKE_CXX_COMPILER_LOADED AND MDBX_CXX_STANDARD LESS 83 AND NOT MDBX_CXX_STANDARD LESS 11) if(NOT MDBX_AMALGAMATED_SOURCE) option(MDBX_ENABLE_TESTS "Build MDBX tests" ${BUILD_TESTING}) endif() @@ -620,9 +653,13 @@ macro(target_setup_options TARGET) endmacro() macro(libmdbx_setup_libs TARGET MODE) - target_link_libraries(${TARGET} ${MODE} Threads::Threads) + if(CMAKE_VERSION VERSION_LESS 3.1) + target_link_libraries(${TARGET} ${MODE} ${CMAKE_THREAD_LIBS_INIT}) + else() + target_link_libraries(${TARGET} ${MODE} Threads::Threads) + endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - target_link_libraries(${TARGET} ${MODE} ntdll advapi32) + target_link_libraries(${TARGET} ${MODE} ntdll user32 kernel32 advapi32) if(MDBX_NTDLL_EXTRA_IMPLIB AND MDBX_WITHOUT_MSVC_CRT) target_link_libraries(${TARGET} ${MODE} ntdll_extra) endif() @@ -743,7 +780,6 @@ if(MDBX_BUILD_SHARED_LIBRARY) if(CMAKE_VERSION VERSION_LESS 3.12) install(TARGETS mdbx EXPORT libmdbx LIBRARY DESTINATION ${MDBX_DLL_INSTALL_DESTINATION} COMPONENT runtime - OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT devel PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT devel) @@ -888,16 +924,16 @@ else() endif() if(CMAKE_C_COMPILER_ABI AND NOT (CMAKE_C_COMPILER_ABI MATCHES ".*${MDBX_BUILD_TARGET}.*" OR MDBX_BUILD_TARGET MATCHES ".*${CMAKE_C_COMPILER_ABI}.*")) - string(APPEND MDBX_BUILD_TARGET "-${CMAKE_C_COMPILER_ABI}") + string(CONCAT MDBX_BUILD_TARGET "${MDBX_BUILD_TARGET}-${CMAKE_C_COMPILER_ABI}") endif() if(CMAKE_C_PLATFORM_ID AND NOT (CMAKE_SYSTEM_NAME AND (CMAKE_C_PLATFORM_ID MATCHES ".*${CMAKE_SYSTEM_NAME}.*" OR CMAKE_SYSTEM_NAME MATCHES ".*${CMAKE_C_PLATFORM_ID}.*")) AND NOT (CMAKE_C_PLATFORM_ID MATCHES ".*${CMAKE_C_PLATFORM_ID}.*" OR MDBX_BUILD_TARGET MATCHES ".*${CMAKE_C_PLATFORM_ID}.*")) - string(APPEND MDBX_BUILD_TARGET "-${CMAKE_C_COMPILER_ABI}") + string(CONCAT MDBX_BUILD_TARGET "${MDBX_BUILD_TARGET}-${CMAKE_C_COMPILER_ABI}") endif() if(CMAKE_SYSTEM_NAME) - string(APPEND MDBX_BUILD_TARGET "-${CMAKE_SYSTEM_NAME}") + string(CONCAT MDBX_BUILD_TARGET "${MDBX_BUILD_TARGET}-${CMAKE_SYSTEM_NAME}") endif() endif() @@ -951,6 +987,7 @@ if (NOT SUBPROJECT) set(CPACK_PACKAGE_VERSION_COMMIT ${MDBX_VERSION_REVISION}) set(PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}.${CPACK_PACKAGE_VERSION_COMMIT}") message(STATUS "libmdbx package version is ${PACKAGE_VERSION}") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/VERSION.txt" "${MDBX_VERSION_MAJOR}.${MDBX_VERSION_MINOR}.${MDBX_VERSION_RELEASE}.${MDBX_VERSION_REVISION}") endif() cmake_policy(POP) diff --git a/mdbxdist/ChangeLog.md b/mdbxdist/ChangeLog.md index 67e761b..899996e 100644 --- a/mdbxdist/ChangeLog.md +++ b/mdbxdist/ChangeLog.md @@ -1,35 +1,837 @@ ChangeLog ---------- +========= -## v0.12.1 (Positive Proxima) scheduled to 2022-08-24 +English version [by Google](https://gitflic-ru.translate.goog/project/erthink/libmdbx/blob?file=ChangeLog.md&_x_tr_sl=ru&_x_tr_tl=en) +and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md). + + +## v0.12.8 (сопровождение и подготовка к релизу) + +Поддержка стабильной ветки. + +Исправления и доработки: + + - Ликвидация зависимости от ранее удаленной опции `MDBX_ENABLE_PREFAULT`, из-за + чего опция `MDBX_ENABLE_MINCORE` не включалась автоматически, что приводило + к не-активации соответствующего улучшения и не-достижению декларируемого уровня + производительности в сценариях использования в режиме `MDBX_WRITEMAP`. + +Мелочи: + + - Удаление устаревших `mdbx_set_compare()` и `mdbx_set_dupsort()`. + - Корректировка определения `MDBX_LAST_ADDED_ERRCODE`. + - Добавление в C++ API забытого исключения `mdbx::duplicated_lck_file`. + - Обновление патча для старых версий buildroot. + + +-------------------------------------------------------------------------------- + + +## v0.12.8 "Владимир Уткин" от 2023-10-17 + +Стабилизирующий выпуск с исправлением обнаруженных ошибок и устранением недочетов, +в день 100-летия со дня рождения выдающегося советского и российского ученого и конструктора [Влади́мира Фёдоровича У́ткина](https://ru.wikipedia.org/wiki/Уткин,_Владимир_Фёдорович). + +``` +git diff' stat: 24 commits, 18 files changed, 624 insertions(+), 94 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Благодарности: + + - [Alain Picard](https://github.com/castortech) за сообщение о проблеме + с обработкой `MDBX_MULTIPLE` и помощь в тестировании. + +Исправления и доработки: + + - Устранение регресса/ошибки в пути обработки `put(MDBX_MULTIPLE)` при пакетном/оптовом + помещении в БД множественных значений одного ключа (aka multi-value или dupsort). + Проявление проблемы зависит от компилятора и опций оптимизации/кодогенерации, но с большой вероятностью возвращется + ошибка `MDBX_BAD_VALSIZE` (`-30781`), а в отладочных сборках срабатывает проверка `cASSERT(mc, !"Invalid key-size")`. + Сценарии приводящие к другим проявлениям на данный момент не известны. + + - Реализована перезапись в `mdbx_put(MDBX_CURRENT)` всех текущих мульти-значений ключа + при отсутствии флага `MDBX_NOOVERWRITE`. Ранее в такой ситуации возвращалась ошибка `MDBX_EMULTIVAL`. + В текущем понимании новое поведение более удобно и не создаёт проблем совместимости с ранее написанным кодом. + + - Добавлена возможность использовать `mdbx_cursor_get(MDBX_GET_MULTIPLE)` без предварительной установки + курсора, совмещая операцию пакетного получения данных с позиционированием курсора на передаваемый ключ. + + - Микрооптимизация и рефакторинг `cursor_put_nochecklen()` в продолжение исправления + регресса/ошибки в пути обработки `put(MDBX_MULTIPLE)`. + + - Уточнение формулировок в описании API, в том числе пояснений о `SIGSEGV` + и недопустимости прямого изменения данных. + +Мелочи: + + - Исправление несущественных предупреждений при `MDBX_ENABLE_PROFGC=ON`. + - Добавление `slice::as_pod()` в C++ API. + - Добавление перегрузки `txn::put_multiple()` и контроля POD в C++ API. + - Добавление smoke-теста для `put(MDBX_MULTIPLE)`. + - Добавление дополнительных smoke-тестов в область видимости ctest. + - Устранение жалоб Valgrind на инвариантное чтение неинициализированной памяти + и утечки памяти в одном из тестов. + - Костыль для глушения/игнорирования `EDEADLK` в ряде сценариев при + использовании Valgrind или ASAN. В частности, это устраняет + ложно-негативный результат проверки БД посредством `mdbx_chk -wc`, + т.е. проверку БД в кооперативном (не эксклюзивном) режиме чтения-записи + в сборках с поддержкой Valgrind или включеным ASAN. Для более подробной + информации см. [соответствующий коммит](https://gitflic.ru/project/erthink/libmdbx/commit/1aead6869a7eff1a85e400ab3eeecb4c8b904fe6). + - Доработка `mdbx_dump_val()` используемой для логирования и отладки. + - Устранение предупреждений Valgrind при логировании в отладочных сборках. + - Доработка использования `filesystem` для старых компиляторов. + - Сокращение излишнего вызова `osal_thread_self()`. + - Вывод информации о большинстве mdbx-опций при сборке посредством CMake. + - Добавление определений макросов для Doxygen. + + +-------------------------------------------------------------------------------- + + +## v0.12.7 "Артек" от 2023-06-16 + +Стабилизирующий выпуск с исправлением обнаруженных ошибок и устранением +недочетов, в день основания международного детского центра [«Арте́к»](https://ru.wikipedia.org/wiki/Артек). + +``` +14 files changed, 222 insertions(+), 56 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Исправления и доработки: + + - Исправление опечатки в имени переменной внутри `mdbx_env_turn_for_recovery()`, + что приводило к неверному поведению в некоторых ситуациях. + + С точки зрения пользователя, с учетом актуальных сценариев использования + утилиты `mdbx_chk`, был только один специфический/редкий сценарий + проявления ошибки/проблемы - когда выполнялась проверка и активация + слабой/weak мета-страницы с НЕ-последней транзакцией после системной + аварии машины, где БД использовалась в хрупком/небезопасном режиме. + В сценарии, при успешной проверке целевой страницы и её последующей + активации выводилось сообщение об ошибке, связанной со срабатыванием + механизма контроля не-когерентности кэша файловой системы и отображенных + в ОЗУ данных БД. При этом БД успешно восстанавливалось и не было + каких-либо негативных последствия, кроме самого сообщения об ошибке. + + Технически же ошибка проявлялась при "переключении" на мета-страницу, + когда у хотя-бы одной из двух других мета-страниц номер транзакции был + больше: + + * Если содержимое других мета-страниц было корректным, а номера + связанных транзакций были больше, то результирующий номер транзакции в + целевой/активируемой мета-страницы устанавливается без учета этих + мета-страниц и мог быть меньше-или-равным. + + * В результате, если такие мета-страницы были в статусе слабых/weak, то + при закрытии БД после переключения могла срабатывать защита от + не-когерентности unified buffer/page cache, а в отладочных сборках могла + срабатывать assert-проверка. + + * Если же такие мета-страницы были в статусе сильных/steady, то + переключение на новую мета-страницу могло не давать эффекта либо + приводить к появлению двух мета-страниц с одинаковым номером транзакции, + что является ошибочной ситуацией. + + - Обходное решение проблем сборки посредством GCC с использование опций `-m32 -arch=i686 -Ofast`. + Проблема обусловлена ошибкой GCC, из-за которой конструкция `__attribute__((__target__("sse2")))` + не включает полноценное использование инструкций SSE и SSE2, если это не было сделано посредством + опций командной строки, но была использована опция `-Ofast`. В результате сборка заканчивалась + сообщением об ошибке: + `error: inlining failed in call to 'always_inline' '_mm_movemask_ps': target specific option mismatch` + + - Доработка режима "восстановления" БД и переключения на заданную мета-страницу: + * Устранение обновления без необходимости мета-страницы с увеличением номера транзакции; + * Устранение вывода (логирования) бессмысленного/лишнего предупреждения о пропуске обновления геометрии БД; + * Более ожидаемое и безопасное поведение при проверке БД с указанием целевой мета-страницы в режиме чтения-записи. + + Теперь при открытии БД посредством `mdbx_env_open_for_recovery()` не + выполняется неявное изменение/обновление БД, в том числе при закрытии + БД. Это позволяет обезопасить БД (снизить шанс её разрушения) если + пользователь при попытке восстановления, либо просто в качестве + эксперимента, задал утилите `mdbx_chk` неверную или опасную комбинацию + параметров. При этом обычная проверка, как и явное переключение + мета-страниц, работают по-прежнему. + +Мелочи: + + - Незначительное уточнение CMake-пробника для `std::filesystem`, + проверяющего необходимость линковки с дополнительными библиотеками C++. + - Устранение минорных предупреждений старых компиляторов в тестах. + - Устранение причины ложно-позитивного предупреждения новых версий GCC в C++ API. + - Исправление ссылки на репозиторий бенчмарка ioarena. + - Добавление перекрестных ссылок в doxygen-документацию по C++ API. + - Уточнение ограничений в разделе [Restrictions & Caveats](https://libmdbx.dqdkfa.ru/intro.html#restrictions). + - Исправление ссылок на описание `mdbx_canary_put()`. + + +-------------------------------------------------------------------------------- + + +## v0.12.6 "ЦСКА" от 2023-04-29 + +Стабилизирующий выпуск с исправлением обнаруженных ошибок и устранением +недочетов, в день 100-летнего юбилея спортивного клуба [«ЦСКА»](https://ru.wikipedia.org/wiki/Центральный_спортивный_клуб_Армии). + +``` +14 files changed, 117 insertions(+), 83 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Мелочи: + + - Обновление патча для старых версий buildroot. + - Использование clang-format-16. + - Использование `enum`-типов вместо `int` для устранения предупреждений GCC 13, + что могло ломать сборку в Fedora 38. + + +-------------------------------------------------------------------------------- + + +## v0.12.5 "Динамо" от 2023-04-18 + +Стабилизирующий выпуск с исправлением обнаруженных ошибок и устранением +недочетов, в день 100-летнего юбилея спортивного общества [«Динамо»](https://ru.wikipedia.org/wiki/Динамо_(спортивное_общество)). + +``` +16 files changed, 686 insertions(+), 247 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Благодарности: + + - Max за сообщение о проблеме экспорта из DSO/DLL + устаревших функций API. + - [`@calvin3721`](https://t.me/calvin3721) за сообщение о проблеме работы + `MainDB` с флагами не по-умолчанию. + +Исправления: + + - Поправлен экспорт из DSO/DLL устаревших функций, + которые заменены на inline в текущем API. + - Устранено использование неверного компаратора при создании или пересоздании + `MainDB` с флагами/опциями предполагающим использование специфического + компаратора (не по-умолчанию). + +Мелочи: + + - Удалена дублирующая диагностика внутри `node_read_bigdata()`. + - Исправлены ссылки в описании `mdbx_env_set_geometry()`. + - Добавлен отдельный тест `extra/upsert_alldups` для специфического + сценария замены/перезаписи одним значением всех multi-значений + соответствующих ключу, т.е. замена всех «дубликатов» одним значением. + - В C++ API добавлены варианты `buffer::key_from()` с явным именованием по типу данных. + - Добавлен отдельный тест `extra/maindb_ordinal` для специфического + сценария создания `MainDB` с флагами требующими использования + компаратора не по-умолчанию. + - Рефакторинг проверки "когерентности" мета-страниц. + - Корректировка `osal_vasprintf()` для устранения предупреждений статических анализаторов. + + +-------------------------------------------------------------------------------- + + +## v0.12.4 "Арта-333" от 2023-03-03 + +Стабилизирующий выпуск с исправлением обнаруженных ошибок, устранением +недочетов и технических долгов. Ветка 0.12 считается готовой к +продуктовому использованию, получает статус стабильной и далее будет +получать только исправление ошибок. Разработка будет продолжена в ветке +0.13, а ветка 0.11 становится архивной. + +``` +63 files changed, 1161 insertions(+), 569 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Благодарности: + + - Max за сообщение о проблеме ERROR_SHARING_VIOLATION + в режиме MDBX_EXCLUSIVE на Windows. + - Alisher Ashyrov за сообщение о проблеме + с assert-проверкой и содействие в отладке. + - Masatoshi Fukunaga за сообщение о проблеме + `put(MDBX_UPSERT+MDBX_ALLDUPS)` для случая замены всех значений в subDb. + +Исправления: + + - Устранен регресс после коммита 474391c83c5f81def6fdf3b0b6f5716a87b78fbf, + приводящий к возврату ERROR_SHARING_VIOLATION в Windows при открытии БД + в режиме MDBX_EXCLUSIVE для чтения-записи. + + - Добавлено ограничение размера отображения при коротком read-only файле, для + предотвращения ошибки ERROR_NOT_ENOUGH_MEMORY в Windows, которая возникает + в этом случае и совсем не информативна для пользователя. + + - Произведен рефакторинг `dxb_resize()`, в том числе, для устранения срабатывания + assert-проверки `size_bytes == env->me_dxb_mmap.current` в специфических + многопоточных сценариях использования. Проверка срабатывала только в + отладочных сборках, при специфическом наложении во времени читающей и + пишущей транзакции в разных потоках, одновременно с изменением размера БД. + Кроме срабатывание проверки, каких-либо других последствий не возникало. + + - Устранена проблема в `put(MDBX_UPSERT+MDBX_ALLDUPS)` для случая замены + всех значений единственного ключа в subDb. В ходе этой операции subDb + становится полностью пустой, без каких-либо страниц и именно эта + ситуация не была учтена в коде, что приводило к повреждению БД + при фиксации такой транзакции. + + - Устранена излишняя assert-проверка внутри `override_meta()`. + Что в отладочных сборках могло приводить к ложным срабатываниям + при восстановлении БД, в том числе при автоматическом откате слабых + мета-страниц. + + - Скорректированы макросы `__cold`/`__hot`, в том числе для устранения проблемы + `error: inlining failed in call to ‘always_inline FOO(...)’: target specific option mismatch` + при сборке посредством GCC >10.x для SH4. + +Ликвидация технических долгов и мелочи: + + - Исправлены многочисленные опечатки в документации. + - Доработан тест для полной стохастической проверки `MDBX_EKEYMISMATCH` в режиме `MDBX_APPEND`. + - Расширены сценарии запуска `mdbx_chk` из CMake-тестов для проверки как в обычном, + так и эксклюзивном режимах чтения-записи. + - Уточнены спецификаторы `const` и `noexcept` для нескольких методов в C++ API. + - Устранено использование стека под буферы для `wchar`-преобразования путей. + - Для Windows добавлена функция `mdbx_env_get_path()` для получения пути к БД + в формате многобайтных символов. + - Добавлены doxygen-описания для API с широкими символами. + - Устранены предупреждения статического анализатора MSVC, + все они были несущественные, либо ложные. + - Устранено ложное предупреждение GCC при сборке для SH4. + - Добавлена поддержка ASAN (Address Sanitizer) при сборке посредством MSVC. + - Расширен набор перебираемых режимов в скрипте `test/long_stochastic.sh`, + добавлена опция `--extra`. + - В C++ API добавлена поддержка расширенных опций времени выполнения `mdbx::extra_runtime_option`, + аналогично `enum MDBX_option_t` из C API. + - Вывод всех счетчиков page-operations в `mdbx_stat`. + + +-------------------------------------------------------------------------------- + + +## v0.12.3 "Акула" от 2023-01-07 + +Выпуск с существенными доработками и новой функциональностью в память о закрытом open-source +[проекте "Акула"](https://erigon.substack.com/p/winding-down-support-for-akula-project). + +Добавлена prefault-запись, переделан контроль “некогерентности” unified page/buffer cache, изменена тактика слияния страниц и т.д. +Стало ещё быстрее, в некоторых сценариях вдвое. + +``` +20 files changed, 4508 insertions(+), 2928 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Благодарности: + + - [Alex Sharov](https://t.me/AskAlexSharov) и команде [Erigon](https://github.com/ledgerwatch/erigon) за тестирование. + - [Simon Leier](https://t.me/leisim) за сообщение о сбоях и тестирование. + +Новое: + + - Использование адреса [https://libmdbx.dqdkfa.ru/dead-github](https://libmdbx.dqdkfa.ru/dead-github) + для отсылки к сохранённым в web.archive.org копиям ресурсов, уничтоженных администрацией Github. + + - Реализована prefault-запись при выделении страниц для read-write отображений. + Это приводит к кратному снижению системных издержек и существенному увеличению + производительности в соответствующих сценариях использования, когда: + - размер БД и объём данных существенно больше ОЗУ; + - используется режим `MDBX_WRITEMAP`; + - не-мелкие транзакции (по ходу транзакции выделяется многие сотни или тысячи страниц). + + В режиме `MDBX_WRITEMAP` выделение/переиспользование страниц приводит + к page-fault и чтению страницы с диска, даже если содержимое страницы + не нужно (будет перезаписано). Это является следствием работы подсистемы + виртуальной памяти, а штатный способ лечения через `MADV_REMOVE` + работает не на всех ФС и обычно дороже получаемой экономии. + + Теперь в libmdbx используется "упреждающая запись" таких страниц, + которая на системах с [unified page cache](https://www.opennet.ru/base/dev/ubc.txt.html) + приводит к "вталкиванию" данных, устраняя необходимость чтения с диска при + обращении к такой странице памяти. + + Новый функционал работает в согласованности с автоматическим управлением read-ahead + и кэшем статуса присутствия страниц в ОЗУ, посредством [mincore()](https://man7.org/linux/man-pages/man2/mincore.2.html). + + - Добавлена опция `MDBX_opt_prefault_write_enable` для возможности принудительного + включения/выключения prefault-записи. + + - Реализован динамический выбор между сквозной записью на диск и обычной записью + с последующим [fdatasync()](https://man7.org/linux/man-pages/man3/fdatasync.3p.html) + управляемый опцией `MDBX_opt_writethrough_threshold`. + + В долговечных (durable) режимах данные на диск могут быть сброшены двумя способами: + - сквозной записью через файловый дескриптор открытый с `O_DSYNC`; + - обычной записью с последующим вызовом `fdatasync()`. + + Первый способ выгоднее при записи малого количества страниц и/или если + канал взаимодействия с диском/носителем имеет близкую к нулю задержку. + Второй способ выгоднее если требуется записать много страниц и/или канал + взаимодействия имеет весомую задержку (датацентры, облака). Добавленная + опция `MDBX_opt_writethrough_threshold` позволяет во время выполнения + задать порог для динамического выбора способа записи в зависимости от + объема и конкретных условия использования. + + - Автоматическая установка `MDBX_opt_rp_augment_limit` в зависимости от размера БД. + + - Запрещение разного режима `MDBX_WRITEMAP` между процессами в режимах + с отложенной/ленивой записью, так как в этом случае невозможно + обеспечить сброс данных на диск во всех случаях на всех поддерживаемых платформах. + + - Добавлена опция сборки `MDBX_MMAP_USE_MS_ASYNC` позволяющая отключить + использование системного вызова `msync(MS_ASYNC)`, в использовании + которого нет необходимости на подавляющем большинстве актуальных ОС. + По-умолчанию `MDBX_MMAP_USE_MS_ASYNC=0` (выключено) на Linux и других + системах с unified page cache. Такое поведение (без использования + `msync(MS_ASYNC)`) соответствует неизменяемой (hardcoded) логике LMDB. В + результате, в простых/наивных бенчмарках, libmdbx опережает LMDB + примерно также как при реальном применении. + + На всякий случай стоит еще раз отметить/напомнить, что на Windows + предположительно libmdbx будет отставать от LMDB в сценариях с + множеством мелких транзакций, так как libmdbx осознанно использует на + Windows файловые блокировки, которые медленные (плохо реализованы в ядре + ОС), но позволяют застраховать пользователей от массы неверных действий + приводящих к повреждению БД. + + - Поддержка не-печатных имен для subDb. + + - Добавлен явный выбор `tls_model("local-dynamic")` для обхода проблемы + `relocation R_X86_64_TPOFF32 against FOO cannot be used with -shared` + из-за ошибки в CLANG приводящей к использованию неверного режима `tls_model`. + + - Изменение тактики слияния страниц при удалении. + Теперь слияние выполняется преимущественно с уже измененной/грязной страницей. + Если же справа и слева обе страницы с одинаковым статусом, + то с наименее заполненной, как прежде. В сценариях с массивным удалением + это позволяет увеличить производительность до 50%. + + - Добавлен контроль отсутствия LCK-файлов с альтернативным именованием. + +Исправления (без корректировок новых функций): + + - Изменение размера отображения если это требуется для сброса данных на + диск при вызове `mdbx_env_sync()` из параллельного потока выполнения вне + работающей транзакции. + + - Исправление регресса после коммита db72763de049d6e4546f838277fe83b9081ad1de от 2022-10-08 + в логике возврата грязных страниц в режиме `MDBX_WRITEMAP`, из-за чего + освободившиеся страницы использовались не немедленно, а попадали в + retired-список совершаемой транзакции и происходил необоснованный рост + размера транзакции. + + - Устранение SIGSEGV или ошибочного вызова `free()` в ситуациях + повторного открытия среды посредством `mdbx_env_open()`. + + - Устранение ошибки совершенной в коммите fe20de136c22ed3bc4c6d3f673e79c106e824f60 от 2022-09-18, + в результате чего на Linux в режиме `MDBX_WRITEMAP` никогда не вызывался `msync()`. + Проблема существует только в релизе 0.12.2. + + - Добавление подсчета грязных страниц в `MDBX_WRITEMAP` для предоставления посредством `mdbx_txn_info()` + актуальной информации об объеме изменений в процессе транзакций чтения-записи. + + - Исправление несущественной опечатки в условиях `#if` определения порядка байт. + + - Исправление сборки для случая `MDBX_PNL_ASCENDING=1`. + +Ликвидация технических долгов и мелочи: + + - Доработка поддержки авто-слияния записей GC внутри `page_alloc_slowpath()`. + - Устранение несущественных предупреждений Coverity. + - Использование единого курсора для поиска в GC. + - Переработка внутренних флагов связанных с выделением страниц из GC. + - Доработка подготовки резерва перед обновлением GC при включенном BigFoot. + - Оптимизация `pnl_merge()` для случаев неперекрывающихся объединяемых списков. + - Оптимизация поддержки отсортированного списка страниц в `dpl_append()`. + - Ускорение работы `mdbx_chk` при обработке пользовательских записей в `@MAIN`. + - Переработка LRU-отметок для спиллинга. + - Переработка контроля "некогерентности" Unified page cache для уменьшения накладных расходов. + - Рефакторинг и микрооптимизация. + + +-------------------------------------------------------------------------------- + + +## v0.12.2 "Иван Ярыгин" от 2022-11-11 + +Выпуск с существенными доработками и новой функциональностью +в память о российском борце [Иване Сергеевиче Ярыгине](https://ru.wikipedia.org/wiki/Ярыгин,_Иван_Сергеевич). + +На Олимпийских играх в Мюнхене в 1972 году Иван Ярыгин уложил всех соперников на лопатки, +суммарно затратив менее 9 минут. Этот рекорд никем не побит до сих пор. + +``` +64 files changed, 5573 insertions(+), 2510 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Новое: + + - Поддержка всех основных опций при сборке посредством CMake. + + - Требования к CMake понижены до версии 3.0.2 для возможности сборки для устаревших платформ. + + - Добавлена возможность профилирования работы GC в сложных и/или нагруженных + сценариях (например Ethereum/Erigon). По-умолчанию соответствующий код отключен, + а для его активации необходимо указать опцию сборки `MDBX_ENABLE_PROFGC=1`. + + - Добавлена функция `mdbx_env_warmup()` для "прогрева" БД с возможностью + закрепления страниц в памяти. + В утилиты `mdbx_chk`, `mdbx_copy` и `mdbx_dump` добавлены опции `-u` и `-U` + для активации соответствующего функционала. + + - Отключение учета «грязных» страниц в не требующих этого режимах + (`MDBX_WRITEMAP` при `MDBX_AVOID_MSYNC=0`). Доработка позволяет снизить + накладные расходы и была запланирована давно, но откладывалась так как + требовала других изменений. + + - Вытеснение из памяти (спиллинг) «грязных» страниц с учетом размера + large/overflow-страниц. Доработка позволяет корректно соблюдать политику + задаваемую опциями `MDBX_opt_txn_dp_limit`, + `MDBX_opt_spill_max_denominator`, `MDBX_opt_spill_min_denominator` и + была запланирована давно, но откладывалась так как требовала других + изменений. + + - Для Windows в API добавлены UNICODE-зависимые определения макросов + `MDBX_DATANAME`, `MDBX_LOCKNAME` и `MDBX_LOCK_SUFFIX`. + + - Переход на преимущественное использование типа `size_t` для + уменьшения накладных расходов на платформе Эльбрус. + + - В API добавлены функции `mdbx_limits_valsize4page_max()` и + `mdbx_env_get_valsize4page_max()` возвращающие максимальный размер в + байтах значения, которое может быть размещена в одной + large/overflow-странице, а не последовательности из двух или более таких + страниц. Для таблиц с поддержкой дубликатов вынос значений на + large/overflow-страницы не поддерживается, поэтому результат совпадает с + `mdbx_limits_valsize_max()`. + + - В API добавлены функции `mdbx_limits_pairsize4page_max()`и + `mdbx_env_get_pairsize4page_max()` возвращающие в байтах максимальный + суммарный размер пары ключ-значение для их размещения на одной листовой + страницы, без выноса значения на отдельную large/overflow-страницу. Для + таблиц с поддержкой дубликатов вынос значений на large/overflow-страницы + не поддерживается, поэтому результат определяет максимальный/допустимый + суммарный размер пары ключ-значение. + + - Реализовано использование асинхронной (overlapped) записи в Windows, + включая использования небуферизированного ввода-вывода и `WriteGather()`. + Это позволяет сократить накладные расходы и частично обойти проблемы + Windows с низкой производительностью ввода-вывода, включая большие + задержки `FlushFileBuffers()`. Новый код также обеспечивает консолидацию + записываемых регионов на всех платформах, а на Windows использование + событий (events) сведено к минимум, одновременно с автоматических + использованием `WriteGather()`. Поэтому ожидается существенное снижение + накладных расходов взаимодействия с ОС, а в Windows это ускорение, в + некоторых сценариях, может быть кратным в сравнении с LMDB. + + - Добавлена опция сборки `MDBX_AVOID_MSYNC`, которая определяет + поведение libmdbx в режиме `MDBX_WRITE_MAP` (когда данные изменяются + непосредственно в отображенных в ОЗУ страницах БД): + + * Если `MDBX_AVOID_MSYNC=0` (по умолчанию на всех системах кроме Windows), + то (как прежде) сохранение данных выполняется посредством `msync()`, + либо `FlushViewOfFile()` на Windows. На платформах с полноценной + подсистемой виртуальной памяти и адекватным файловым вводом-выводом + это обеспечивает минимум накладных расходов (один системный вызов) + и максимальную производительность. Однако, на Windows приводит + к значительной деградации, в том числе из-за того что после + `FlushViewOfFile()` требуется также вызов `FlushFileBuffers()` + с массой проблем и суеты внутри ядра ОС. + + * Если `MDBX_AVOID_MSYNC=1` (по умолчанию только на Windows), то + сохранение данных выполняется явной записью в файл каждой измененной + страницы БД. Это требует дополнительных накладных расходов, как + на отслеживание измененных страниц (ведение списков "грязных" + страниц), так и на системные вызовы для их записи. + Кроме этого, с точки зрения подсистемы виртуальной памяти ядра ОС, + страницы БД измененные в ОЗУ и явно записанные в файл, могут либо + оставаться "грязными" и быть повторно записаны ядром ОС позже, + либо требовать дополнительных накладных расходов для отслеживания + PTE (Page Table Entries), их модификации и дополнительного копирования + данных. Тем не менее, по имеющейся информации, на Windows такой путь + записи данных в целом обеспечивает более высокую производительность. + + - Улучшение эвристики включения авто-слияния записей GC. + + - Изменение формата LCK и семантики некоторых внутренних полей. Версии + libmdbx использующие разный формат не смогут работать с одной БД + одновременно, а только поочередно (LCK-файл переписывается при открытии + первым открывающим БД процессом). + + - В `C++` API добавлены методы фиксации транзакции с получением информации + о задержках. + + - Added `MDBX_HAVE_BUILT IN_CPU_SUPPORTS` build option to control use GCC's + `__builtin_cpu_supports()` function, which could be unavailable on a fake + OSes (macos, ios, android, etc). + +Исправления (без корректировок вышеперечисленных новых функций): + + - Устранения ряда предупреждений при сборке посредством MinGW. + - Устранение ложно-положительных сообщений от Valgrind об использовании + не инициализированных данных из-за выравнивающих зазоров в `struct troika`. + - Исправлен возврат неожиданной ошибки `MDBX_BUSY` из функций `mdbx_env_set_option()`, + `mdbx_env_set_syncbytes()` и `mdbx_env_set_syncperiod()`. + - Небольшие исправления для совместимости с CMake 3.8 + - Больше контроля и осторожности (паранойи) для страховки от дефектов `mremap()`. + - Костыль для починки сборки со старыми версиями `stdatomic.h` из GNU Lib C, + где макросы `ATOMIC_*_LOCK_FREE` ошибочно переопределяются через функции. + - Использование `fcntl64(F_GETLK64/F_SETLK64/F_SETLKW64)` при наличии. + Это решает проблему срабатывания проверочного утверждения при сборке для + платформ где тип `off_t` шире соответствующих полей `структуры flock`, + используемой для блокировки файлов. + - Доработан сбор информации о задержках при фиксации транзакций: + * Устранено искажение замеров длительности обновления GC + при включении отладочного внутреннего аудита; + * Защита от undeflow-нуля только общей задержки в метриках, + чтобы исключить ситуации, когда сумма отдельных стадий + больше общей длительности. + - Ряд исправлений для устранения срабатываний проверочных утверждения в + отладочных сборках. + - Более осторожное преобразование к типу `mdbx_tid_t` для устранения + предупреждений. + - Исправление лишнего сброса данных на диск в режиме `MDBX_SAFE_NOSYNC` + при обновлении GC. + - Fixed an extra check for `MDBX_APPENDDUP` inside `mdbx_cursor_put()` + which could result in returning `MDBX_EKEYMISMATCH` for valid cases. + - Fixed nasty `clz()` bug (by using `_BitScanReverse()`, only MSVC builds affected). + +Мелочи: + + - Исторические ссылки cвязанные с удалённым на ~~github~~ проектом перенаправлены на [web.archive.org](https://web.archive.org/web/https://github.com/erthink/libmdbx). + - Синхронизированы конструкции CMake между проектами. + - Добавлено предупреждение о небезопасности RISC-V. + - Добавлено описание параметров `MDBX_debug_func` и `MDBX_debug_func`. + - Добавлено обходное решение для минимизации ложно-положительных + конфликтов при использовании файловых блокировок в Windows. + - Проверка атомарности C11-операций c 32/64-битными данными. + - Уменьшение в 42 раза значения по-умолчанию для `me_options.dp_limit` + в отладочных сборках. + - Добавление платформы `gcc-riscv64-linux-gnu` в список для цели `cross-gcc`. + - Небольшие правки скрипта `long_stochastic.sh` для работы в Windows. + - Удаление ненужного вызова `LockFileEx()` внутри `mdbx_env_copy()`. + - Добавлено описание использования файловых дескрипторов в различных режимах. + - Добавлено использование `_CrtDbgReport()` в отладочных сборках. + - Fixed an extra ensure/assertion check of `oldest_reader` inside `txn_end()`. + - Removed description of deprecated usage of `MDBX_NODUPDATA`. + - Fixed regression ASAN/Valgring-enabled builds. + - Fixed minor MingGW warning. + + +-------------------------------------------------------------------------------- + + +## v0.12.1 "Positive Proxima" at 2022-08-24 The planned frontward release with new superior features on the day of 20 anniversary of [Positive Technologies](https://ptsecurty.com). +``` +37 files changed, 7604 insertions(+), 7417 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + New: - The `Big Foot` feature which significantly reduces GC overhead for processing large lists of retired pages from huge transactions. Now _libmdbx_ avoid creating large chunks of PNLs (page number lists) which required a long sequences of free pages, aka large/overflow pages. Thus avoiding searching, allocating and storing such sequences inside GC. - Improved hot/online validation and checking of database pages both for more robustness and performance. + - New solid and fast method to latch meta-pages called `Troika`. + The minimum of memory barriers, reads, comparisons and conditional transitions are used. - New `MDBX_VALIDATION` environment options to extra validation of DB structure and pages content for carefully/safe handling damaged or untrusted DB. - - Optionally cache for pointers to last/steady meta-pages (currently is off by default). + - Accelerated ×16/×8/×4 by AVX512/AVX2/SSE2/Neon implementations of search page sequences. - Added the `gcrtime_seconds16dot16` counter to the "Page Operation Statistics" that accumulates time spent for GC searching and reclaiming. - Copy-with-compactification now clears/zeroes unused gaps inside database pages. + - The `C` and `C++` APIs has been extended and/or refined to simplify using `wchar_t` pathnames. + On Windows the `mdbx_env_openW()`, `mdbx_env_get_pathW()`, `mdbx_env_copyW()`, `mdbx_env_open_for_recoveryW()` are available for now, + but the `mdbx_env_get_path()` has been replaced in favor of `mdbx_env_get_pathW()`. + - Added explicit error message for Buildroot's Microblaze toolchain maintainers. + - Added `MDBX_MANAGE_BUILD_FLAGS` build options for CMake. + - Speed-up internal `bsearch`/`lower_bound` implementation using branchless tactic, including workaround for CLANG x86 optimiser bug. + - A lot internal refinement and micro-optimisations. + - Internally counted volume of dirty pages (unused for now but for coming features). + +Fixes: + + - Never use modern `__cxa_thread_atexit()` on Apple's OSes. + - Don't check owner for finished transactions. + - Fixed typo in `MDBX_EINVAL` which breaks MingGW builds with CLANG. + ## v0.12.0 at 2022-06-19 Not a release but preparation for changing feature set and API. -------------------------------------------------------------------------------- +******************************************************************************** + +## v0.11.14 "Sergey Kapitsa" at 2023-02-14 -## v0.11.9 (Чирчик-1992) scheduled to 2022-08-02 +The stable bugfix release in memory of [Sergey Kapitsa](https://en.wikipedia.org/wiki/Sergey_Kapitsa) on his 95th birthday. + +``` +22 files changed, 250 insertions(+), 174 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Fixes: + - backport: Fixed insignificant typo of `||` inside `#if` byte-order condition. + - backport: Fixed `SIGSEGV` or an erroneous call to `free()` in situations where + errors occur when reopening by `mdbx_env_open()` of a previously used + environment. + - backport: Fixed `cursor_put_nochecklen()` internals for case when dupsort'ed named subDb + contains a single key with multiple values (aka duplicates), which are replaced + with a single value by put-operation with the `MDBX_UPSERT+MDBX_ALLDUPS` flags. + In this case, the database becomes completely empty, without any pages. + However exactly this condition was not considered and thus wasn't handled correctly. + See [issue#8](https://gitflic.ru/project/erthink/libmdbx/issue/8) for more information. + - backport: Fixed extra assertion inside `override_meta()`, which could + lead to false-positive failing of the assertion in a debug builds during + DB recovery and auto-rollback. + - backport: Refined the `__cold`/`__hot` macros to avoid the + `error: inlining failed in call to ‘always_inline FOO(...)’: target specific option mismatch` + issue during build using GCC >10.x for SH4 arch. + +Minors: + + - backport: Using the https://libmdbx.dqdkfa.ru/dead-github + for resources deleted by the Github' administration. + - backport: Fixed English typos. + - backport: Fixed proto of `__asan_default_options()`. + - backport: Fixed doxygen-description of C++ API, especially of C++20 concepts. + - backport: Refined `const` and `noexcept` for few C++ API methods. + - backport: Fixed copy&paste typo of "Getting started". + - backport: Update MithrilDB status. + - backport: Resolve false-posirive `used uninitialized` warning from GCC >10.x + while build for SH4 arch. + + +-------------------------------------------------------------------------------- + + +## v0.11.13 at "Swashplate" 2022-11-10 + +The stable bugfix release in memory of [Boris Yuryev](https://ru.wikipedia.org/wiki/Юрьев,_Борис_Николаевич) on his 133rd birthday. + +``` +30 files changed, 405 insertions(+), 136 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Fixes: + + - Fixed builds with older libc versions after using `fcntl64()` (backport). + - Fixed builds with older `stdatomic.h` versions, + where the `ATOMIC_*_LOCK_FREE` macros mistakenly redefined using functions (backport). + - Added workaround for `mremap()` defect to avoid assertion failure (backport). + - Workaround for `encryptfs` bug(s) in the `copy_file_range` implementation (backport). + - Fixed unexpected `MDBX_BUSY` from `mdbx_env_set_option()`, `mdbx_env_set_syncbytes()` + and `mdbx_env_set_syncperiod()` (backport). + - CMake requirements lowered to version 3.0.2 (backport). + +Minors: + + - Minor clarification output of `--help` for `mdbx_test` (backport). + - Added admonition of insecure for RISC-V (backport). + - Stochastic scripts and CMake files synchronized with the `devel` branch. + - Use `--dont-check-ram-size` for small-tests make-targets (backport). + + +-------------------------------------------------------------------------------- + + +## v0.11.12 "Эребуни" at 2022-10-12 + +The stable bugfix release. + +``` +11 files changed, 96 insertions(+), 49 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Fixes: + + - Fixed static assertion failure on platforms where the `off_t` type is wider + than corresponding fields of `struct flock` used for file locking (backport). + Now _libmdbx_ will use `fcntl64(F_GETLK64/F_SETLK64/F_SETLKW64)` if available. + - Fixed assertion check inside `page_retire_ex()` (backport). + +Minors: + + - Fixed `-Wint-to-pointer-cast` warnings while casting to `mdbx_tid_t` (backport). + - Removed needless `LockFileEx()` inside `mdbx_env_copy()` (backport). + + +-------------------------------------------------------------------------------- + + +## v0.11.11 "Тендра-1790" at 2022-09-11 + +The stable bugfix release. + +``` +10 files changed, 38 insertions(+), 21 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Fixes: + + - Fixed an extra check for `MDBX_APPENDDUP` inside `mdbx_cursor_put()` which could result in returning `MDBX_EKEYMISMATCH` for valid cases. + - Fixed an extra ensure/assertion check of `oldest_reader` inside `mdbx_txn_end()`. + - Fixed derived C++ builds by removing `MDBX_INTERNAL_FUNC` for `mdbx_w2mb()` and `mdbx_mb2w()`. + + +-------------------------------------------------------------------------------- + + +## v0.11.10 "the TriColor" at 2022-08-22 The stable bugfix release. -It is planned that this will be the last release of the v0.11 branch. -Acknowledgements: +``` +14 files changed, 263 insertions(+), 252 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +New: + + - The C++ API has been refined to simplify support for `wchar_t` in path names. + - Added explicit error message for Buildroot's Microblaze toolchain maintainers. + +Fixes: + + - Never use modern `__cxa_thread_atexit()` on Apple's OSes. + - Use `MultiByteToWideChar(CP_THREAD_ACP)` instead of `mbstowcs()`. + - Don't check owner for finished transactions. + - Fixed typo in `MDBX_EINVAL` which breaks MingGW builds with CLANG. + +Minors: + + - Fixed variable name typo. + - Using `ldd` to check used dso. + - Added `MDBX_WEAK_IMPORT_ATTRIBUTE` macro. + - Use current transaction geometry for untouched parameters when `env_set_geometry()` called within a write transaction. + - Minor clarified `iov_page()` failure case. + + +-------------------------------------------------------------------------------- + + +## v0.11.9 "Чирчик-1992" at 2022-08-02 + +The stable bugfix release. + +``` +18 files changed, 318 insertions(+), 178 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Acknowledgments: - [Alex Sharov](https://github.com/AskAlexSharov) and Erigon team for reporting and testing. - [Andrew Ashikhmin](https://gitflic.ru/user/yperbasis) for contributing. @@ -58,14 +860,14 @@ Minors: - Fixed `has no symbols` warning from Apple's ranlib. -------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -## v0.11.8 (Baked Apple) at 2022-06-12 +## v0.11.8 "Baked Apple" at 2022-06-12 The stable release with an important fixes and workaround for the critical macOS thread-local-storage issue. -Acknowledgements: +Acknowledgments: - [Masatoshi Fukunaga](https://github.com/mah0x211) for [Lua bindings](https://github.com/mah0x211/lua-libmdbx). @@ -111,10 +913,10 @@ Minors: - Don't provide nor report package information if used as a CMake subproject. -------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -## v0.11.7 (Resurrected Sarmat) at 2022-04-22 +## v0.11.7 "Resurrected Sarmat" at 2022-04-22 The stable risen release after the Github's intentional malicious disaster. @@ -135,7 +937,7 @@ New: - Support build by MinGW' make from command line without CMake. - Added `mdbx::filesystem` C++ API namespace that corresponds to `std::filesystem` or `std::experimental::filesystem`. - Created [website](https://libmdbx.dqdkfa.ru/) for online auto-generated documentation. - - Used `https://web.archive.org/web/20220414235959/https://github.com/erthink/` for dead (or temporarily lost) resources deleted by ~~Github~~. + - Used `https://web.archive.org/web/https://github.com/erthink/libmdbx` for dead (or temporarily lost) resources deleted by ~~Github~~. - Added `--loglevel=` command-line option to the `mdbx_test` tool. - Added few fast smoke-like tests into CMake builds. @@ -160,7 +962,7 @@ Minors: - Switched to using `MDBX_EPERM` instead of `MDBX_RESULT_TRUE` to indicate that the geometry cannot be updated. - Added `NULL` checking during memory allocation inside `mdbx_chk`. - Resolved all warnings from MinGW while used without CMake. - - Added inheretable `target_include_directories()` to `CMakeLists.txt` for easy integration. + - Added inheritable `target_include_directories()` to `CMakeLists.txt` for easy integration. - Added build-time checks and paranoid runtime assertions for the `off_t` arguments of `fcntl()` which are used for locking. - Added `-Wno-lto-type-mismatch` to avoid false-positive warnings from old GCC during LTO-enabled builds. - Added checking for TID (system thread id) to avoid hang on 32-bit Bionic/Android within `pthread_mutex_lock()`. @@ -168,24 +970,24 @@ Minors: - Added `CMAKE_HOST_ARCH` and `CMAKE_HOST_CAN_RUN_EXECUTABLES_BUILT_FOR_TARGET`. -------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- ## v0.11.6 at 2022-03-24 The stable release with the complete workaround for an incoherence flaw of Linux unified page/buffer cache. Nonetheless the cause for this trouble may be an issue of Intel CPU cache/MESI. -See [issue#269](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/269) for more information. +See [issue#269](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for more information. -Acknowledgements: +Acknowledgments: - [David Bouyssié](https://github.com/david-bouyssie) for [Scala bindings](https://github.com/david-bouyssie/mdbx4s). - [Michelangelo Riccobene](https://github.com/mriccobene) for reporting and testing. Fixes: - - [Added complete workaround](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/269) for an incoherence flaw of Linux unified page/buffer cache. - - [Fixed](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/272) cursor reusing for read-only transactions. + - [Added complete workaround](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for an incoherence flaw of Linux unified page/buffer cache. + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/272) cursor reusing for read-only transactions. - Fixed copy&paste typo inside `mdbx::cursor::find_multivalue()`. Minors: @@ -197,12 +999,15 @@ Minors: - Clarified error messages of a signature/version mismatch. +-------------------------------------------------------------------------------- + + ## v0.11.5 at 2022-02-23 The release with the temporary hotfix for a flaw of Linux unified page/buffer cache. -See [issue#269](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/269) for more information. +See [issue#269](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for more information. -Acknowledgements: +Acknowledgments: - [Simon Leier](https://github.com/leisim) for reporting and testing. - [Kai Wetlesen](https://github.com/kaiwetlesen) for [RPMs](http://copr.fedorainfracloud.org/coprs/kwetlesen/libmdbx/). @@ -210,10 +1015,10 @@ Acknowledgements: Fixes: - - [Added hotfix](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/269) for a flaw of Linux unified page/buffer cache. - - [Fixed/Reworked](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/pull/270) move-assignment operators for "managed" classes of C++ API. + - [Added hotfix](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for a flaw of Linux unified page/buffer cache. + - [Fixed/Reworked](https://libmdbx.dqdkfa.ru/dead-github/pull/270) move-assignment operators for "managed" classes of C++ API. - Fixed potential `SIGSEGV` while open DB with overrided non-default page size. - - [Made](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/267) `mdbx_env_open()` idempotence in failure cases. + - [Made](https://libmdbx.dqdkfa.ru/dead-github/issues/267) `mdbx_env_open()` idempotence in failure cases. - Refined/Fixed pages reservation inside `mdbx_update_gc()` to avoid non-reclamation in a rare cases. - Fixed typo in a retained space calculation for the hsr-callback. @@ -226,11 +1031,14 @@ Minors: - Minor fixes Doxygen references, comments, descriptions, etc. +-------------------------------------------------------------------------------- + + ## v0.11.4 at 2022-02-02 The stable release with fixes for large and huge databases sized of 4..128 TiB. -Acknowledgements: +Acknowledgments: - [Ledgerwatch](https://github.com/ledgerwatch), [Binance](https://github.com/binance-chain) and [Positive Technologies](https://www.ptsecurity.com/) teams for reporting, assistance in investigation and testing. - [Alex Sharov](https://github.com/AskAlexSharov) for reporting, testing and provide resources for remote debugging/investigation. @@ -246,15 +1054,15 @@ New features, extensions and improvements: Fixes: - Fixed handling `MDBX_opt_rp_augment_limit` for GC's records from huge transactions (Erigon/Akula/Ethereum). - - [Fixed](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/258) build on Android (avoid including `sys/sem.h`). - - [Fixed](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/pull/261) missing copy assignment operator for `mdbx::move_result`. + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/258) build on Android (avoid including `sys/sem.h`). + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/pull/261) missing copy assignment operator for `mdbx::move_result`. - Fixed missing `&` for `std::ostream &operator<<()` overloads. - Fixed unexpected `EXDEV` (Cross-device link) error from `mdbx_env_copy()`. - Fixed base64 encoding/decoding bugs in auxillary C++ API. - Fixed overflow of `pgno_t` during checking PNL on 64-bit platforms. - - [Fixed](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/260) excessive PNL checking after sort for spilling. + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/260) excessive PNL checking after sort for spilling. - Reworked checking `MAX_PAGENO` and DB upper-size geometry limit. - - [Fixed](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/265) build for some combinations of versions of MSVC and Windows SDK. + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/265) build for some combinations of versions of MSVC and Windows SDK. Minors: @@ -271,9 +1079,12 @@ Minors: - Using the `-fno-semantic interposition` option to reduce the overhead to calling self own public functions. +-------------------------------------------------------------------------------- + + ## v0.11.3 at 2021-12-31 -Acknowledgements: +Acknowledgments: - [gcxfd ](https://github.com/gcxfd) for reporting, contributing and testing. - [장세연 (Чан Се Ен)](https://github.com/sasgas) for reporting and testing. @@ -281,10 +1092,10 @@ Acknowledgements: New features, extensions and improvements: - - [Added](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/236) `mdbx_cursor_get_batch()`. - - [Added](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/250) `MDBX_SET_UPPERBOUND`. + - [Added](https://libmdbx.dqdkfa.ru/dead-github/issues/236) `mdbx_cursor_get_batch()`. + - [Added](https://libmdbx.dqdkfa.ru/dead-github/issues/250) `MDBX_SET_UPPERBOUND`. - C++ API is finalized now. - - The GC update stage has been [significantly speeded](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/254) when fixing huge Erigon's transactions (Ethereum ecosystem). + - The GC update stage has been [significantly speeded](https://libmdbx.dqdkfa.ru/dead-github/issues/254) when fixing huge Erigon's transactions (Ethereum ecosystem). Fixes: @@ -295,18 +1106,21 @@ Minors: - Fixed returning `MDBX_RESULT_TRUE` (unexpected -1) from `mdbx_env_set_option()`. - Added `mdbx_env_get_syncbytes()` and `mdbx_env_get_syncperiod()`. - - [Clarified](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/pull/249) description of `MDBX_INTEGERKEY`. + - [Clarified](https://libmdbx.dqdkfa.ru/dead-github/pull/249) description of `MDBX_INTEGERKEY`. - Reworked/simplified `mdbx_env_sync_internal()`. - - [Fixed](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/248) extra assertion inside `mdbx_cursor_put()` for `MDBX_DUPFIXED` cases. + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/248) extra assertion inside `mdbx_cursor_put()` for `MDBX_DUPFIXED` cases. - Avoiding extra looping inside `mdbx_env_info_ex()`. - Explicitly enabled core dumps from stochastic tests scripts on Linux. - - [Fixed](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/253) `mdbx_override_meta()` to avoid false-positive assertions. + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/253) `mdbx_override_meta()` to avoid false-positive assertions. - For compatibility reverted returning `MDBX_ENODATA`for some cases. +-------------------------------------------------------------------------------- + + ## v0.11.2 at 2021-12-02 -Acknowledgements: +Acknowledgments: - [장세연 (Чан Се Ен)](https://github.com/sasgas) for contributing to C++ API. - [Alain Picard](https://github.com/castortech) for [Java bindings](https://github.com/castortech/mdbxjni). @@ -316,10 +1130,10 @@ Acknowledgements: Fixes: - - [Fixed compilation](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/pull/239) with `devtoolset-9` on CentOS/RHEL 7. - - [Fixed unexpected `MDBX_PROBLEM` error](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/242) because of update an obsolete meta-page. - - [Fixed returning `MDBX_NOTFOUND` error](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/243) in case an inexact value found for `MDBX_GET_BOTH` operation. - - [Fixed compilation](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/245) without kernel/libc-devel headers. + - [Fixed compilation](https://libmdbx.dqdkfa.ru/dead-github/pull/239) with `devtoolset-9` on CentOS/RHEL 7. + - [Fixed unexpected `MDBX_PROBLEM` error](https://libmdbx.dqdkfa.ru/dead-github/issues/242) because of update an obsolete meta-page. + - [Fixed returning `MDBX_NOTFOUND` error](https://libmdbx.dqdkfa.ru/dead-github/issues/243) in case an inexact value found for `MDBX_GET_BOTH` operation. + - [Fixed compilation](https://libmdbx.dqdkfa.ru/dead-github/issues/245) without kernel/libc-devel headers. Minors: @@ -330,13 +1144,16 @@ Minors: - Remove unneeded `#undef P_DIRTY`. +-------------------------------------------------------------------------------- + + ## v0.11.1 at 2021-10-23 ### Backward compatibility break: The database format signature has been changed to prevent forward-interoperability with an previous releases, which may lead to a -[false positive diagnosis of database corruption](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/238) +[false positive diagnosis of database corruption](https://libmdbx.dqdkfa.ru/dead-github/issues/238) due to flaws of an old library versions. This change is mostly invisible: @@ -344,12 +1161,12 @@ This change is mostly invisible: - previously versions are unable to read/write a new DBs; - but the new release is able to handle an old DBs and will silently upgrade ones. -Acknowledgements: +Acknowledgments: - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing. -------------------------------------------------------------------------------- +******************************************************************************** ## v0.10.5 at 2021-10-13 (obsolete, please use v0.11.1) @@ -362,7 +1179,7 @@ Unfortunately, the `v0.10.5` accidentally comes not full-compatible with previou This cannot be fixed, as it requires fixing past versions, which as a result we will just get a current version. Therefore, it is recommended to use `v0.11.1` instead of `v0.10.5`. -Acknowledgements: +Acknowledgments: - [Noel Kuntze](https://github.com/Thermi) for immediately bug reporting. @@ -378,9 +1195,12 @@ Minors: - Refined providing information for the `@MAIN` and `@GC` sub-databases of a last committed modification transaction's ID. +-------------------------------------------------------------------------------- + + ## v0.10.4 at 2021-10-10 -Acknowledgements: +Acknowledgments: - [Artem Vorotnikov](https://github.com/vorot93) for support [Rust wrapper](https://github.com/vorot93/libmdbx-rs). - [Andrew Ashikhmin](https://github.com/yperbasis) for contributing to C++ API. @@ -388,7 +1208,7 @@ Acknowledgements: Fixes: - Fixed possibility of looping update GC during transaction commit (no public issue since the problem was discovered inside [Positive Technologies](https://www.ptsecurity.ru)). - - Fixed `#pragma pack` to avoid provoking some compilers to generate code with [unaligned access](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/235). + - Fixed `#pragma pack` to avoid provoking some compilers to generate code with [unaligned access](https://libmdbx.dqdkfa.ru/dead-github/issues/235). - Fixed `noexcept` for potentially throwing `txn::put()` of C++ API. Minors: @@ -398,9 +1218,12 @@ Minors: - In debugging builds fixed a too small (single page) by default DB shrink threshold. +-------------------------------------------------------------------------------- + + ## v0.10.3 at 2021-08-27 -Acknowledgements: +Acknowledgments: - [Francisco Vallarino](https://github.com/fjvallarino) for [Haskell bindings for libmdbx](https://hackage.haskell.org/package/libmdbx). - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing. @@ -414,7 +1237,7 @@ Extensions and improvements: Fixes: - - Always setup `madvise` while opening DB (fixes https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/231). + - Always setup `madvise` while opening DB (fixes https://libmdbx.dqdkfa.ru/dead-github/issues/231). - Fixed checking legacy `P_DIRTY` flag (`0x10`) for nested/sub-pages. Minors: @@ -426,20 +1249,23 @@ Minors: - Fixed CMake warning about compatibility with 3.8.2 +-------------------------------------------------------------------------------- + + ## v0.10.2 at 2021-07-26 -Acknowledgements: +Acknowledgments: - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing. - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for reporting bugs. - [Lionel Debroux](https://github.com/debrouxl) for fuzzing tests and reporting bugs. - [Sergey Fedotov](https://github.com/SergeyFromHell/) for [`node-mdbx` NodeJS bindings](https://www.npmjs.com/package/node-mdbx). - [Kris Zyp](https://github.com/kriszyp) for [`lmdbx-store` NodeJS bindings](https://github.com/kriszyp/lmdbx-store). - - [Noel Kuntze](https://github.com/Thermi) for [draft Python bindings](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/commits/python-bindings). + - [Noel Kuntze](https://github.com/Thermi) for [draft Python bindings](https://libmdbx.dqdkfa.ru/dead-github/commits/python-bindings). New features, extensions and improvements: - - [Allow to predefine/override `MDBX_BUILD_TIMESTAMP` for builds reproducibility](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/201). + - [Allow to predefine/override `MDBX_BUILD_TIMESTAMP` for builds reproducibility](https://libmdbx.dqdkfa.ru/dead-github/issues/201). - Added options support for `long-stochastic` script. - Avoided `MDBX_TXN_FULL` error for large transactions when possible. - The `MDBX_READERS_LIMIT` increased to `32767`. @@ -447,7 +1273,7 @@ New features, extensions and improvements: - Minimized the size of poisoned/unpoisoned regions to avoid Valgrind/ASAN stuck. - Added more workarounds for QEMU for testing builds for 32-bit platforms, Alpha and Sparc architectures. - `mdbx_chk` now skips iteration & checking of DB' records if corresponding page-tree is corrupted (to avoid `SIGSEGV`, ASAN failures, etc). - - Added more checks for [rare/fuzzing corruption cases](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/217). + - Added more checks for [rare/fuzzing corruption cases](https://libmdbx.dqdkfa.ru/dead-github/issues/217). Backward compatibility break: @@ -459,23 +1285,26 @@ Backward compatibility break: Fixes: - Fixed excess meta-pages checks in case `mdbx_chk` is called to check the DB for a specific meta page and thus could prevent switching to the selected meta page, even if the check passed without errors. - - Fixed [recursive use of SRW-lock on Windows cause by `MDBX_NOTLS` option](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/203). - - Fixed [log a warning during a new DB creation](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/205). - - Fixed [false-negative `mdbx_cursor_eof()` result](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/207). - - Fixed [`make install` with non-GNU `install` utility (OSX, BSD)](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/208). - - Fixed [installation by `CMake` in special cases by complete use `GNUInstallDirs`'s variables](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/209). - - Fixed [C++ Buffer issue with `std::string` and alignment](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/191). + - Fixed [recursive use of SRW-lock on Windows cause by `MDBX_NOTLS` option](https://libmdbx.dqdkfa.ru/dead-github/issues/203). + - Fixed [log a warning during a new DB creation](https://libmdbx.dqdkfa.ru/dead-github/issues/205). + - Fixed [false-negative `mdbx_cursor_eof()` result](https://libmdbx.dqdkfa.ru/dead-github/issues/207). + - Fixed [`make install` with non-GNU `install` utility (OSX, BSD)](https://libmdbx.dqdkfa.ru/dead-github/issues/208). + - Fixed [installation by `CMake` in special cases by complete use `GNUInstallDirs`'s variables](https://libmdbx.dqdkfa.ru/dead-github/issues/209). + - Fixed [C++ Buffer issue with `std::string` and alignment](https://libmdbx.dqdkfa.ru/dead-github/issues/191). - Fixed `safe64_reset()` for platforms without atomic 64-bit compare-and-swap. - Fixed hang/shutdown on big-endian platforms without `__cxa_thread_atexit()`. - - Fixed [using bad meta-pages if DB was partially/recoverable corrupted](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/217). + - Fixed [using bad meta-pages if DB was partially/recoverable corrupted](https://libmdbx.dqdkfa.ru/dead-github/issues/217). - Fixed extra `noexcept` for `buffer::&assign_reference()`. - Fixed `bootid` generation on Windows for case of change system' time. - - Fixed [test framework keygen-related issue](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/127). + - Fixed [test framework keygen-related issue](https://libmdbx.dqdkfa.ru/dead-github/issues/127). + + +-------------------------------------------------------------------------------- ## v0.10.1 at 2021-06-01 -Acknowledgements: +Acknowledgments: - [Alexey Akhunov](https://github.com/AlexeyAkhunov) and [Alex Sharov](https://github.com/AskAlexSharov) for bug reporting and testing. - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for bug reporting and testing related to WSL2. @@ -491,15 +1320,18 @@ New features: Fixes: - Fixed minor "foo not used" warnings from modern C++ compilers when building the C++ part of the library. - - Fixed confusing/messy errors when build library from unfit github's archives (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/197). + - Fixed confusing/messy errors when build library from unfit github's archives (https://libmdbx.dqdkfa.ru/dead-github/issues/197). - Fixed `#​e​l​s​i​f` typo. - - Fixed rare unexpected `MDBX_PROBLEM` error during altering data in huge transactions due to wrong spilling/oust of dirty pages (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/195). - - Re-Fixed WSL1/WSL2 detection with distinguishing (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/97). + - Fixed rare unexpected `MDBX_PROBLEM` error during altering data in huge transactions due to wrong spilling/oust of dirty pages (https://libmdbx.dqdkfa.ru/dead-github/issues/195). + - Re-Fixed WSL1/WSL2 detection with distinguishing (https://libmdbx.dqdkfa.ru/dead-github/issues/97). + + +-------------------------------------------------------------------------------- ## v0.10.0 at 2021-05-09 -Acknowledgements: +Acknowledgments: - [Mahlon E. Smith](https://github.com/mahlonsmith) for [Ruby bindings](https://rubygems.org/gems/mdbx/). - [Alex Sharov](https://github.com/AskAlexSharov) for [mdbx-go](https://github.com/torquem-ch/mdbx-go), bug reporting and testing. @@ -517,7 +1349,7 @@ New features: and conjointly with the `MDBX_ENV_CHECKPID=0` and `MDBX_TXN_CHECKOWNER=0` options can yield up to 30% more performance compared to LMDB. - Using float point (exponential quantized) representation for internal 16-bit values - of grow step and shrink threshold when huge ones (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/166). + of grow step and shrink threshold when huge ones (https://libmdbx.dqdkfa.ru/dead-github/issues/166). To minimize the impact on compatibility, only the odd values inside the upper half of the range (i.e. 32769..65533) are used for the new representation. - Added the `mdbx_drop` similar to LMDB command-line tool to purge or delete (sub)database(s). @@ -526,7 +1358,7 @@ New features: - The internal node sizes were refined, resulting in a reduction in large/overflow pages in some use cases and a slight increase in limits for a keys size to ≈½ of page size. - Added to `mdbx_chk` output number of keys/items on pages. - - Added explicit `install-strip` and `install-no-strip` targets to the `Makefile` (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/pull/180). + - Added explicit `install-strip` and `install-no-strip` targets to the `Makefile` (https://libmdbx.dqdkfa.ru/dead-github/pull/180). - Major rework page splitting (af9b7b560505684249b76730997f9e00614b8113) for - An "auto-appending" feature upon insertion for both ascending and descending key sequences. As a result, the optimality of page filling @@ -534,7 +1366,7 @@ New features: inserting ordered sequences of keys, - A "splitting at middle" to make page tree more balanced on average. - Added `mdbx_get_sysraminfo()` to the API. - - Added guessing a reasonable maximum DB size for the default upper limit of geometry (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/183). + - Added guessing a reasonable maximum DB size for the default upper limit of geometry (https://libmdbx.dqdkfa.ru/dead-github/issues/183). - Major rework internal labeling of a dirty pages (958fd5b9479f52f2124ab7e83c6b18b04b0e7dda) for a "transparent spilling" feature with the gist to make a dirty pages be ready to spilling (writing to a disk) without further altering ones. @@ -550,7 +1382,7 @@ New features: - Support `make help` to list available make targets. - Silently `make`'s build by default. - Preliminary [Python bindings](https://github.com/Thermi/libmdbx/tree/python-bindings) is available now - by [Noel Kuntze](https://github.com/Thermi) (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/147). + by [Noel Kuntze](https://github.com/Thermi) (https://libmdbx.dqdkfa.ru/dead-github/issues/147). Backward compatibility break: @@ -565,30 +1397,30 @@ Backward compatibility break: Fixes: - - Fixed performance regression due non-optimal C11 atomics usage (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/160). - - Fixed "reincarnation" of subDB after it deletion (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/168). + - Fixed performance regression due non-optimal C11 atomics usage (https://libmdbx.dqdkfa.ru/dead-github/issues/160). + - Fixed "reincarnation" of subDB after it deletion (https://libmdbx.dqdkfa.ru/dead-github/issues/168). - Fixed (disallowing) implicit subDB deletion via operations on `@MAIN`'s DBI-handle. - - Fixed a crash of `mdbx_env_info_ex()` in case of a call for a non-open environment (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/171). - - Fixed the selecting/adjustment values inside `mdbx_env_set_geometry()` for implicit out-of-range cases (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/170). - - Fixed `mdbx_env_set_option()` for set initial and limit size of dirty page list ((https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/179). - - Fixed an unreasonably huge default upper limit for DB geometry (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/183). + - Fixed a crash of `mdbx_env_info_ex()` in case of a call for a non-open environment (https://libmdbx.dqdkfa.ru/dead-github/issues/171). + - Fixed the selecting/adjustment values inside `mdbx_env_set_geometry()` for implicit out-of-range cases (https://libmdbx.dqdkfa.ru/dead-github/issues/170). + - Fixed `mdbx_env_set_option()` for set initial and limit size of dirty page list ((https://libmdbx.dqdkfa.ru/dead-github/issues/179). + - Fixed an unreasonably huge default upper limit for DB geometry (https://libmdbx.dqdkfa.ru/dead-github/issues/183). - Fixed `constexpr` specifier for the `slice::invalid()`. - - Fixed (no)readahead auto-handling (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/164). + - Fixed (no)readahead auto-handling (https://libmdbx.dqdkfa.ru/dead-github/issues/164). - Fixed non-alloy build for Windows. - Switched to using Heap-functions instead of LocalAlloc/LocalFree on Windows. - - Fixed `mdbx_env_stat_ex()` to returning statistics of the whole environment instead of MainDB only (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/190). + - Fixed `mdbx_env_stat_ex()` to returning statistics of the whole environment instead of MainDB only (https://libmdbx.dqdkfa.ru/dead-github/issues/190). - Fixed building by GCC 4.8.5 (added workaround for a preprocessor's bug). - Fixed building C++ part for iOS <= 13.0 (unavailability of `std::filesystem::path`). - Fixed building for Windows target versions prior to Windows Vista (`WIN32_WINNT < 0x0600`). - - Fixed building by MinGW for Windows (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/155). + - Fixed building by MinGW for Windows (https://libmdbx.dqdkfa.ru/dead-github/issues/155). -------------------------------------------------------------------------------- +******************************************************************************** ## v0.9.3 at 2021-02-02 -Acknowledgements: +Acknowledgments: - [Mahlon E. Smith](http://www.martini.nu/) for [FreeBSD port of libmdbx](https://svnweb.freebsd.org/ports/head/databases/mdbx/). - [장세연](http://www.castis.com) for bug fixing and PR. @@ -603,7 +1435,7 @@ Removed options and features: New features: - Package for FreeBSD is available now by Mahlon E. Smith. - - New API functions to get/set various options (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/128): + - New API functions to get/set various options (https://libmdbx.dqdkfa.ru/dead-github/issues/128): - the maximum number of named databases for the environment; - the maximum number of threads/reader slots; - threshold (since the last unsteady commit) to force flush the data buffers to disk; @@ -616,7 +1448,7 @@ New features: - maximal part of the dirty pages may be spilled when necessary; - minimal part of the dirty pages should be spilled when necessary; - how much of the parent transaction dirty pages will be spilled while start each child transaction; - - Unlimited/Dynamic size of retired and dirty page lists (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/123). + - Unlimited/Dynamic size of retired and dirty page lists (https://libmdbx.dqdkfa.ru/dead-github/issues/123). - Added `-p` option (purge subDB before loading) to `mdbx_load` tool. - Reworked spilling of large transaction and committing of nested transactions: - page spilling code reworked to avoid the flaws and bugs inherited from LMDB; @@ -626,27 +1458,30 @@ New features: - Added `MDBX_ENABLE_REFUND` and `MDBX_PNL_ASCENDING` internal/advanced build options. - Added `mdbx_default_pagesize()` function. - Better support architectures with a weak/relaxed memory consistency model (ARM, AARCH64, PPC, MIPS, RISC-V, etc) by means [C11 atomics](https://en.cppreference.com/w/c/atomic). - - Speed up page number lists and dirty page lists (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/132). + - Speed up page number lists and dirty page lists (https://libmdbx.dqdkfa.ru/dead-github/issues/132). - Added `LIBMDBX_NO_EXPORTS_LEGACY_API` build option. Fixes: - - Fixed missing cleanup (null assigned) in the C++ commit/abort (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/pull/143). + - Fixed missing cleanup (null assigned) in the C++ commit/abort (https://libmdbx.dqdkfa.ru/dead-github/pull/143). - Fixed `mdbx_realloc()` for case of nullptr and `MDBX_WITHOUT_MSVC_CRT=ON` for Windows. - - Fixed the possibility to use invalid and renewed (closed & re-opened, dropped & re-created) DBI-handles (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/146). - - Fixed 4-byte aligned access to 64-bit integers, including access to the `bootid` meta-page's field (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/153). + - Fixed the possibility to use invalid and renewed (closed & re-opened, dropped & re-created) DBI-handles (https://libmdbx.dqdkfa.ru/dead-github/issues/146). + - Fixed 4-byte aligned access to 64-bit integers, including access to the `bootid` meta-page's field (https://libmdbx.dqdkfa.ru/dead-github/issues/153). - Fixed minor/potential memory leak during page flushing and unspilling. - Fixed handling states of cursors's and subDBs's for nested transactions. - Fixed page leak in extra rare case the list of retired pages changed during update GC on transaction commit. - - Fixed assertions to avoid false-positive UB detection by CLANG/LLVM (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/153). - - Fixed `MDBX_TXN_FULL` and regressive `MDBX_KEYEXIST` during large transaction commit with `MDBX_LIFORECLAIM` (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/123). + - Fixed assertions to avoid false-positive UB detection by CLANG/LLVM (https://libmdbx.dqdkfa.ru/dead-github/issues/153). + - Fixed `MDBX_TXN_FULL` and regressive `MDBX_KEYEXIST` during large transaction commit with `MDBX_LIFORECLAIM` (https://libmdbx.dqdkfa.ru/dead-github/issues/123). - Fixed auto-recovery (`weak->steady` with the same boot-id) when Database size at last weak checkpoint is large than at last steady checkpoint. - - Fixed operation on systems with unusual small/large page size, including PowerPC (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/157). + - Fixed operation on systems with unusual small/large page size, including PowerPC (https://libmdbx.dqdkfa.ru/dead-github/issues/157). + + +-------------------------------------------------------------------------------- ## v0.9.2 at 2020-11-27 -Acknowledgements: +Acknowledgments: - Jens Alfke (Mobile Architect at [Couchbase](https://www.couchbase.com/)) for [NimDBX](https://github.com/snej/nimdbx). - Clément Renault (CTO at [MeiliSearch](https://www.meilisearch.com/)) for [mdbx-rs](https://github.com/Kerollmops/mdbx-rs). @@ -679,11 +1514,11 @@ Fixes: - Fixed copy&paste typos. - Fixed minor false-positive GCC warning. - Added workaround for broken `DEFINE_ENUM_FLAG_OPERATORS` from Windows SDK. - - Fixed cursor state after multimap/dupsort repeated deletes (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/121). + - Fixed cursor state after multimap/dupsort repeated deletes (https://libmdbx.dqdkfa.ru/dead-github/issues/121). - Added `SIGPIPE` suppression for internal thread during `mdbx_env_copy()`. - - Fixed extra-rare `MDBX_KEY_EXIST` error during `mdbx_commit()` (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/131). - - Fixed spilled pages checking (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/126). - - Fixed `mdbx_load` for 'plain text' and without `-s name` cases (https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/136). + - Fixed extra-rare `MDBX_KEY_EXIST` error during `mdbx_commit()` (https://libmdbx.dqdkfa.ru/dead-github/issues/131). + - Fixed spilled pages checking (https://libmdbx.dqdkfa.ru/dead-github/issues/126). + - Fixed `mdbx_load` for 'plain text' and without `-s name` cases (https://libmdbx.dqdkfa.ru/dead-github/issues/136). - Fixed save/restore/commit of cursors for nested transactions. - Fixed cursors state in rare/special cases (move next beyond end-of-data, after deletion and so on). - Added workaround for MSVC 19.28 (Visual Studio 16.8) (but may still hang during compilation). @@ -694,6 +1529,9 @@ Fixes: - Added handling `EXCEPTION_POSSIBLE_DEADLOCK` condition for Windows. +-------------------------------------------------------------------------------- + + ## v0.9.1 2020-09-30 Added features: @@ -736,10 +1574,13 @@ Fixes: - Fix a lot of typos & spelling (Thanks to Josh Soref for PR). - Fix `getopt()` messages for Windows (Thanks to Andrey Sporaw for reporting). - Fix MSVC compiler version requirements (Thanks to Andrey Sporaw for reporting). - - Workarounds for QEMU's bugs to run tests for cross-builded library under QEMU. + - Workarounds for QEMU's bugs to run tests for cross-built[A library under QEMU. - Now C++ compiler optional for building by CMake. +-------------------------------------------------------------------------------- + + ## v0.9.0 2020-07-31 (not a release, but API changes) Added features: @@ -753,7 +1594,7 @@ Deprecated functions and flags: Please use the value-to-key functions to provide keys that are compatible with the built-in libmdbx comparators. -------------------------------------------------------------------------------- +******************************************************************************** ## 2020-07-06 @@ -805,7 +1646,7 @@ Deprecated functions and flags: - Avoid using `pwritev()` for single-writes (up to 10% speedup for some kernels & scenarios). - Avoiding `MDBX_UTTERLY_NOSYNC` as result of flags merge. - Add `mdbx_dbi_dupsort_depthmask()` function. - - Add `MDBX_CP_FORCE_RESIZEABLE` option. + - Add `MDBX_CP_FORCE_RESIZABLE` option. - Add deprecated `MDBX_MAP_RESIZED` for compatibility. - Add `MDBX_BUILD_TOOLS` option (default `ON`). - Refine `mdbx_dbi_open_ex()` to safe concurrently opening the same handle from different threads. @@ -893,6 +1734,8 @@ Deprecated functions and flags: - API description. - Checking for non-local filesystems to avoid DB corruption. -------------------------------------------------------------------------------- + +******************************************************************************** + For early changes see the git commit history. diff --git a/mdbxdist/GNUmakefile b/mdbxdist/GNUmakefile index d6b9fc7..35e7849 100644 --- a/mdbxdist/GNUmakefile +++ b/mdbxdist/GNUmakefile @@ -6,7 +6,7 @@ # ################################################################################ # -# Basic internal definitios. For a customizable variables and options see below. +# Basic internal definitions. For a customizable variables and options see below. # $(info // The GNU Make $(MAKE_VERSION)) SHELL := $(shell env bash -c 'echo $$BASH') @@ -53,8 +53,9 @@ CFLAGS_EXTRA ?= LD ?= ld # build options -MDBX_BUILD_OPTIONS ?=-DNDEBUG=1 +MDBX_BUILD_OPTIONS ?=-DNDEBUG=1 MDBX_BUILD_TIMESTAMP ?=$(shell date +%Y-%m-%dT%H:%M:%S%z) +MDBX_BUILD_CXX ?= YES # probe and compose common compiler flags with variable expansion trick (seems this work two times per session for GNU Make 3.81) CFLAGS ?= $(strip $(eval CFLAGS := -std=gnu11 -O2 -g -Wall -Werror -Wextra -Wpedantic -ffunction-sections -fPIC -fvisibility=hidden -pthread -Wno-error=attributes $$(shell for opt in -fno-semantic-interposition -Wno-unused-command-line-argument -Wno-tautological-compare; do [ -z "$$$$($(CC) '-DMDBX_BUILD_FLAGS="probe"' $$$${opt} -c $(SRC_PROBE_C) -o /dev/null >/dev/null 2>&1 || echo failed)" ] && echo "$$$${opt} "; done)$(CFLAGS_EXTRA))$(CFLAGS)) @@ -127,6 +128,9 @@ TIP := // TIP: .PHONY: all help options lib libs tools clean install uninstall check_buildflags_tag tools-static .PHONY: install-strip install-no-strip strip libmdbx mdbx show-options lib-static lib-shared +boolean = $(if $(findstring $(strip $($1)),YES Yes yes y ON On on 1 true True TRUE),1,$(if $(findstring $(strip $($1)),NO No no n OFF Off off 0 false False FALSE),,$(error Wrong value `$($1)` of $1 for YES/NO option))) +select_by = $(if $(call boolean,$(1)),$(2),$(3)) + ifeq ("$(origin V)", "command line") MDBX_BUILD_VERBOSE := $(V) endif @@ -134,7 +138,7 @@ ifndef MDBX_BUILD_VERBOSE MDBX_BUILD_VERBOSE := 0 endif -ifeq ($(MDBX_BUILD_VERBOSE),1) +ifeq ($(call boolean,MDBX_BUILD_VERBOSE),1) QUIET := HUSH := $(info $(TIP) Use `make V=0` for quiet.) @@ -169,12 +173,12 @@ help: show-options: @echo " MDBX_BUILD_OPTIONS = $(MDBX_BUILD_OPTIONS)" + @echo " MDBX_BUILD_CXX = $(MDBX_BUILD_CXX)" @echo " MDBX_BUILD_TIMESTAMP = $(MDBX_BUILD_TIMESTAMP)" @echo '$(TIP) Use `make options` to listing available build options.' - @echo " CC =`which $(CC)` | `$(CC) --version | head -1`" - @echo " CFLAGS =$(CFLAGS)" - @echo " CXXFLAGS =$(CXXFLAGS)" - @echo " LDFLAGS =$(LDFLAGS) $(LIB_STDCXXFS) $(LIBS) $(EXE_LDFLAGS)" + @echo $(call select_by,MDBX_BUILD_CXX," CXX =`which $(CXX)` | `$(CXX) --version | head -1`"," CC =`which $(CC)` | `$(CC) --version | head -1`") + @echo $(call select_by,MDBX_BUILD_CXX," CXXFLAGS =$(CXXFLAGS)"," CFLAGS =$(CFLAGS)") + @echo $(call select_by,MDBX_BUILD_CXX," LDFLAGS =$(LDFLAGS) $(LIB_STDCXXFS) $(LIBS) $(EXE_LDFLAGS)"," LDFLAGS =$(LDFLAGS) $(LIBS) $(EXE_LDFLAGS)") @echo '$(TIP) Use `make help` to listing available targets.' options: @@ -221,7 +225,7 @@ clean: config.h src/config.h src/version.c *.tar* buildflags.tag \ mdbx_*.static mdbx_*.static-lto -MDBX_BUILD_FLAGS =$(strip $(MDBX_BUILD_OPTIONS) $(CXXSTD) $(CFLAGS) $(LDFLAGS) $(LIBS)) +MDBX_BUILD_FLAGS =$(strip MDBX_BUILD_CXX=$(MDBX_BUILD_CXX) $(MDBX_BUILD_OPTIONS) $(call select_by,MDBX_BUILD_CXX,$(CXXFLAGS) $(LDFLAGS) $(LIB_STDCXXFS) $(LIBS),$(CFLAGS) $(LDFLAGS) $(LIBS))) check_buildflags_tag: $(QUIET)if [ "$(MDBX_BUILD_FLAGS)" != "$$(cat buildflags.tag 2>&1)" ]; then \ echo -n " CLEAN for build with specified flags..." && \ @@ -231,13 +235,13 @@ check_buildflags_tag: buildflags.tag: check_buildflags_tag -lib-static libmdbx.a: mdbx-static.o mdbx++-static.o +lib-static libmdbx.a: mdbx-static.o $(call select_by,MDBX_BUILD_CXX,mdbx++-static.o) @echo ' AR $@' $(QUIET)$(AR) rcs $@ $? $(HUSH) -lib-shared libmdbx.$(SO_SUFFIX): mdbx-dylib.o mdbx++-dylib.o +lib-shared libmdbx.$(SO_SUFFIX): mdbx-dylib.o $(call select_by,MDBX_BUILD_CXX,mdbx++-dylib.o) @echo ' LD $@' - $(QUIET)$(CXX) $(CXXFLAGS) $^ -pthread -shared $(LDFLAGS) $(LIB_STDCXXFS) $(LIBS) -o $@ + $(QUIET)$(call select_by,MDBX_BUILD_CXX,$(CXX) $(CXXFLAGS),$(CC) $(CFLAGS)) $^ -pthread -shared $(LDFLAGS) $(call select_by,MDBX_BUILD_CXX,$(LIB_STDCXXFS)) $(LIBS) -o $@ ################################################################################ @@ -316,7 +320,7 @@ IOARENA := $(shell \ (test -x ../ioarena/@BUILD/src/ioarena && echo ../ioarena/@BUILD/src/ioarena) || \ (test -x ../../@BUILD/src/ioarena && echo ../../@BUILD/src/ioarena) || \ (test -x ../../src/ioarena && echo ../../src/ioarena) || which ioarena 2>&- || \ - (echo false && echo '$(TIP) Clone and build the https://github.com/pmwkaa/ioarena.git within a neighbouring directory for availability of benchmarking.' >&2)) + (echo false && echo '$(TIP) Clone and build the https://abf.io/erthink/ioarena.git within a neighbouring directory for availability of benchmarking.' >&2)) endif NN ?= 25000000 BENCH_CRUD_MODE ?= nosync @@ -330,7 +334,7 @@ re-bench: bench-clean bench ifeq ($(or $(IOARENA),false),false) bench bench-quartet bench-triplet bench-couple: $(QUIET)echo 'The `ioarena` benchmark is required.' >&2 && \ - echo 'Please clone and build the https://github.com/pmwkaa/ioarena.git within a neighbouring `ioarena` directory.' >&2 && \ + echo 'Please clone and build the https://abf.io/erthink/ioarena.git within a neighbouring `ioarena` directory.' >&2 && \ false else @@ -340,16 +344,21 @@ else define bench-rule bench-$(1)_$(2).txt: $(3) $(IOARENA) $(lastword $(MAKEFILE_LIST)) @echo ' RUNNING ioarena for $1/$2...' - $(QUIET)LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}" \ + $(QUIET)(export LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}"; \ + ldd $(IOARENA) | grep -i $(1) && \ + $(IOARENA) -D $(1) -B batch -m $(BENCH_CRUD_MODE) -n $(2) \ + | tee $$@ | grep throughput | sed 's/throughput/batch×N/' && \ $(IOARENA) -D $(1) -B crud -m $(BENCH_CRUD_MODE) -n $(2) \ - | tee $$@ | grep throughput && \ - LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}" \ - $(IOARENA) -D $(1) -B get,iterate -m $(BENCH_CRUD_MODE) -r 4 -n $(2) \ - | tee -a $$@ | grep throughput \ - || mv -f $$@ $$@.error + | tee -a $$@ | grep throughput | sed 's/throughput/ crud/' && \ + $(IOARENA) -D $(1) -B iterate,get,iterate,get,iterate -m $(BENCH_CRUD_MODE) -r 4 -n $(2) \ + | tee -a $$@ | grep throughput | sed '0,/throughput/{s/throughput/iterate/};s/throughput/ get/' && \ + $(IOARENA) -D $(1) -B delete -m $(BENCH_CRUD_MODE) -n $(2) \ + | tee -a $$@ | grep throughput | sed 's/throughput/ delete/' && \ + true) || mv -f $$@ $$@.error endef + $(eval $(call bench-rule,mdbx,$(NN),libmdbx.$(SO_SUFFIX))) $(eval $(call bench-rule,sophia,$(NN))) diff --git a/mdbxdist/README.md b/mdbxdist/README.md index 3f78a26..de335b0 100644 --- a/mdbxdist/README.md +++ b/mdbxdist/README.md @@ -81,19 +81,48 @@ Historically, _libmdbx_ is a deeply revised and extended descendant of the amazi [Lightning Memory-Mapped Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database). _libmdbx_ inherits all benefits from _LMDB_, but resolves some issues and adds [a set of improvements](#improvements-beyond-lmdb). +### MithrilDB and Future + -The next version is under active non-public development from scratch and will be +The next version is under non-public development from scratch and will be released as **MithrilDB** and `libmithrildb` for libraries & packages. Admittedly mythical [Mithril](https://en.wikipedia.org/wiki/Mithril) is resembling silver but being stronger and lighter than steel. Therefore _MithrilDB_ is a rightly relevant name. - > _MithrilDB_ will be radically different from _libmdbx_ by the new - > database format and API based on C++17, as well as the [Apache 2.0 - > License](https://www.apache.org/licenses/LICENSE-2.0). The goal of this - > revolution is to provide a clearer and robust API, add more features and - > new valuable properties of the database. +_MithrilDB_ is radically different from _libmdbx_ by the new database +format and API based on C++20. The goal of this revolution is to provide +a clearer and robust API, add more features and new valuable properties +of the database. All fundamental architectural problems of libmdbx/LMDB +have been solved there, but now the active development has been +suspended for top-three reasons: + +1. For now _libmdbx_ «mostly» enough for all [our products](https://www.ptsecurity.com/ww-en/products/), +and I’m busy in development of replication for scalability. +2. Waiting for fresh [Elbrus CPU](https://wiki.elbrus.ru/) of [e2k architecture](https://en.wikipedia.org/wiki/Elbrus_2000), +especially with hardware acceleration of [Streebog](https://en.wikipedia.org/wiki/Streebog) and +[Kuznyechik](https://en.wikipedia.org/wiki/Kuznyechik), which are required for Merkle tree, etc. +3. The expectation of needs and opportunities due to the wide use of NVDIMM (aka persistent memory), +modern NVMe and [Ангара](https://ru.wikipedia.org/wiki/Ангара_(интерконнект)). + +However, _MithrilDB_ will not be available for countries unfriendly to +Russia (i.e. acceded the sanctions, devil adepts and/or NATO). But it is +not yet known whether such restriction will be implemented only through +a license and support, either the source code will not be open at all. +Basically we are not inclined to allow our work to contribute to the +profit that goes to weapons that kill our relatives and friends. +NO OPTIONS. + +Nonetheless, I try not to make any promises regarding _MithrilDB_ until release. + +Contrary to _MithrilDB_, _libmdbx_ will forever free and open source. +Moreover with high-quality support whenever possible. Tu deviens +responsable pour toujours de ce que tu as apprivois. So we will continue +to comply with the original open license and the principles of +constructive cooperation, in spite of outright Github sabotage and +sanctions. I will also try to keep (not drop) Windows support, despite +it is an unused obsolete technology for us. @@ -248,7 +277,7 @@ the user's point of view. > and up to 30% faster when _libmdbx_ compiled with specific build options > which downgrades several runtime checks to be match with LMDB behaviour. > - > These and other results could be easily reproduced with [ioArena](https://github.com/pmwkaa/ioarena) just by `make bench-quartet` command, + > These and other results could be easily reproduced with [ioArena](https://abf.io/erthink/ioarena) just by `make bench-quartet` command, > including comparisons with [RockDB](https://en.wikipedia.org/wiki/RocksDB) > and [WiredTiger](https://en.wikipedia.org/wiki/WiredTiger). @@ -353,7 +382,7 @@ named mutexes are used. Historically, _libmdbx_ is a deeply revised and extended descendant of the [Lightning Memory-Mapped Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database). At first the development was carried out within the -[ReOpenLDAP](https://web.archive.org/web/20220414235959/https://github.com/erthink/ReOpenLDAP) project. About a +[ReOpenLDAP](https://web.archive.org/web/https://github.com/erthink/ReOpenLDAP) project. About a year later _libmdbx_ was separated into a standalone project, which was [presented at Highload++ 2015 conference](http://www.highload.ru/2015/abstracts/1831.html). @@ -435,7 +464,7 @@ unexpected or broken down. ### Testing The amalgamated source code does not contain any tests for or several reasons. -Please read [the explanation](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/issues/214#issuecomment-870717981) and don't ask to alter this. +Please read [the explanation](https://libmdbx.dqdkfa.ru/dead-github/issues/214#issuecomment-870717981) and don't ask to alter this. So for testing _libmdbx_ itself you need a full source code, i.e. the clone of a git repository, there is no option. The full source code of _libmdbx_ has a [`test` subdirectory](https://gitflic.ru/project/erthink/libmdbx/tree/master/test) with minimalistic test "framework". @@ -618,7 +647,7 @@ Bindings | Rust | [libmdbx-rs](https://github.com/vorot93/libmdbx-rs) | [Artem Vorotnikov](https://github.com/vorot93) | | Rust | [mdbx](https://crates.io/crates/mdbx) | [gcxfd](https://github.com/gcxfd) | | Java | [mdbxjni](https://github.com/castortech/mdbxjni) | [Castor Technologies](https://castortech.com/) | -| Python (draft) | [python-bindings](https://web.archive.org/web/20220414235959/https://github.com/erthink/libmdbx/commits/python-bindings) branch | [Noel Kuntze](https://github.com/Thermi) +| Python (draft) | [python-bindings](https://libmdbx.dqdkfa.ru/dead-github/commits/python-bindings) branch | [Noel Kuntze](https://github.com/Thermi) | .NET (obsolete) | [mdbx.NET](https://github.com/wangjia184/mdbx.NET) | [Jerry Wang](https://github.com/wangjia184) | @@ -630,7 +659,7 @@ Bindings Performance comparison ====================== -All benchmarks were done in 2015 by [IOArena](https://github.com/pmwkaa/ioarena) +All benchmarks were done in 2015 by [IOArena](https://abf.io/erthink/ioarena) and multiple [scripts](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015) runs on Lenovo Carbon-2 laptop, i7-4600U 2.1 GHz (2 physical cores, 4 HyperThreading cores), 8 Gb RAM, SSD SAMSUNG MZNTD512HAGL-000L1 (DXT23L0Q) 512 Gb. diff --git a/mdbxdist/VERSION.txt b/mdbxdist/VERSION.txt index 3f0148e..44ac589 100644 --- a/mdbxdist/VERSION.txt +++ b/mdbxdist/VERSION.txt @@ -1 +1 @@ -0.12.0.71 +0.12.8.6 diff --git a/mdbxdist/cmake/compiler.cmake b/mdbxdist/cmake/compiler.cmake index 842c801..762ea1b 100644 --- a/mdbxdist/cmake/compiler.cmake +++ b/mdbxdist/cmake/compiler.cmake @@ -1,4 +1,4 @@ -## Copyright (c) 2012-2022 Leonid Yuriev . +## Copyright (c) 2012-2023 Leonid Yuriev . ## ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. @@ -13,7 +13,9 @@ ## limitations under the License. ## -if(CMAKE_VERSION VERSION_LESS 3.12) +if(CMAKE_VERSION VERSION_LESS 3.8.2) + cmake_minimum_required(VERSION 3.0.2) +elseif(CMAKE_VERSION VERSION_LESS 3.12) cmake_minimum_required(VERSION 3.8.2) else() cmake_minimum_required(VERSION 3.12) @@ -203,9 +205,38 @@ endif() if(NOT CMAKE_SYSTEM_ARCH) if(CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_ARCHITECTURE_ID) - set(CMAKE_SYSTEM_ARCH "${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_ARCHITECTURE_ID}") + string(TOLOWER "${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_ARCHITECTURE_ID}" CMAKE_SYSTEM_ARCH) + if(CMAKE_SYSTEM_ARCH STREQUAL "x86") + set(X86_32 TRUE) + elseif(CMAKE_SYSTEM_ARCH STREQUAL "x86_64" OR CMAKE_SYSTEM_ARCH STREQUAL "x64") + set(X86_64 TRUE) + set(CMAKE_SYSTEM_ARCH "x86_64") + elseif(CMAKE_SYSTEM_ARCH MATCHES "^(aarch.*|arm.*)") + if(CMAKE_TARGET_BITNESS EQUAL 64) + set(AARCH64 TRUE) + else() + set(ARM32 TRUE) + endif() + endif() elseif(CMAKE_ANDROID_ARCH_ABI) set(CMAKE_SYSTEM_ARCH "${CMAKE_ANDROID_ARCH_ABI}") + if(CMAKE_SYSTEM_ARCH STREQUAL "x86") + set(X86_32 TRUE) + elseif(CMAKE_SYSTEM_ARCH STREQUAL "x86_64") + set(X86_64 TRUE) + elseif(CMAKE_SYSTEM_ARCH MATCHES "^(aarch.*|AARCH.*|arm.*|ARM.*)") + if(CMAKE_TARGET_BITNESS EQUAL 64) + set(AARCH64 TRUE) + else() + set(ARM32 TRUE) + endif() + elseif(CMAKE_SYSTEM_ARCH MATCHES "^(mips|MIPS).*") + if(CMAKE_TARGET_BITNESS EQUAL 64) + set(MIPS64 TRUE) + else() + set(MIPS32 TRUE) + endif() + endif() elseif(CMAKE_COMPILER_IS_ELBRUSC OR CMAKE_COMPILER_IS_ELBRUSCXX OR CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_ID STREQUAL "LCC" OR CMAKE_SYSTEM_PROCESSOR MATCHES "e2k.*|E2K.*|elbrus.*|ELBRUS.*") @@ -317,6 +348,8 @@ endif() if(MSVC) check_compiler_flag("/WX" CC_HAS_WERROR) + check_compiler_flag("/fsanitize=address" CC_HAS_ASAN) + check_compiler_flag("/fsanitize=undefined" CC_HAS_UBSAN) else() # # GCC started to warn for unused result starting from 4.2, and @@ -808,19 +841,26 @@ macro(setup_compile_flags) endif() if(ENABLE_ASAN) - add_compile_flags("C;CXX" "-fsanitize=address") + if(NOT MSVC) + add_compile_flags("C;CXX" "-fsanitize=address") + else() + add_compile_flags("C;CXX" "/fsanitize=address") + endif() add_definitions(-DASAN_ENABLED=1) endif() if(ENABLE_UBSAN) - add_compile_flags("C;CXX" "-fsanitize=undefined" "-fsanitize-undefined-trap-on-error") + if(NOT MSVC) + add_compile_flags("C;CXX" "-fsanitize=undefined" "-fsanitize-undefined-trap-on-error") + else() + add_compile_flags("C;CXX" "/fsanitize=undefined") + endif() add_definitions(-DUBSAN_ENABLED=1) endif() if(ENABLE_GCOV) if(NOT HAVE_GCOV) - message(FATAL_ERROR - "ENABLE_GCOV option requested but gcov library is not found") + message(FATAL_ERROR "ENABLE_GCOV option requested but gcov library is not found") endif() add_compile_flags("C;CXX" "-fprofile-arcs" "-ftest-coverage") @@ -929,12 +969,13 @@ endmacro(setup_compile_flags) macro(probe_libcxx_filesystem) if(CMAKE_CXX_COMPILER_LOADED AND NOT DEFINED LIBCXX_FILESYSTEM) list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_11 HAS_CXX11) - if(NOT HAS_CXX11 LESS 0) + if(NOT HAS_CXX11 LESS 0 OR CXX_FALLBACK_GNU11 OR CXX_FALLBACK_11) include(CMakePushCheckState) include(CheckCXXSourceCompiles) cmake_push_check_state() set(stdfs_probe_save_libraries ${CMAKE_REQUIRED_LIBRARIES}) set(stdfs_probe_save_flags ${CMAKE_REQUIRED_FLAGS}) + set(stdfs_probe_flags ${CMAKE_REQUIRED_FLAGS}) set(stdfs_probe_save_link_options ${CMAKE_REQUIRED_LINK_OPTIONS}) unset(stdfs_probe_clear_cxx_standard) if(NOT DEFINED CMAKE_CXX_STANDARD) @@ -945,18 +986,23 @@ macro(probe_libcxx_filesystem) set(CMAKE_CXX_STANDARD 17) elseif(NOT HAS_CXX14 LESS 0) set(CMAKE_CXX_STANDARD 14) - else() + elseif(NOT HAS_CXX11 LESS 0) set(CMAKE_CXX_STANDARD 11) + elseif(CXX_FALLBACK_GNU11) + set(stdfs_probe_flags ${stdfs_probe_flags} "-std=gnu++11") + else() + set(stdfs_probe_flags ${stdfs_probe_flags} "-std=c++11") endif() set(stdfs_probe_clear_cxx_standard ON) endif() if(CMAKE_COMPILER_IS_ELBRUSCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 1.25.23) if(CMAKE_VERSION VERSION_LESS 3.14) - set(CMAKE_REQUIRED_FLAGS ${stdfs_probe_save_flags} "-Wl,--allow-multiple-definition") + set(stdfs_probe_flags ${stdfs_probe_flags} "-Wl,--allow-multiple-definition") else() set(CMAKE_REQUIRED_LINK_OPTIONS ${stdfs_probe_save_link_options} "-Wl,--allow-multiple-definition") endif() endif() + set(CMAKE_REQUIRED_FLAGS ${stdfs_probe_flags}) set(stdfs_probe_code [[ #if defined(__SIZEOF_INT128__) && !defined(__GLIBCXX_TYPE_INT_N_0) && defined(__clang__) && __clang_major__ < 4 @@ -993,9 +1039,15 @@ macro(probe_libcxx_filesystem) #endif int main(int argc, const char*argv[]) { - fs::path probe(argv[0]); + std::string str(argv[0]); + fs::path probe(str); if (argc != 1) throw fs::filesystem_error(std::string("fake"), std::error_code()); - return fs::is_directory(probe.relative_path()); + int r = fs::is_directory(probe.relative_path()); + for (auto const& i : fs::directory_iterator(probe)) { + ++r; + (void)i; + } + return r; } ]]) set(LIBCXX_FILESYSTEM "") @@ -1037,6 +1089,7 @@ macro(probe_libcxx_filesystem) unset(stdfs_probe_clear_cxx_standard) unset(stdfs_probe_save_link_options) unset(stdfs_probe_save_flags) + unset(stdfs_probe_flags) unset(stdfs_probe_save_libraries) unset(stdfs_probe_code) unset(stdfs_probe_rc) diff --git a/mdbxdist/cmake/profile.cmake b/mdbxdist/cmake/profile.cmake index 6fe9c82..f13b697 100644 --- a/mdbxdist/cmake/profile.cmake +++ b/mdbxdist/cmake/profile.cmake @@ -1,4 +1,4 @@ -## Copyright (c) 2012-2022 Leonid Yuriev . +## Copyright (c) 2012-2023 Leonid Yuriev . ## ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. @@ -13,7 +13,9 @@ ## limitations under the License. ## -if(CMAKE_VERSION VERSION_LESS 3.12) +if(CMAKE_VERSION VERSION_LESS 3.8.2) + cmake_minimum_required(VERSION 3.0.2) +elseif(CMAKE_VERSION VERSION_LESS 3.12) cmake_minimum_required(VERSION 3.8.2) else() cmake_minimum_required(VERSION 3.12) diff --git a/mdbxdist/cmake/utils.cmake b/mdbxdist/cmake/utils.cmake index a461cc2..aa8aef0 100644 --- a/mdbxdist/cmake/utils.cmake +++ b/mdbxdist/cmake/utils.cmake @@ -1,4 +1,4 @@ -## Copyright (c) 2012-2022 Leonid Yuriev . +## Copyright (c) 2012-2023 Leonid Yuriev . ## ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. @@ -13,7 +13,9 @@ ## limitations under the License. ## -if(CMAKE_VERSION VERSION_LESS 3.12) +if(CMAKE_VERSION VERSION_LESS 3.8.2) + cmake_minimum_required(VERSION 3.0.2) +elseif(CMAKE_VERSION VERSION_LESS 3.12) cmake_minimum_required(VERSION 3.8.2) else() cmake_minimum_required(VERSION 3.12) diff --git a/mdbxdist/config.h.in b/mdbxdist/config.h.in index 58119c3..05c561b 100644 --- a/mdbxdist/config.h.in +++ b/mdbxdist/config.h.in @@ -27,6 +27,12 @@ #cmakedefine01 MDBX_TRUST_RTC #endif #cmakedefine01 MDBX_DISABLE_VALIDATION +#cmakedefine01 MDBX_AVOID_MSYNC +#cmakedefine01 MDBX_ENABLE_REFUND +#cmakedefine01 MDBX_ENABLE_MADVISE +#cmakedefine01 MDBX_ENABLE_BIGFOOT +#cmakedefine01 MDBX_ENABLE_PGOP_STAT +#cmakedefine01 MDBX_ENABLE_PROFGC /* Windows */ #cmakedefine01 MDBX_WITHOUT_MSVC_CRT diff --git a/mdbxdist/man1/mdbx_chk.1 b/mdbxdist/man1/mdbx_chk.1 index 343b80c..aa4e986 100644 --- a/mdbxdist/man1/mdbx_chk.1 +++ b/mdbxdist/man1/mdbx_chk.1 @@ -1,6 +1,6 @@ -.\" Copyright 2015-2022 Leonid Yuriev . +.\" Copyright 2015-2023 Leonid Yuriev . .\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.TH MDBX_CHK 1 "2022-06-19" "MDBX 0.12.0" +.TH MDBX_CHK 1 "2023-10-17" "MDBX 0.12.8" .SH NAME mdbx_chk \- MDBX checking tool .SH SYNOPSIS @@ -81,6 +81,13 @@ Turn to a specified meta-page on successful check. .BR \-T Turn to a specified meta-page EVEN ON UNSUCCESSFUL CHECK! .TP +.BR \-u +Warms up the DB before checking via notifying OS kernel of subsequent access to the database pages. +.TP +.BR \-U +Warms up the DB before checking, notifying the OS kernel of subsequent access to the database pages, +then forcibly loads ones by sequential access and tries to lock database pages in memory. +.TP .BR \-n Open MDBX environment(s) which do not use subdirectories. This is legacy option. For now MDBX handles this automatically. diff --git a/mdbxdist/man1/mdbx_copy.1 b/mdbxdist/man1/mdbx_copy.1 index 4a86117..4e67a5b 100644 --- a/mdbxdist/man1/mdbx_copy.1 +++ b/mdbxdist/man1/mdbx_copy.1 @@ -1,8 +1,8 @@ -.\" Copyright 2015-2022 Leonid Yuriev . -.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. +.\" Copyright 2015-2023 Leonid Yuriev . .\" Copyright 2015,2016 Peter-Service R&D LLC . +.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.TH MDBX_COPY 1 "2022-06-19" "MDBX 0.12.0" +.TH MDBX_COPY 1 "2023-10-17" "MDBX 0.12.8" .SH NAME mdbx_copy \- MDBX environment copy tool .SH SYNOPSIS @@ -45,6 +45,13 @@ or unused pages will be omitted from the copy. This option will slow down the backup process as it is more CPU-intensive. Currently it fails if the environment has suffered a page leak. .TP +.BR \-u +Warms up the DB before copying via notifying OS kernel of subsequent access to the database pages. +.TP +.BR \-U +Warms up the DB before copying, notifying the OS kernel of subsequent access to the database pages, +then forcibly loads ones by sequential access and tries to lock database pages in memory. +.TP .BR \-n Open MDBX environment(s) which do not use subdirectories. This is legacy option. For now MDBX handles this automatically. diff --git a/mdbxdist/man1/mdbx_drop.1 b/mdbxdist/man1/mdbx_drop.1 index 1594580..425eecd 100644 --- a/mdbxdist/man1/mdbx_drop.1 +++ b/mdbxdist/man1/mdbx_drop.1 @@ -1,7 +1,7 @@ -.\" Copyright 2021-2022 Leonid Yuriev . +.\" Copyright 2021-2023 Leonid Yuriev . .\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.TH MDBX_DROP 1 "2022-06-19" "MDBX 0.12.0" +.TH MDBX_DROP 1 "2023-10-17" "MDBX 0.12.8" .SH NAME mdbx_drop \- MDBX database delete tool .SH SYNOPSIS diff --git a/mdbxdist/man1/mdbx_dump.1 b/mdbxdist/man1/mdbx_dump.1 index 4e360ed..d236b93 100644 --- a/mdbxdist/man1/mdbx_dump.1 +++ b/mdbxdist/man1/mdbx_dump.1 @@ -1,8 +1,8 @@ -.\" Copyright 2015-2022 Leonid Yuriev . -.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. +.\" Copyright 2015-2023 Leonid Yuriev . .\" Copyright 2015,2016 Peter-Service R&D LLC . +.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.TH MDBX_DUMP 1 "2022-06-19" "MDBX 0.12.0" +.TH MDBX_DUMP 1 "2023-10-17" "MDBX 0.12.8" .SH NAME mdbx_dump \- MDBX environment export tool .SH SYNOPSIS @@ -66,6 +66,13 @@ Dump a specific subdatabase. If no database is specified, only the main database .BR \-r Rescure mode. Ignore some errors to dump corrupted DB. .TP +.BR \-u +Warms up the DB before dumping via notifying OS kernel of subsequent access to the database pages. +.TP +.BR \-U +Warms up the DB before dumping, notifying the OS kernel of subsequent access to the database pages, +then forcibly loads ones by sequential access and tries to lock database pages in memory. +.TP .BR \-n Dump an MDBX database which does not use subdirectories. This is legacy option. For now MDBX handles this automatically. diff --git a/mdbxdist/man1/mdbx_load.1 b/mdbxdist/man1/mdbx_load.1 index 1363d56..ae8e759 100644 --- a/mdbxdist/man1/mdbx_load.1 +++ b/mdbxdist/man1/mdbx_load.1 @@ -1,8 +1,8 @@ -.\" Copyright 2015-2022 Leonid Yuriev . -.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. +.\" Copyright 2015-2023 Leonid Yuriev . .\" Copyright 2015,2016 Peter-Service R&D LLC . +.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.TH MDBX_LOAD 1 "2022-06-19" "MDBX 0.12.0" +.TH MDBX_LOAD 1 "2023-10-17" "MDBX 0.12.8" .SH NAME mdbx_load \- MDBX environment import tool .SH SYNOPSIS diff --git a/mdbxdist/man1/mdbx_stat.1 b/mdbxdist/man1/mdbx_stat.1 index 1580ed4..c330d2e 100644 --- a/mdbxdist/man1/mdbx_stat.1 +++ b/mdbxdist/man1/mdbx_stat.1 @@ -1,8 +1,8 @@ -.\" Copyright 2015-2022 Leonid Yuriev . -.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. +.\" Copyright 2015-2023 Leonid Yuriev . .\" Copyright 2015,2016 Peter-Service R&D LLC . +.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.TH MDBX_STAT 1 "2022-06-19" "MDBX 0.12.0" +.TH MDBX_STAT 1 "2023-10-17" "MDBX 0.12.8" .SH NAME mdbx_stat \- MDBX environment status tool .SH SYNOPSIS diff --git a/mdbxdist/mdbx.c b/mdbxdist/mdbx.c index 634fcc2..23cb316 100644 --- a/mdbxdist/mdbx.c +++ b/mdbxdist/mdbx.c @@ -12,7 +12,7 @@ * . */ #define xMDBX_ALLOY 1 -#define MDBX_BUILD_SOURCERY 748ccee885a921bfe8ef7b24e71957dd3922fe37083ceb8048cb89c28c5d8f9b_v0_12_7_20_g2b0eae08 +#define MDBX_BUILD_SOURCERY d7603e99410126db376215bd0ceb9c2e32eba2af6c4988c85272497a38e29e56_v0_12_8_6_ged8c7ead #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -2051,8 +2051,7 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; /** Controls using Unix' mincore() to determine whether DB-pages * are resident in memory. */ #ifndef MDBX_ENABLE_MINCORE -#if MDBX_ENABLE_PREFAULT && \ - (defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64))) +#if defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64)) #define MDBX_ENABLE_MINCORE 1 #else #define MDBX_ENABLE_MINCORE 0 @@ -20916,11 +20915,13 @@ static __hot int cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, } break; case MDBX_GET_MULTIPLE: - if (unlikely(data == NULL || !(mc->mc_flags & C_INITIALIZED))) + if (unlikely(!data)) return MDBX_EINVAL; - if (unlikely(!(mc->mc_db->md_flags & MDBX_DUPFIXED))) + if (unlikely((mc->mc_db->md_flags & MDBX_DUPFIXED) == 0)) return MDBX_INCOMPATIBLE; - rc = MDBX_SUCCESS; + rc = (mc->mc_flags & C_INITIALIZED) + ? MDBX_SUCCESS + : cursor_set(mc, key, data, MDBX_SET).err; if ((mc->mc_xcursor->mx_cursor.mc_flags & (C_INITIALIZED | C_EOF)) != C_INITIALIZED) break; @@ -27101,30 +27102,6 @@ int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, bool del) { return rc; } -int mdbx_set_compare(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR); - if (unlikely(rc != MDBX_SUCCESS)) - return rc; - - if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID))) - return MDBX_BAD_DBI; - - txn->mt_dbxs[dbi].md_cmp = cmp; - return MDBX_SUCCESS; -} - -int mdbx_set_dupsort(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR); - if (unlikely(rc != MDBX_SUCCESS)) - return rc; - - if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID))) - return MDBX_BAD_DBI; - - txn->mt_dbxs[dbi].md_dcmp = cmp; - return MDBX_SUCCESS; -} - __cold int mdbx_reader_list(const MDBX_env *env, MDBX_reader_list_func *func, void *ctx) { int rc = check_env(env, true); @@ -33363,10 +33340,10 @@ __dll_export const struct MDBX_version_info mdbx_version = { 0, 12, - 7, - 20, - {"2023-10-09T22:12:06+03:00", "1f76e0a48d39074b6ca2a30b74c31b858d09cb2b", "2b0eae08f565b55d035d08cb87dea89566cf0747", - "v0.12.7-20-g2b0eae08"}, + 8, + 6, + {"2023-10-29T12:20:54+03:00", "551a22197e35ee5c5902f8fe0c4dbf4da99722a4", "ed8c7ead4e0f7afc50491d34918eae85dff64b86", + "v0.12.8-6-ged8c7ead"}, sourcery}; __dll_export diff --git a/mdbxdist/mdbx.c++ b/mdbxdist/mdbx.c++ index d41fcd0..20c62e2 100644 --- a/mdbxdist/mdbx.c++ +++ b/mdbxdist/mdbx.c++ @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 Leonid Yuriev + * Copyright 2015-2023 Leonid Yuriev * and other libmdbx authors: please see AUTHORS file. * All rights reserved. * @@ -12,7 +12,7 @@ * . */ #define xMDBX_ALLOY 1 -#define MDBX_BUILD_SOURCERY 99d371079af9d05b2f0e8751b4ee8fd75986ecba45c5a7f9807d154a86cff0eb_v0_12_0_71_g1cac6536 +#define MDBX_BUILD_SOURCERY d7603e99410126db376215bd0ceb9c2e32eba2af6c4988c85272497a38e29e56_v0_12_8_6_ged8c7ead #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -36,7 +36,7 @@ /** Disables using GNU/Linux libc extensions. * \ingroup build_option - * \note This option couldn't be moved to the options.h since dependant + * \note This option couldn't be moved to the options.h since dependent * control macros/defined should be prepared before include the options.h */ #ifndef MDBX_DISABLE_GNU_SOURCE #define MDBX_DISABLE_GNU_SOURCE 0 @@ -87,27 +87,31 @@ #pragma warning(disable : 4464) /* relative include path contains '..' */ #endif #if _MSC_VER > 1913 -#pragma warning(disable : 5045) /* Compiler will insert Spectre mitigation... \ - */ +#pragma warning(disable : 5045) /* will insert Spectre mitigation... */ #endif #if _MSC_VER > 1914 #pragma warning( \ - disable : 5105) /* winbase.h(9531): warning C5105: macro expansion \ - producing 'defined' has undefined behavior */ + disable : 5105) /* winbase.h(9531): warning C5105: macro expansion \ + producing 'defined' has undefined behavior */ +#endif +#if _MSC_VER > 1930 +#pragma warning(disable : 6235) /* is always a constant */ +#pragma warning(disable : 6237) /* is never evaluated and might \ + have side effects */ #endif #pragma warning(disable : 4710) /* 'xyz': function not inlined */ #pragma warning(disable : 4711) /* function 'xyz' selected for automatic \ inline expansion */ -#pragma warning( \ - disable : 4201) /* nonstandard extension used : nameless struct / union */ +#pragma warning(disable : 4201) /* nonstandard extension used: nameless \ + struct/union */ #pragma warning(disable : 4702) /* unreachable code */ #pragma warning(disable : 4706) /* assignment within conditional expression */ #pragma warning(disable : 4127) /* conditional expression is constant */ #pragma warning(disable : 4324) /* 'xyz': structure was padded due to \ alignment specifier */ #pragma warning(disable : 4310) /* cast truncates constant value */ -#pragma warning( \ - disable : 4820) /* bytes padding added after data member for alignment */ +#pragma warning(disable : 4820) /* bytes padding added after data member for \ + alignment */ #pragma warning(disable : 4548) /* expression before comma has no effect; \ expected expression with side - effect */ #pragma warning(disable : 4366) /* the result of the unary '&' operator may be \ @@ -117,8 +121,8 @@ #pragma warning(disable : 4204) /* nonstandard extension used: non-constant \ aggregate initializer */ #pragma warning( \ - disable : 4505) /* unreferenced local function has been removed */ -#endif /* _MSC_VER (warnings) */ + disable : 4505) /* unreferenced local function has been removed */ +#endif /* _MSC_VER (warnings) */ #if defined(__GNUC__) && __GNUC__ < 9 #pragma GCC diagnostic ignored "-Wattributes" @@ -127,11 +131,15 @@ #if (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)) && \ !defined(__USE_MINGW_ANSI_STDIO) #define __USE_MINGW_ANSI_STDIO 1 -#endif /* __USE_MINGW_ANSI_STDIO */ +#endif /* MinGW */ + +#if (defined(_WIN32) || defined(_WIN64)) && !defined(UNICODE) +#define UNICODE +#endif /* UNICODE */ #include "mdbx.h++" /* - * Copyright 2015-2022 Leonid Yuriev + * Copyright 2015-2023 Leonid Yuriev * and other libmdbx authors: please see AUTHORS file. * All rights reserved. * @@ -194,7 +202,7 @@ #define SSIZE_MAX INTPTR_MAX #endif -#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul +#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul || defined(_WIN64) #define MDBX_WORDBITS 64 #else #define MDBX_WORDBITS 32 @@ -288,12 +296,12 @@ #define nullptr NULL #endif -#ifdef __APPLE__ +#if defined(__APPLE__) || defined(_DARWIN_C_SOURCE) #include +#include #ifndef MAC_OS_X_VERSION_MIN_REQUIRED #define MAC_OS_X_VERSION_MIN_REQUIRED 1070 /* Mac OS X 10.7, 2011 */ #endif -#include #endif /* Apple OSX & iOS */ #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ @@ -367,10 +375,6 @@ __extern_C key_t ftok(const char *, int); #elif _WIN32_WINNT < 0x0500 #error At least 'Windows 2000' API is required for libmdbx. #endif /* _WIN32_WINNT */ -#if (defined(__MINGW32__) || defined(__MINGW64__)) && \ - !defined(__USE_MINGW_ANSI_STDIO) -#define __USE_MINGW_ANSI_STDIO 1 -#endif /* MinGW */ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif /* WIN32_LEAN_AND_MEAN */ @@ -394,8 +398,10 @@ __extern_C key_t ftok(const char *, int); #include #include #include +#include #include #include +#include #include #endif /*---------------------------------------------------------------------*/ @@ -426,8 +432,8 @@ __extern_C key_t ftok(const char *, int); /* Byteorder */ #if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \ - defined(i486) || defined(__i486) || defined(__i486__) || \ - defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) || \ + defined(i486) || defined(__i486) || defined(__i486__) || defined(i586) || \ + defined(__i586) || defined(__i586__) || defined(i686) || \ defined(__i686) || defined(__i686__) || defined(_M_IX86) || \ defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || \ defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) || \ @@ -437,8 +443,9 @@ __extern_C key_t ftok(const char *, int); /* LY: define neutral __ia32__ for x86 and x86-64 */ #define __ia32__ 1 #endif /* __ia32__ */ -#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) || \ - defined(__amd64) || defined(_M_X64)) +#if !defined(__amd64__) && \ + (defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || \ + defined(_M_X64) || defined(_M_AMD64)) /* LY: define trusty __amd64__ for all AMD64/x86-64 arch */ #define __amd64__ 1 #endif /* __amd64__ */ @@ -506,18 +513,50 @@ __extern_C key_t ftok(const char *, int); #endif #endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */ +/*----------------------------------------------------------------------------*/ +/* Availability of CMOV or equivalent */ + +#ifndef MDBX_HAVE_CMOV +#if defined(__e2k__) +#define MDBX_HAVE_CMOV 1 +#elif defined(__thumb2__) || defined(__thumb2) +#define MDBX_HAVE_CMOV 1 +#elif defined(__thumb__) || defined(__thumb) || defined(__TARGET_ARCH_THUMB) +#define MDBX_HAVE_CMOV 0 +#elif defined(_M_ARM) || defined(_M_ARM64) || defined(__aarch64__) || \ + defined(__aarch64) || defined(__arm__) || defined(__arm) || \ + defined(__CC_ARM) +#define MDBX_HAVE_CMOV 1 +#elif (defined(__riscv__) || defined(__riscv64)) && \ + (defined(__riscv_b) || defined(__riscv_bitmanip)) +#define MDBX_HAVE_CMOV 1 +#elif defined(i686) || defined(__i686) || defined(__i686__) || \ + (defined(_M_IX86) && _M_IX86 > 600) || defined(__x86_64) || \ + defined(__x86_64__) || defined(__amd64__) || defined(__amd64) || \ + defined(_M_X64) || defined(_M_AMD64) +#define MDBX_HAVE_CMOV 1 +#else +#define MDBX_HAVE_CMOV 0 +#endif +#endif /* MDBX_HAVE_CMOV */ + /*----------------------------------------------------------------------------*/ /* Compiler's includes for builtins/intrinsics */ #if defined(_MSC_VER) || defined(__INTEL_COMPILER) #include #elif __GNUC_PREREQ(4, 4) || defined(__clang__) -#if defined(__ia32__) || defined(__e2k__) +#if defined(__e2k__) +#include #include -#endif /* __ia32__ */ +#endif /* __e2k__ */ #if defined(__ia32__) #include +#include #endif /* __ia32__ */ +#ifdef __ARM_NEON +#include +#endif #elif defined(__SUNPRO_C) || defined(__sun) || defined(sun) #include #elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) && \ @@ -672,15 +711,13 @@ __extern_C key_t ftok(const char *, int); #ifndef __hot #if defined(__OPTIMIZE__) -#if defined(__e2k__) -#define __hot __attribute__((__hot__)) __optimize(3) -#elif defined(__clang__) && !__has_attribute(__hot_) && \ +#if defined(__clang__) && !__has_attribute(__hot__) && \ __has_attribute(__section__) && \ (defined(__linux__) || defined(__gnu_linux__)) /* just put frequently used functions in separate section */ #define __hot __attribute__((__section__("text.hot"))) __optimize("O3") #elif defined(__GNUC__) || __has_attribute(__hot__) -#define __hot __attribute__((__hot__)) __optimize("O3") +#define __hot __attribute__((__hot__)) #else #define __hot __optimize("O3") #endif @@ -691,15 +728,13 @@ __extern_C key_t ftok(const char *, int); #ifndef __cold #if defined(__OPTIMIZE__) -#if defined(__e2k__) -#define __cold __attribute__((__cold__)) __optimize(1) -#elif defined(__clang__) && !__has_attribute(cold) && \ +#if defined(__clang__) && !__has_attribute(__cold__) && \ __has_attribute(__section__) && \ (defined(__linux__) || defined(__gnu_linux__)) /* just put infrequently used functions in separate section */ #define __cold __attribute__((__section__("text.unlikely"))) __optimize("Os") -#elif defined(__GNUC__) || __has_attribute(cold) -#define __cold __attribute__((__cold__)) __optimize("Os") +#elif defined(__GNUC__) || __has_attribute(__cold__) +#define __cold __attribute__((__cold__)) #else #define __cold __optimize("Os") #endif @@ -742,6 +777,51 @@ __extern_C key_t ftok(const char *, int); #endif #endif /* __anonymous_struct_extension__ */ +#ifndef expect_with_probability +#if defined(__builtin_expect_with_probability) || \ + __has_builtin(__builtin_expect_with_probability) || __GNUC_PREREQ(9, 0) +#define expect_with_probability(expr, value, prob) \ + __builtin_expect_with_probability(expr, value, prob) +#else +#define expect_with_probability(expr, value, prob) (expr) +#endif +#endif /* expect_with_probability */ + +#ifndef MDBX_WEAK_IMPORT_ATTRIBUTE +#ifdef WEAK_IMPORT_ATTRIBUTE +#define MDBX_WEAK_IMPORT_ATTRIBUTE WEAK_IMPORT_ATTRIBUTE +#elif __has_attribute(__weak__) && __has_attribute(__weak_import__) +#define MDBX_WEAK_IMPORT_ATTRIBUTE __attribute__((__weak__, __weak_import__)) +#elif __has_attribute(__weak__) || \ + (defined(__GNUC__) && __GNUC__ >= 4 && defined(__ELF__)) +#define MDBX_WEAK_IMPORT_ATTRIBUTE __attribute__((__weak__)) +#else +#define MDBX_WEAK_IMPORT_ATTRIBUTE +#endif +#endif /* MDBX_WEAK_IMPORT_ATTRIBUTE */ + +#ifndef MDBX_GOOFY_MSVC_STATIC_ANALYZER +#ifdef _PREFAST_ +#define MDBX_GOOFY_MSVC_STATIC_ANALYZER 1 +#else +#define MDBX_GOOFY_MSVC_STATIC_ANALYZER 0 +#endif +#endif /* MDBX_GOOFY_MSVC_STATIC_ANALYZER */ + +#if MDBX_GOOFY_MSVC_STATIC_ANALYZER || (defined(_MSC_VER) && _MSC_VER > 1919) +#define MDBX_ANALYSIS_ASSUME(expr) __analysis_assume(expr) +#ifdef _PREFAST_ +#define MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(warn_id) \ + __pragma(prefast(suppress : warn_id)) +#else +#define MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(warn_id) \ + __pragma(warning(suppress : warn_id)) +#endif +#else +#define MDBX_ANALYSIS_ASSUME(expr) assert(expr) +#define MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(warn_id) +#endif /* MDBX_GOOFY_MSVC_STATIC_ANALYZER */ + /*----------------------------------------------------------------------------*/ #if defined(MDBX_USE_VALGRIND) @@ -896,6 +976,16 @@ __Wpedantic_format_voidptr(const void *ptr) { #endif #endif /* -Walignment-reduction-ignored */ +#ifndef MDBX_EXCLUDE_FOR_GPROF +#ifdef ENABLE_GPROF +#define MDBX_EXCLUDE_FOR_GPROF \ + __attribute__((__no_instrument_function__, \ + __no_profile_instrument_function__)) +#else +#define MDBX_EXCLUDE_FOR_GPROF +#endif /* ENABLE_GPROF */ +#endif /* MDBX_EXCLUDE_FOR_GPROF */ + #ifdef __cplusplus extern "C" { #endif @@ -903,7 +993,7 @@ extern "C" { /* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */ /* - * Copyright 2015-2022 Leonid Yuriev + * Copyright 2015-2023 Leonid Yuriev * and other libmdbx authors: please see AUTHORS file. * All rights reserved. * @@ -959,7 +1049,7 @@ extern "C" { #include #endif -MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) { +MDBX_MAYBE_UNUSED static __inline void osal_compiler_barrier(void) { #if defined(__clang__) || defined(__GNUC__) __asm__ __volatile__("" ::: "memory"); #elif defined(_MSC_VER) @@ -979,7 +1069,7 @@ MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) { #endif } -MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) { +MDBX_MAYBE_UNUSED static __inline void osal_memory_barrier(void) { #ifdef MDBX_HAVE_C11ATOMICS atomic_thread_fence(memory_order_seq_cst); #elif defined(__ATOMIC_SEQ_CST) @@ -1017,8 +1107,8 @@ MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) { #if defined(_WIN32) || defined(_WIN64) #define HAVE_SYS_STAT_H #define HAVE_SYS_TYPES_H -typedef HANDLE mdbx_thread_t; -typedef unsigned mdbx_thread_key_t; +typedef HANDLE osal_thread_t; +typedef unsigned osal_thread_key_t; #define MAP_FAILED NULL #define HIGH_DWORD(v) ((DWORD)((sizeof(v) > 4) ? ((uint64_t)(v) >> 32) : 0)) #define THREAD_CALL WINAPI @@ -1026,8 +1116,8 @@ typedef unsigned mdbx_thread_key_t; typedef struct { HANDLE mutex; HANDLE event[2]; -} mdbx_condpair_t; -typedef CRITICAL_SECTION mdbx_fastmutex_t; +} osal_condpair_t; +typedef CRITICAL_SECTION osal_fastmutex_t; #if !defined(_MSC_VER) && !defined(__try) #define __try @@ -1036,36 +1126,36 @@ typedef CRITICAL_SECTION mdbx_fastmutex_t; #if MDBX_WITHOUT_MSVC_CRT -#ifndef mdbx_malloc -static inline void *mdbx_malloc(size_t bytes) { +#ifndef osal_malloc +static inline void *osal_malloc(size_t bytes) { return HeapAlloc(GetProcessHeap(), 0, bytes); } -#endif /* mdbx_malloc */ +#endif /* osal_malloc */ -#ifndef mdbx_calloc -static inline void *mdbx_calloc(size_t nelem, size_t size) { +#ifndef osal_calloc +static inline void *osal_calloc(size_t nelem, size_t size) { return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nelem * size); } -#endif /* mdbx_calloc */ +#endif /* osal_calloc */ -#ifndef mdbx_realloc -static inline void *mdbx_realloc(void *ptr, size_t bytes) { +#ifndef osal_realloc +static inline void *osal_realloc(void *ptr, size_t bytes) { return ptr ? HeapReAlloc(GetProcessHeap(), 0, ptr, bytes) : HeapAlloc(GetProcessHeap(), 0, bytes); } -#endif /* mdbx_realloc */ +#endif /* osal_realloc */ -#ifndef mdbx_free -static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } -#endif /* mdbx_free */ +#ifndef osal_free +static inline void osal_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } +#endif /* osal_free */ #else /* MDBX_WITHOUT_MSVC_CRT */ -#define mdbx_malloc malloc -#define mdbx_calloc calloc -#define mdbx_realloc realloc -#define mdbx_free free -#define mdbx_strdup _strdup +#define osal_malloc malloc +#define osal_calloc calloc +#define osal_realloc realloc +#define osal_free free +#define osal_strdup _strdup #endif /* MDBX_WITHOUT_MSVC_CRT */ @@ -1079,21 +1169,21 @@ static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } #else /*----------------------------------------------------------------------*/ -typedef pthread_t mdbx_thread_t; -typedef pthread_key_t mdbx_thread_key_t; +typedef pthread_t osal_thread_t; +typedef pthread_key_t osal_thread_key_t; #define INVALID_HANDLE_VALUE (-1) #define THREAD_CALL #define THREAD_RESULT void * typedef struct { pthread_mutex_t mutex; pthread_cond_t cond[2]; -} mdbx_condpair_t; -typedef pthread_mutex_t mdbx_fastmutex_t; -#define mdbx_malloc malloc -#define mdbx_calloc calloc -#define mdbx_realloc realloc -#define mdbx_free free -#define mdbx_strdup strdup +} osal_condpair_t; +typedef pthread_mutex_t osal_fastmutex_t; +#define osal_malloc malloc +#define osal_calloc calloc +#define osal_realloc realloc +#define osal_free free +#define osal_strdup strdup #endif /* Platform */ #if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size) @@ -1107,24 +1197,30 @@ typedef pthread_mutex_t mdbx_fastmutex_t; /*----------------------------------------------------------------------------*/ /* OS abstraction layer stuff */ +MDBX_INTERNAL_VAR unsigned sys_pagesize; +MDBX_MAYBE_UNUSED MDBX_INTERNAL_VAR unsigned sys_pagesize_ln2, + sys_allocation_granularity; + /* Get the size of a memory page for the system. * This is the basic size that the platform's memory manager uses, and is * fundamental to the use of memory-mapped files. */ MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline size_t -mdbx_syspagesize(void) { +osal_syspagesize(void) { + assert(sys_pagesize > 0 && (sys_pagesize & (sys_pagesize - 1)) == 0); + return sys_pagesize; +} + #if defined(_WIN32) || defined(_WIN64) - SYSTEM_INFO si; - GetSystemInfo(&si); - return si.dwPageSize; +typedef wchar_t pathchar_t; +#define MDBX_PRIsPATH "ls" #else - return sysconf(_SC_PAGE_SIZE); +typedef char pathchar_t; +#define MDBX_PRIsPATH "s" #endif -} -typedef struct mdbx_mmap_param { +typedef struct osal_mmap { union { - void *address; - uint8_t *dxb; + void *base; struct MDBX_lockinfo *lck; }; mdbx_filehandle_t fd; @@ -1134,36 +1230,174 @@ typedef struct mdbx_mmap_param { #if defined(_WIN32) || defined(_WIN64) HANDLE section; /* memory-mapped section handle */ #endif -} mdbx_mmap_t; +} osal_mmap_t; typedef union bin128 { - __anonymous_struct_extension__ struct { uint64_t x, y; }; - __anonymous_struct_extension__ struct { uint32_t a, b, c, d; }; + __anonymous_struct_extension__ struct { + uint64_t x, y; + }; + __anonymous_struct_extension__ struct { + uint32_t a, b, c, d; + }; } bin128_t; #if defined(_WIN32) || defined(_WIN64) -typedef union MDBX_srwlock { +typedef union osal_srwlock { __anonymous_struct_extension__ struct { long volatile readerCount; long volatile writerCount; }; RTL_SRWLOCK native; -} MDBX_srwlock; +} osal_srwlock_t; #endif /* Windows */ +#ifndef MDBX_HAVE_PWRITEV +#if defined(_WIN32) || defined(_WIN64) + +#define MDBX_HAVE_PWRITEV 0 + +#elif defined(__ANDROID_API__) + +#if __ANDROID_API__ < 24 +#define MDBX_HAVE_PWRITEV 0 +#else +#define MDBX_HAVE_PWRITEV 1 +#endif + +#elif defined(__APPLE__) || defined(__MACH__) || defined(_DARWIN_C_SOURCE) + +#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && defined(MAC_OS_VERSION_11_0) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 +/* FIXME: add checks for IOS versions, etc */ +#define MDBX_HAVE_PWRITEV 1 +#else +#define MDBX_HAVE_PWRITEV 0 +#endif + +#elif defined(_SC_IOV_MAX) || (defined(IOV_MAX) && IOV_MAX > 1) +#define MDBX_HAVE_PWRITEV 1 +#else +#define MDBX_HAVE_PWRITEV 0 +#endif +#endif /* MDBX_HAVE_PWRITEV */ + +typedef struct ior_item { +#if defined(_WIN32) || defined(_WIN64) + OVERLAPPED ov; +#define ior_svg_gap4terminator 1 +#define ior_sgv_element FILE_SEGMENT_ELEMENT +#else + size_t offset; +#if MDBX_HAVE_PWRITEV + size_t sgvcnt; +#define ior_svg_gap4terminator 0 +#define ior_sgv_element struct iovec +#endif /* MDBX_HAVE_PWRITEV */ +#endif /* !Windows */ + union { + MDBX_val single; +#if defined(ior_sgv_element) + ior_sgv_element sgv[1 + ior_svg_gap4terminator]; +#endif /* ior_sgv_element */ + }; +} ior_item_t; + +typedef struct osal_ioring { + unsigned slots_left; + unsigned allocated; +#if defined(_WIN32) || defined(_WIN64) +#define IOR_STATE_LOCKED 1 + HANDLE overlapped_fd; + unsigned pagesize; + unsigned last_sgvcnt; + size_t last_bytes; + uint8_t direct, state, pagesize_ln2; + unsigned event_stack; + HANDLE *event_pool; + volatile LONG async_waiting; + volatile LONG async_completed; + HANDLE async_done; + +#define ior_last_sgvcnt(ior, item) (ior)->last_sgvcnt +#define ior_last_bytes(ior, item) (ior)->last_bytes +#elif MDBX_HAVE_PWRITEV + unsigned last_bytes; +#define ior_last_sgvcnt(ior, item) (item)->sgvcnt +#define ior_last_bytes(ior, item) (ior)->last_bytes +#else +#define ior_last_sgvcnt(ior, item) (1) +#define ior_last_bytes(ior, item) (item)->single.iov_len +#endif /* !Windows */ + ior_item_t *last; + ior_item_t *pool; + char *boundary; +} osal_ioring_t; + #ifndef __cplusplus +/* Actually this is not ioring for now, but on the way. */ +MDBX_INTERNAL_FUNC int osal_ioring_create(osal_ioring_t * +#if defined(_WIN32) || defined(_WIN64) + , + bool enable_direct, + mdbx_filehandle_t overlapped_fd +#endif /* Windows */ +); +MDBX_INTERNAL_FUNC int osal_ioring_resize(osal_ioring_t *, size_t items); +MDBX_INTERNAL_FUNC void osal_ioring_destroy(osal_ioring_t *); +MDBX_INTERNAL_FUNC void osal_ioring_reset(osal_ioring_t *); +MDBX_INTERNAL_FUNC int osal_ioring_add(osal_ioring_t *ctx, const size_t offset, + void *data, const size_t bytes); +typedef struct osal_ioring_write_result { + int err; + unsigned wops; +} osal_ioring_write_result_t; +MDBX_INTERNAL_FUNC osal_ioring_write_result_t +osal_ioring_write(osal_ioring_t *ior, mdbx_filehandle_t fd); + +typedef struct iov_ctx iov_ctx_t; +MDBX_INTERNAL_FUNC void osal_ioring_walk( + osal_ioring_t *ior, iov_ctx_t *ctx, + void (*callback)(iov_ctx_t *ctx, size_t offset, void *data, size_t bytes)); + +MDBX_MAYBE_UNUSED static inline unsigned +osal_ioring_left(const osal_ioring_t *ior) { + return ior->slots_left; +} + +MDBX_MAYBE_UNUSED static inline unsigned +osal_ioring_used(const osal_ioring_t *ior) { + return ior->allocated - ior->slots_left; +} + +MDBX_MAYBE_UNUSED static inline int +osal_ioring_prepare(osal_ioring_t *ior, size_t items, size_t bytes) { + items = (items > 32) ? items : 32; +#if defined(_WIN32) || defined(_WIN64) + if (ior->direct) { + const size_t npages = bytes >> ior->pagesize_ln2; + items = (items > npages) ? items : npages; + } +#else + (void)bytes; +#endif + items = (items < 65536) ? items : 65536; + if (likely(ior->allocated >= items)) + return MDBX_SUCCESS; + return osal_ioring_resize(ior, items); +} + /*----------------------------------------------------------------------------*/ /* libc compatibility stuff */ #if (!defined(__GLIBC__) && __GLIBC_PREREQ(2, 1)) && \ (defined(_GNU_SOURCE) || defined(_BSD_SOURCE)) -#define mdbx_asprintf asprintf -#define mdbx_vasprintf vasprintf +#define osal_asprintf asprintf +#define osal_vasprintf vasprintf #else MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC - MDBX_PRINTF_ARGS(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...); -MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap); + MDBX_PRINTF_ARGS(2, 3) int osal_asprintf(char **strp, const char *fmt, ...); +MDBX_INTERNAL_FUNC int osal_vasprintf(char **strp, const char *fmt, va_list ap); #endif #if !defined(MADV_DODUMP) && defined(MADV_CORE) @@ -1174,26 +1408,69 @@ MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap); #define MADV_DONTDUMP MADV_NOCORE #endif /* MADV_NOCORE -> MADV_DONTDUMP */ -MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny); -MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny); +MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void osal_jitter(bool tiny); +MDBX_MAYBE_UNUSED static __inline void jitter4testing(bool tiny); /* max bytes to write in one call */ -#if defined(_WIN32) || defined(_WIN64) -#define MAX_WRITE UINT32_C(0x01000000) +#if defined(_WIN64) +#define MAX_WRITE UINT32_C(0x10000000) +#elif defined(_WIN32) +#define MAX_WRITE UINT32_C(0x04000000) +#else +#define MAX_WRITE UINT32_C(0x3f000000) + +#if defined(F_GETLK64) && defined(F_SETLK64) && defined(F_SETLKW64) && \ + !defined(__ANDROID_API__) +#define MDBX_F_SETLK F_SETLK64 +#define MDBX_F_SETLKW F_SETLKW64 +#define MDBX_F_GETLK F_GETLK64 +#if (__GLIBC_PREREQ(2, 28) && \ + (defined(__USE_LARGEFILE64) || defined(__LARGEFILE64_SOURCE) || \ + defined(_USE_LARGEFILE64) || defined(_LARGEFILE64_SOURCE))) || \ + defined(fcntl64) +#define MDBX_FCNTL fcntl64 +#else +#define MDBX_FCNTL fcntl +#endif +#define MDBX_STRUCT_FLOCK struct flock64 +#ifndef OFF_T_MAX +#define OFF_T_MAX UINT64_C(0x7fffFFFFfff00000) +#endif /* OFF_T_MAX */ #else -#define MAX_WRITE UINT32_C(0x3fff0000) +#define MDBX_F_SETLK F_SETLK +#define MDBX_F_SETLKW F_SETLKW +#define MDBX_F_GETLK F_GETLK +#define MDBX_FCNTL fcntl +#define MDBX_STRUCT_FLOCK struct flock +#endif /* MDBX_F_SETLK, MDBX_F_SETLKW, MDBX_F_GETLK */ + +#if defined(F_OFD_SETLK64) && defined(F_OFD_SETLKW64) && \ + defined(F_OFD_GETLK64) && !defined(__ANDROID_API__) +#define MDBX_F_OFD_SETLK F_OFD_SETLK64 +#define MDBX_F_OFD_SETLKW F_OFD_SETLKW64 +#define MDBX_F_OFD_GETLK F_OFD_GETLK64 +#else +#define MDBX_F_OFD_SETLK F_OFD_SETLK +#define MDBX_F_OFD_SETLKW F_OFD_SETLKW +#define MDBX_F_OFD_GETLK F_OFD_GETLK +#ifndef OFF_T_MAX +#define OFF_T_MAX \ + (((sizeof(off_t) > 4) ? INT64_MAX : INT32_MAX) & ~(size_t)0xFffff) +#endif /* OFF_T_MAX */ +#endif /* MDBX_F_OFD_SETLK64, MDBX_F_OFD_SETLKW64, MDBX_F_OFD_GETLK64 */ + #endif #if defined(__linux__) || defined(__gnu_linux__) -MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version; +MDBX_INTERNAL_VAR uint32_t linux_kernel_version; MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */; #endif /* Linux */ -#ifndef mdbx_strdup -LIBMDBX_API char *mdbx_strdup(const char *str); +#ifndef osal_strdup +LIBMDBX_API char *osal_strdup(const char *str); #endif -MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) { +MDBX_MAYBE_UNUSED static __inline int osal_get_errno(void) { #if defined(_WIN32) || defined(_WIN64) DWORD rc = GetLastError(); #else @@ -1202,84 +1479,101 @@ MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) { return rc; } -#ifndef mdbx_memalign_alloc -MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes, +#ifndef osal_memalign_alloc +MDBX_INTERNAL_FUNC int osal_memalign_alloc(size_t alignment, size_t bytes, void **result); #endif -#ifndef mdbx_memalign_free -MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr); +#ifndef osal_memalign_free +MDBX_INTERNAL_FUNC void osal_memalign_free(void *ptr); #endif -MDBX_INTERNAL_FUNC int mdbx_condpair_init(mdbx_condpair_t *condpair); -MDBX_INTERNAL_FUNC int mdbx_condpair_lock(mdbx_condpair_t *condpair); -MDBX_INTERNAL_FUNC int mdbx_condpair_unlock(mdbx_condpair_t *condpair); -MDBX_INTERNAL_FUNC int mdbx_condpair_signal(mdbx_condpair_t *condpair, +MDBX_INTERNAL_FUNC int osal_condpair_init(osal_condpair_t *condpair); +MDBX_INTERNAL_FUNC int osal_condpair_lock(osal_condpair_t *condpair); +MDBX_INTERNAL_FUNC int osal_condpair_unlock(osal_condpair_t *condpair); +MDBX_INTERNAL_FUNC int osal_condpair_signal(osal_condpair_t *condpair, bool part); -MDBX_INTERNAL_FUNC int mdbx_condpair_wait(mdbx_condpair_t *condpair, bool part); -MDBX_INTERNAL_FUNC int mdbx_condpair_destroy(mdbx_condpair_t *condpair); - -MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex); -MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex); -MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex); -MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex); - -MDBX_INTERNAL_FUNC int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov, - int iovcnt, uint64_t offset, - size_t expected_written); -MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t count, +MDBX_INTERNAL_FUNC int osal_condpair_wait(osal_condpair_t *condpair, bool part); +MDBX_INTERNAL_FUNC int osal_condpair_destroy(osal_condpair_t *condpair); + +MDBX_INTERNAL_FUNC int osal_fastmutex_init(osal_fastmutex_t *fastmutex); +MDBX_INTERNAL_FUNC int osal_fastmutex_acquire(osal_fastmutex_t *fastmutex); +MDBX_INTERNAL_FUNC int osal_fastmutex_release(osal_fastmutex_t *fastmutex); +MDBX_INTERNAL_FUNC int osal_fastmutex_destroy(osal_fastmutex_t *fastmutex); + +MDBX_INTERNAL_FUNC int osal_pwritev(mdbx_filehandle_t fd, struct iovec *iov, + size_t sgvcnt, uint64_t offset); +MDBX_INTERNAL_FUNC int osal_pread(mdbx_filehandle_t fd, void *buf, size_t count, uint64_t offset); -MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf, +MDBX_INTERNAL_FUNC int osal_pwrite(mdbx_filehandle_t fd, const void *buf, size_t count, uint64_t offset); -MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf, +MDBX_INTERNAL_FUNC int osal_write(mdbx_filehandle_t fd, const void *buf, size_t count); MDBX_INTERNAL_FUNC int -mdbx_thread_create(mdbx_thread_t *thread, +osal_thread_create(osal_thread_t *thread, THREAD_RESULT(THREAD_CALL *start_routine)(void *), void *arg); -MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread); +MDBX_INTERNAL_FUNC int osal_thread_join(osal_thread_t thread); -enum mdbx_syncmode_bits { +enum osal_syncmode_bits { MDBX_SYNC_NONE = 0, - MDBX_SYNC_DATA = 1, - MDBX_SYNC_SIZE = 2, - MDBX_SYNC_IODQ = 4 + MDBX_SYNC_KICK = 1, + MDBX_SYNC_DATA = 2, + MDBX_SYNC_SIZE = 4, + MDBX_SYNC_IODQ = 8 }; -MDBX_INTERNAL_FUNC int mdbx_fsync(mdbx_filehandle_t fd, - const enum mdbx_syncmode_bits mode_bits); -MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length); -MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos); -MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length); - -enum mdbx_openfile_purpose { - MDBX_OPEN_DXB_READ = 0, - MDBX_OPEN_DXB_LAZY = 1, - MDBX_OPEN_DXB_DSYNC = 2, - MDBX_OPEN_LCK = 3, - MDBX_OPEN_COPY = 4, - MDBX_OPEN_DELETE = 5 +MDBX_INTERNAL_FUNC int osal_fsync(mdbx_filehandle_t fd, + const enum osal_syncmode_bits mode_bits); +MDBX_INTERNAL_FUNC int osal_ftruncate(mdbx_filehandle_t fd, uint64_t length); +MDBX_INTERNAL_FUNC int osal_fseek(mdbx_filehandle_t fd, uint64_t pos); +MDBX_INTERNAL_FUNC int osal_filesize(mdbx_filehandle_t fd, uint64_t *length); + +enum osal_openfile_purpose { + MDBX_OPEN_DXB_READ, + MDBX_OPEN_DXB_LAZY, + MDBX_OPEN_DXB_DSYNC, +#if defined(_WIN32) || defined(_WIN64) + MDBX_OPEN_DXB_OVERLAPPED, + MDBX_OPEN_DXB_OVERLAPPED_DIRECT, +#endif /* Windows */ + MDBX_OPEN_LCK, + MDBX_OPEN_COPY, + MDBX_OPEN_DELETE }; -MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose, - const MDBX_env *env, const char *pathname, +MDBX_MAYBE_UNUSED static __inline bool osal_isdirsep(pathchar_t c) { + return +#if defined(_WIN32) || defined(_WIN64) + c == '\\' || +#endif + c == '/'; +} + +MDBX_INTERNAL_FUNC bool osal_pathequal(const pathchar_t *l, const pathchar_t *r, + size_t len); +MDBX_INTERNAL_FUNC pathchar_t *osal_fileext(const pathchar_t *pathname, + size_t len); +MDBX_INTERNAL_FUNC int osal_fileexists(const pathchar_t *pathname); +MDBX_INTERNAL_FUNC int osal_openfile(const enum osal_openfile_purpose purpose, + const MDBX_env *env, + const pathchar_t *pathname, mdbx_filehandle_t *fd, mdbx_mode_t unix_mode_bits); -MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd); -MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname); -MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname); -MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd); -MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait); +MDBX_INTERNAL_FUNC int osal_closefile(mdbx_filehandle_t fd); +MDBX_INTERNAL_FUNC int osal_removefile(const pathchar_t *pathname); +MDBX_INTERNAL_FUNC int osal_removedirectory(const pathchar_t *pathname); +MDBX_INTERNAL_FUNC int osal_is_pipe(mdbx_filehandle_t fd); +MDBX_INTERNAL_FUNC int osal_lockfile(mdbx_filehandle_t fd, bool wait); #define MMAP_OPTION_TRUNCATE 1 #define MMAP_OPTION_SEMAPHORE 2 -MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map, - const size_t must, const size_t limit, - const unsigned options); -MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map); +MDBX_INTERNAL_FUNC int osal_mmap(const int flags, osal_mmap_t *map, size_t size, + const size_t limit, const unsigned options); +MDBX_INTERNAL_FUNC int osal_munmap(osal_mmap_t *map); #define MDBX_MRESIZE_MAY_MOVE 0x00000100 #define MDBX_MRESIZE_MAY_UNMAP 0x00000200 -MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map, +MDBX_INTERNAL_FUNC int osal_mresize(const int flags, osal_mmap_t *map, size_t size, size_t limit); #if defined(_WIN32) || defined(_WIN64) typedef struct { @@ -1287,17 +1581,19 @@ typedef struct { HANDLE handles[31]; } mdbx_handle_array_t; MDBX_INTERNAL_FUNC int -mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array); +osal_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array); MDBX_INTERNAL_FUNC int -mdbx_resume_threads_after_remap(mdbx_handle_array_t *array); +osal_resume_threads_after_remap(mdbx_handle_array_t *array); #endif /* Windows */ -MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset, +MDBX_INTERNAL_FUNC int osal_msync(const osal_mmap_t *map, size_t offset, size_t length, - enum mdbx_syncmode_bits mode_bits); -MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle, - const char *pathname, int err); + enum osal_syncmode_bits mode_bits); +MDBX_INTERNAL_FUNC int osal_check_fs_rdonly(mdbx_filehandle_t handle, + const pathchar_t *pathname, + int err); +MDBX_INTERNAL_FUNC int osal_check_fs_incore(mdbx_filehandle_t handle); -MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) { +MDBX_MAYBE_UNUSED static __inline uint32_t osal_getpid(void) { STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t)); #if defined(_WIN32) || defined(_WIN64) return GetCurrentProcessId(); @@ -1307,7 +1603,7 @@ MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) { #endif } -MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) { +MDBX_MAYBE_UNUSED static __inline uintptr_t osal_thread_self(void) { mdbx_tid_t thunk; STATIC_ASSERT(sizeof(uintptr_t) >= sizeof(thunk)); #if defined(_WIN32) || defined(_WIN64) @@ -1320,24 +1616,30 @@ MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) { #if !defined(_WIN32) && !defined(_WIN64) #if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC) -MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void); +MDBX_INTERNAL_FUNC int osal_check_tid4bionic(void); #else -static __inline int mdbx_check_tid4bionic(void) { return 0; } +static __inline int osal_check_tid4bionic(void) { return 0; } #endif /* __ANDROID_API__ || ANDROID) || BIONIC */ MDBX_MAYBE_UNUSED static __inline int -mdbx_pthread_mutex_lock(pthread_mutex_t *mutex) { - int err = mdbx_check_tid4bionic(); +osal_pthread_mutex_lock(pthread_mutex_t *mutex) { + int err = osal_check_tid4bionic(); return unlikely(err) ? err : pthread_mutex_lock(mutex); } #endif /* !Windows */ -MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void); -MDBX_INTERNAL_FUNC uint64_t -mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16); -MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime); +MDBX_INTERNAL_FUNC uint64_t osal_monotime(void); +MDBX_INTERNAL_FUNC uint64_t osal_cputime(size_t *optional_page_faults); +MDBX_INTERNAL_FUNC uint64_t osal_16dot16_to_monotime(uint32_t seconds_16dot16); +MDBX_INTERNAL_FUNC uint32_t osal_monotime_to_16dot16(uint64_t monotime); -MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void); +MDBX_MAYBE_UNUSED static inline uint32_t +osal_monotime_to_16dot16_noUnderflow(uint64_t monotime) { + uint32_t seconds_16dot16 = osal_monotime_to_16dot16(monotime); + return seconds_16dot16 ? seconds_16dot16 : /* fix underflow */ (monotime > 0); +} + +MDBX_INTERNAL_FUNC bin128_t osal_bootid(void); /*----------------------------------------------------------------------------*/ /* lck stuff */ @@ -1353,7 +1655,7 @@ MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void); /// MUST NOT initialize shared synchronization objects in memory-mapped /// LCK-file that are already in use. /// \return Error code or zero on success. -MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env, +MDBX_INTERNAL_FUNC int osal_lck_init(MDBX_env *env, MDBX_env *inprocess_neighbor, int global_uniqueness_flag); @@ -1374,7 +1676,7 @@ MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env, /// of other instances of MDBX_env within the current process, e.g. /// restore POSIX-fcntl locks after the closing of file descriptors. /// \return Error code (MDBX_PANIC) or zero on success. -MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env, +MDBX_INTERNAL_FUNC int osal_lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor); /// \brief Connects to shared interprocess locking objects and tries to acquire @@ -1382,17 +1684,17 @@ MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env, /// Depending on implementation or/and platform (Windows) this function may /// acquire the non-OS super-level lock (e.g. for shared synchronization /// objects initialization), which will be downgraded to OS-exclusive or -/// shared via explicit calling of mdbx_lck_downgrade(). +/// shared via explicit calling of osal_lck_downgrade(). /// \return /// MDBX_RESULT_TRUE (-1) - if an exclusive lock was acquired and thus /// the current process is the first and only after the last use of DB. /// MDBX_RESULT_FALSE (0) - if a shared lock was acquired and thus /// DB has already been opened and now is used by other processes. /// Otherwise (not 0 and not -1) - error code. -MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env); +MDBX_INTERNAL_FUNC int osal_lck_seize(MDBX_env *env); /// \brief Downgrades the level of initially acquired lock to -/// operational level specified by argument. The reson for such downgrade: +/// operational level specified by argument. The reason for such downgrade: /// - unblocking of other processes that are waiting for access, i.e. /// if (env->me_flags & MDBX_EXCLUSIVE) != 0, then other processes /// should be made aware that access is unavailable rather than @@ -1402,14 +1704,14 @@ MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env); /// (env->me_flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive /// operational lock. /// \return Error code or zero on success -MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env); +MDBX_INTERNAL_FUNC int osal_lck_downgrade(MDBX_env *env); /// \brief Locks LCK-file or/and table of readers for (de)registering. /// \return Error code or zero on success -MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env); +MDBX_INTERNAL_FUNC int osal_rdt_lock(MDBX_env *env); /// \brief Unlocks LCK-file or/and table of readers after (de)registering. -MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env); +MDBX_INTERNAL_FUNC void osal_rdt_unlock(MDBX_env *env); /// \brief Acquires lock for DB change (on writing transaction start) /// Reading transactions will not be blocked. @@ -1424,15 +1726,15 @@ LIBMDBX_API void mdbx_txn_unlock(MDBX_env *env); /// \brief Sets alive-flag of reader presence (indicative lock) for PID of /// the current process. The function does no more than needed for -/// the correct working of mdbx_rpid_check() in other processes. +/// the correct working of osal_rpid_check() in other processes. /// \return Error code or zero on success -MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env); +MDBX_INTERNAL_FUNC int osal_rpid_set(MDBX_env *env); /// \brief Resets alive-flag of reader presence (indicative lock) /// for PID of the current process. The function does no more than needed -/// for the correct working of mdbx_rpid_check() in other processes. +/// for the correct working of osal_rpid_check() in other processes. /// \return Error code or zero on success -MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env); +MDBX_INTERNAL_FUNC int osal_rpid_clear(MDBX_env *env); /// \brief Checks for reading process status with the given pid with help of /// alive-flag of presence (indicative lock) or using another way. @@ -1442,14 +1744,16 @@ MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env); /// MDBX_RESULT_FALSE (0) - if the reader process with the given PID is absent /// or not working with DB (indicative lock is not present). /// Otherwise (not 0 and not -1) - error code. -MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid); +MDBX_INTERNAL_FUNC int osal_rpid_check(MDBX_env *env, uint32_t pid); #if defined(_WIN32) || defined(_WIN64) -typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *); -MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init, - mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared, - mdbx_srwlock_AcquireExclusive, mdbx_srwlock_ReleaseExclusive; +MDBX_INTERNAL_FUNC int osal_mb2w(const char *const src, wchar_t **const pdst); + +typedef void(WINAPI *osal_srwlock_t_function)(osal_srwlock_t *); +MDBX_INTERNAL_VAR osal_srwlock_t_function osal_srwlock_Init, + osal_srwlock_AcquireShared, osal_srwlock_ReleaseShared, + osal_srwlock_AcquireExclusive, osal_srwlock_ReleaseExclusive; #if _WIN32_WINNT < 0x0600 /* prior to Windows Vista */ typedef enum _FILE_INFO_BY_HANDLE_CLASS { @@ -1565,12 +1869,57 @@ MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA; NTSYSAPI ULONG RtlRandomEx(PULONG Seed); +typedef BOOL(WINAPI *MDBX_SetFileIoOverlappedRange)(HANDLE FileHandle, + PUCHAR OverlappedRangeStart, + ULONG Length); +MDBX_INTERNAL_VAR MDBX_SetFileIoOverlappedRange mdbx_SetFileIoOverlappedRange; + #endif /* Windows */ #endif /* !__cplusplus */ /*----------------------------------------------------------------------------*/ +MDBX_MAYBE_UNUSED MDBX_NOTHROW_PURE_FUNCTION static __always_inline uint64_t +osal_bswap64(uint64_t v) { +#if __GNUC_PREREQ(4, 4) || __CLANG_PREREQ(4, 0) || \ + __has_builtin(__builtin_bswap64) + return __builtin_bswap64(v); +#elif defined(_MSC_VER) && !defined(__clang__) + return _byteswap_uint64(v); +#elif defined(__bswap_64) + return __bswap_64(v); +#elif defined(bswap_64) + return bswap_64(v); +#else + return v << 56 | v >> 56 | ((v << 40) & UINT64_C(0x00ff000000000000)) | + ((v << 24) & UINT64_C(0x0000ff0000000000)) | + ((v << 8) & UINT64_C(0x000000ff00000000)) | + ((v >> 8) & UINT64_C(0x00000000ff000000)) | + ((v >> 24) & UINT64_C(0x0000000000ff0000)) | + ((v >> 40) & UINT64_C(0x000000000000ff00)); +#endif +} + +MDBX_MAYBE_UNUSED MDBX_NOTHROW_PURE_FUNCTION static __always_inline uint32_t +osal_bswap32(uint32_t v) { +#if __GNUC_PREREQ(4, 4) || __CLANG_PREREQ(4, 0) || \ + __has_builtin(__builtin_bswap32) + return __builtin_bswap32(v); +#elif defined(_MSC_VER) && !defined(__clang__) + return _byteswap_ulong(v); +#elif defined(__bswap_32) + return __bswap_32(v); +#elif defined(bswap_32) + return bswap_32(v); +#else + return v << 24 | v >> 24 | ((v << 8) & UINT32_C(0x00ff0000)) | + ((v >> 8) & UINT32_C(0x0000ff00)); +#endif +} + +/*----------------------------------------------------------------------------*/ + #if defined(_MSC_VER) && _MSC_VER >= 1900 /* LY: MSVC 2015/2017/2019 has buggy/inconsistent PRIuPTR/PRIxPTR macros * for internal format-args checker. */ @@ -1646,6 +1995,8 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #define MDBX_ENV_CHECKPID 1 #endif #define MDBX_ENV_CHECKPID_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_ENV_CHECKPID) +#elif !(MDBX_ENV_CHECKPID == 0 || MDBX_ENV_CHECKPID == 1) +#error MDBX_ENV_CHECKPID must be defined as 0 or 1 #else #define MDBX_ENV_CHECKPID_CONFIG MDBX_STRINGIFY(MDBX_ENV_CHECKPID) #endif /* MDBX_ENV_CHECKPID */ @@ -1655,6 +2006,8 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #ifndef MDBX_TXN_CHECKOWNER #define MDBX_TXN_CHECKOWNER 1 #define MDBX_TXN_CHECKOWNER_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER) +#elif !(MDBX_TXN_CHECKOWNER == 0 || MDBX_TXN_CHECKOWNER == 1) +#error MDBX_TXN_CHECKOWNER must be defined as 0 or 1 #else #define MDBX_TXN_CHECKOWNER_CONFIG MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER) #endif /* MDBX_TXN_CHECKOWNER */ @@ -1668,6 +2021,8 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #define MDBX_TRUST_RTC 1 #endif #define MDBX_TRUST_RTC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TRUST_RTC) +#elif !(MDBX_TRUST_RTC == 0 || MDBX_TRUST_RTC == 1) +#error MDBX_TRUST_RTC must be defined as 0 or 1 #else #define MDBX_TRUST_RTC_CONFIG MDBX_STRINGIFY(MDBX_TRUST_RTC) #endif /* MDBX_TRUST_RTC */ @@ -1679,6 +2034,13 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #error MDBX_ENABLE_REFUND must be defined as 0 or 1 #endif /* MDBX_ENABLE_REFUND */ +/** Controls profiling of GC search and updates. */ +#ifndef MDBX_ENABLE_PROFGC +#define MDBX_ENABLE_PROFGC 0 +#elif !(MDBX_ENABLE_PROFGC == 0 || MDBX_ENABLE_PROFGC == 1) +#error MDBX_ENABLE_PROFGC must be defined as 0 or 1 +#endif /* MDBX_ENABLE_PROFGC */ + /** Controls gathering statistics for page operations. */ #ifndef MDBX_ENABLE_PGOP_STAT #define MDBX_ENABLE_PGOP_STAT 1 @@ -1686,6 +2048,18 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #error MDBX_ENABLE_PGOP_STAT must be defined as 0 or 1 #endif /* MDBX_ENABLE_PGOP_STAT */ +/** Controls using Unix' mincore() to determine whether DB-pages + * are resident in memory. */ +#ifndef MDBX_ENABLE_MINCORE +#if defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64)) +#define MDBX_ENABLE_MINCORE 1 +#else +#define MDBX_ENABLE_MINCORE 0 +#endif +#elif !(MDBX_ENABLE_MINCORE == 0 || MDBX_ENABLE_MINCORE == 1) +#error MDBX_ENABLE_MINCORE must be defined as 0 or 1 +#endif /* MDBX_ENABLE_MINCORE */ + /** Enables chunking long list of retired pages during huge transactions commit * to avoid use sequences of pages. */ #ifndef MDBX_ENABLE_BIGFOOT @@ -1698,13 +2072,7 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #error MDBX_ENABLE_BIGFOOT must be defined as 0 or 1 #endif /* MDBX_ENABLE_BIGFOOT */ -#ifndef MDBX_CACHE_METAPTR -#define MDBX_CACHE_METAPTR 0 -#elif !(MDBX_CACHE_METAPTR == 0 || MDBX_CACHE_METAPTR == 1) -#error MDBX_CACHE_METAPTR must be defined as 0 or 1 -#endif /* MDBX_CACHE_METAPTR */ - -/** Controls use of POSIX madvise() hints and friends. */ +/** Controls using of POSIX' madvise() and/or similar hints. */ #ifndef MDBX_ENABLE_MADVISE #define MDBX_ENABLE_MADVISE 1 #elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1) @@ -1733,27 +2101,26 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #error MDBX_DPL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1 #endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */ -/** Basically, this build-option is for TODO. Guess it should be replaced - * with MDBX_ENABLE_WRITEMAP_SPILLING with the three variants: - * 0/OFF = Don't track dirty pages at all and don't spilling ones. - * This should be by-default on Linux and may-be other systems - * (not sure: Darwin/OSX, FreeBSD, Windows 10) where kernel provides - * properly LRU tracking and async writing on-demand. - * 1/ON = Lite tracking of dirty pages but with LRU labels and explicit - * spilling with msync(MS_ASYNC). */ -#ifndef MDBX_FAKE_SPILL_WRITEMAP -#if defined(__linux__) || defined(__gnu_linux__) -#define MDBX_FAKE_SPILL_WRITEMAP 1 /* msync(MS_ASYNC) is no-op on Linux */ +/** Controls dirty pages tracking, spilling and persisting in MDBX_WRITEMAP + * mode. 0/OFF = Don't track dirty pages at all, don't spill ones, and use + * msync() to persist data. This is by-default on Linux and other systems where + * kernel provides properly LRU tracking and effective flushing on-demand. 1/ON + * = Tracking of dirty pages but with LRU labels for spilling and explicit + * persist ones by write(). This may be reasonable for systems which low + * performance of msync() and/or LRU tracking. */ +#ifndef MDBX_AVOID_MSYNC +#if defined(_WIN32) || defined(_WIN64) +#define MDBX_AVOID_MSYNC 1 #else -#define MDBX_FAKE_SPILL_WRITEMAP 0 +#define MDBX_AVOID_MSYNC 0 #endif -#elif !(MDBX_FAKE_SPILL_WRITEMAP == 0 || MDBX_FAKE_SPILL_WRITEMAP == 1) -#error MDBX_FAKE_SPILL_WRITEMAP must be defined as 0 or 1 -#endif /* MDBX_FAKE_SPILL_WRITEMAP */ +#elif !(MDBX_AVOID_MSYNC == 0 || MDBX_AVOID_MSYNC == 1) +#error MDBX_AVOID_MSYNC must be defined as 0 or 1 +#endif /* MDBX_AVOID_MSYNC */ /** Controls sort order of internal page number lists. * This mostly experimental/advanced option with not for regular MDBX users. - * \warning The database format depend on this option and libmdbx builded with + * \warning The database format depend on this option and libmdbx built with * different option value are incompatible. */ #ifndef MDBX_PNL_ASCENDING #define MDBX_PNL_ASCENDING 0 @@ -1806,6 +2173,31 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #ifndef MDBX_HAVE_C11ATOMICS #endif /* MDBX_HAVE_C11ATOMICS */ +/** If defined then enables use the GCC's `__builtin_cpu_supports()` + * for runtime dispatching depending on the CPU's capabilities. + * \note Defining `MDBX_HAVE_BUILTIN_CPU_SUPPORTS` to `0` should avoided unless + * build for particular single-target platform, since on AMD64/x86 this disables + * dynamic choice (at runtime) of SSE2 / AVX2 / AVX512 instructions + * with fallback to non-accelerated baseline code. */ +#ifndef MDBX_HAVE_BUILTIN_CPU_SUPPORTS +#if defined(__APPLE__) || defined(BIONIC) +/* Never use any modern features on Apple's or Google's OSes + * since a lot of troubles with compatibility and/or performance */ +#define MDBX_HAVE_BUILTIN_CPU_SUPPORTS 0 +#elif defined(__e2k__) +#define MDBX_HAVE_BUILTIN_CPU_SUPPORTS 0 +#elif __has_builtin(__builtin_cpu_supports) || \ + defined(__BUILTIN_CPU_SUPPORTS__) || \ + (defined(__ia32__) && __GNUC_PREREQ(4, 8) && __GLIBC_PREREQ(2, 23)) +#define MDBX_HAVE_BUILTIN_CPU_SUPPORTS 1 +#else +#define MDBX_HAVE_BUILTIN_CPU_SUPPORTS 0 +#endif +#elif !(MDBX_HAVE_BUILTIN_CPU_SUPPORTS == 0 || \ + MDBX_HAVE_BUILTIN_CPU_SUPPORTS == 1) +#error MDBX_HAVE_BUILTIN_CPU_SUPPORTS must be defined as 0 or 1 +#endif /* MDBX_HAVE_BUILTIN_CPU_SUPPORTS */ + //------------------------------------------------------------------------------ /** Win32 File Locking API for \ref MDBX_LOCKING */ @@ -1861,7 +2253,10 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; /** Advanced: Using POSIX OFD-locks (autodetection by default). */ #ifndef MDBX_USE_OFDLOCKS -#if defined(F_OFD_SETLK) && defined(F_OFD_SETLKW) && defined(F_OFD_GETLK) && \ +#if ((defined(F_OFD_SETLK) && defined(F_OFD_SETLKW) && \ + defined(F_OFD_GETLK)) || \ + (defined(F_OFD_SETLK64) && defined(F_OFD_SETLKW64) && \ + defined(F_OFD_GETLK64))) && \ !defined(MDBX_SAFE4QEMU) && \ !defined(__sun) /* OFD-lock are broken on Solaris */ #define MDBX_USE_OFDLOCKS 1 @@ -1869,6 +2264,8 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #define MDBX_USE_OFDLOCKS 0 #endif #define MDBX_USE_OFDLOCKS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_USE_OFDLOCKS) +#elif !(MDBX_USE_OFDLOCKS == 0 || MDBX_USE_OFDLOCKS == 1) +#error MDBX_USE_OFDLOCKS must be defined as 0 or 1 #else #define MDBX_USE_OFDLOCKS_CONFIG MDBX_STRINGIFY(MDBX_USE_OFDLOCKS) #endif /* MDBX_USE_OFDLOCKS */ @@ -1882,6 +2279,8 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #else #define MDBX_USE_SENDFILE 0 #endif +#elif !(MDBX_USE_SENDFILE == 0 || MDBX_USE_SENDFILE == 1) +#error MDBX_USE_SENDFILE must be defined as 0 or 1 #endif /* MDBX_USE_SENDFILE */ /** Advanced: Using copy_file_range() syscall (autodetection by default). */ @@ -1891,6 +2290,8 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #else #define MDBX_USE_COPYFILERANGE 0 #endif +#elif !(MDBX_USE_COPYFILERANGE == 0 || MDBX_USE_COPYFILERANGE == 1) +#error MDBX_USE_COPYFILERANGE must be defined as 0 or 1 #endif /* MDBX_USE_COPYFILERANGE */ /** Advanced: Using sync_file_range() syscall (autodetection by default). */ @@ -1902,6 +2303,8 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #else #define MDBX_USE_SYNCFILERANGE 0 #endif +#elif !(MDBX_USE_SYNCFILERANGE == 0 || MDBX_USE_SYNCFILERANGE == 1) +#error MDBX_USE_SYNCFILERANGE must be defined as 0 or 1 #endif /* MDBX_USE_SYNCFILERANGE */ //------------------------------------------------------------------------------ @@ -1913,6 +2316,9 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #else #define MDBX_CPU_WRITEBACK_INCOHERENT 1 #endif +#elif !(MDBX_CPU_WRITEBACK_INCOHERENT == 0 || \ + MDBX_CPU_WRITEBACK_INCOHERENT == 1) +#error MDBX_CPU_WRITEBACK_INCOHERENT must be defined as 0 or 1 #endif /* MDBX_CPU_WRITEBACK_INCOHERENT */ #ifndef MDBX_MMAP_INCOHERENT_FILE_WRITE @@ -1921,6 +2327,9 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #else #define MDBX_MMAP_INCOHERENT_FILE_WRITE 0 #endif +#elif !(MDBX_MMAP_INCOHERENT_FILE_WRITE == 0 || \ + MDBX_MMAP_INCOHERENT_FILE_WRITE == 1) +#error MDBX_MMAP_INCOHERENT_FILE_WRITE must be defined as 0 or 1 #endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */ #ifndef MDBX_MMAP_INCOHERENT_CPU_CACHE @@ -1933,8 +2342,21 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; /* LY: assume no relevant mmap/dcache issues. */ #define MDBX_MMAP_INCOHERENT_CPU_CACHE 0 #endif +#elif !(MDBX_MMAP_INCOHERENT_CPU_CACHE == 0 || \ + MDBX_MMAP_INCOHERENT_CPU_CACHE == 1) +#error MDBX_MMAP_INCOHERENT_CPU_CACHE must be defined as 0 or 1 #endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */ +#ifndef MDBX_MMAP_USE_MS_ASYNC +#if MDBX_MMAP_INCOHERENT_FILE_WRITE || MDBX_MMAP_INCOHERENT_CPU_CACHE +#define MDBX_MMAP_USE_MS_ASYNC 1 +#else +#define MDBX_MMAP_USE_MS_ASYNC 0 +#endif +#elif !(MDBX_MMAP_USE_MS_ASYNC == 0 || MDBX_MMAP_USE_MS_ASYNC == 1) +#error MDBX_MMAP_USE_MS_ASYNC must be defined as 0 or 1 +#endif /* MDBX_MMAP_USE_MS_ASYNC */ + #ifndef MDBX_64BIT_ATOMIC #if MDBX_WORDBITS >= 64 || defined(DOXYGEN) #define MDBX_64BIT_ATOMIC 1 @@ -1942,31 +2364,35 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #define MDBX_64BIT_ATOMIC 0 #endif #define MDBX_64BIT_ATOMIC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_ATOMIC) +#elif !(MDBX_64BIT_ATOMIC == 0 || MDBX_64BIT_ATOMIC == 1) +#error MDBX_64BIT_ATOMIC must be defined as 0 or 1 #else #define MDBX_64BIT_ATOMIC_CONFIG MDBX_STRINGIFY(MDBX_64BIT_ATOMIC) #endif /* MDBX_64BIT_ATOMIC */ #ifndef MDBX_64BIT_CAS -#if defined(ATOMIC_LLONG_LOCK_FREE) -#if ATOMIC_LLONG_LOCK_FREE > 1 +#if defined(__GCC_ATOMIC_LLONG_LOCK_FREE) +#if __GCC_ATOMIC_LLONG_LOCK_FREE > 1 #define MDBX_64BIT_CAS 1 #else #define MDBX_64BIT_CAS 0 #endif -#elif defined(__GCC_ATOMIC_LLONG_LOCK_FREE) -#if __GCC_ATOMIC_LLONG_LOCK_FREE > 1 +#elif defined(__CLANG_ATOMIC_LLONG_LOCK_FREE) +#if __CLANG_ATOMIC_LLONG_LOCK_FREE > 1 #define MDBX_64BIT_CAS 1 #else #define MDBX_64BIT_CAS 0 #endif -#elif defined(__CLANG_ATOMIC_LLONG_LOCK_FREE) -#if __CLANG_ATOMIC_LLONG_LOCK_FREE > 1 +#elif defined(ATOMIC_LLONG_LOCK_FREE) +#if ATOMIC_LLONG_LOCK_FREE > 1 #define MDBX_64BIT_CAS 1 #else #define MDBX_64BIT_CAS 0 #endif #elif defined(_MSC_VER) || defined(__APPLE__) || defined(DOXYGEN) #define MDBX_64BIT_CAS 1 +#elif !(MDBX_64BIT_CAS == 0 || MDBX_64BIT_CAS == 1) +#error MDBX_64BIT_CAS must be defined as 0 or 1 #else #define MDBX_64BIT_CAS MDBX_64BIT_ATOMIC #endif @@ -1976,14 +2402,11 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #endif /* MDBX_64BIT_CAS */ #ifndef MDBX_UNALIGNED_OK -#if defined(__ALIGNED__) || defined(__SANITIZE_UNDEFINED__) +#if defined(__ALIGNED__) || defined(__SANITIZE_UNDEFINED__) || \ + defined(ENABLE_UBSAN) #define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */ #elif defined(__ARM_FEATURE_UNALIGNED) #define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */ -#elif __CLANG_PREREQ(5, 0) || __GNUC_PREREQ(5, 0) -/* expecting an optimization will well done, also this - * hushes false-positives from UBSAN (undefined behaviour sanitizer) */ -#define MDBX_UNALIGNED_OK 0 #elif defined(__e2k__) || defined(__elbrus__) #if __iset__ > 4 #define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */ @@ -1992,6 +2415,10 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #endif #elif defined(__ia32__) #define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */ +#elif __CLANG_PREREQ(5, 0) || __GNUC_PREREQ(5, 0) +/* expecting an optimization will well done, also this + * hushes false-positives from UBSAN (undefined behaviour sanitizer) */ +#define MDBX_UNALIGNED_OK 0 #else #define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */ #endif @@ -2055,13 +2482,149 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; #undef NDEBUG #endif +#ifndef __cplusplus +/*----------------------------------------------------------------------------*/ +/* Debug and Logging stuff */ + +#define MDBX_RUNTIME_FLAGS_INIT \ + ((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT + +extern uint8_t runtime_flags; +extern uint8_t loglevel; +extern MDBX_debug_func *debug_logger; + +MDBX_MAYBE_UNUSED static __inline void jitter4testing(bool tiny) { +#if MDBX_DEBUG + if (MDBX_DBG_JITTER & runtime_flags) + osal_jitter(tiny); +#else + (void)tiny; +#endif +} + +MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5) + debug_log(int level, const char *function, int line, const char *fmt, ...) + MDBX_PRINTF_ARGS(4, 5); +MDBX_INTERNAL_FUNC void debug_log_va(int level, const char *function, int line, + const char *fmt, va_list args); + +#if MDBX_DEBUG +#define LOG_ENABLED(msg) unlikely(msg <= loglevel) +#define AUDIT_ENABLED() unlikely((runtime_flags & MDBX_DBG_AUDIT)) +#else /* MDBX_DEBUG */ +#define LOG_ENABLED(msg) (msg < MDBX_LOG_VERBOSE && msg <= loglevel) +#define AUDIT_ENABLED() (0) +#endif /* MDBX_DEBUG */ + +#if MDBX_FORCE_ASSERTIONS +#define ASSERT_ENABLED() (1) +#elif MDBX_DEBUG +#define ASSERT_ENABLED() likely((runtime_flags & MDBX_DBG_ASSERT)) +#else +#define ASSERT_ENABLED() (0) +#endif /* assertions */ + +#define DEBUG_EXTRA(fmt, ...) \ + do { \ + if (LOG_ENABLED(MDBX_LOG_EXTRA)) \ + debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__); \ + } while (0) + +#define DEBUG_EXTRA_PRINT(fmt, ...) \ + do { \ + if (LOG_ENABLED(MDBX_LOG_EXTRA)) \ + debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__); \ + } while (0) + +#define TRACE(fmt, ...) \ + do { \ + if (LOG_ENABLED(MDBX_LOG_TRACE)) \ + debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n", __VA_ARGS__); \ + } while (0) + +#define DEBUG(fmt, ...) \ + do { \ + if (LOG_ENABLED(MDBX_LOG_DEBUG)) \ + debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n", __VA_ARGS__); \ + } while (0) + +#define VERBOSE(fmt, ...) \ + do { \ + if (LOG_ENABLED(MDBX_LOG_VERBOSE)) \ + debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n", __VA_ARGS__); \ + } while (0) + +#define NOTICE(fmt, ...) \ + do { \ + if (LOG_ENABLED(MDBX_LOG_NOTICE)) \ + debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n", __VA_ARGS__); \ + } while (0) + +#define WARNING(fmt, ...) \ + do { \ + if (LOG_ENABLED(MDBX_LOG_WARN)) \ + debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n", __VA_ARGS__); \ + } while (0) + +#undef ERROR /* wingdi.h \ + Yeah, morons from M$ put such definition to the public header. */ + +#define ERROR(fmt, ...) \ + do { \ + if (LOG_ENABLED(MDBX_LOG_ERROR)) \ + debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n", __VA_ARGS__); \ + } while (0) + +#define FATAL(fmt, ...) \ + debug_log(MDBX_LOG_FATAL, __func__, __LINE__, fmt "\n", __VA_ARGS__); + +#if MDBX_DEBUG +#define ASSERT_FAIL(env, msg, func, line) mdbx_assert_fail(env, msg, func, line) +#else /* MDBX_DEBUG */ +MDBX_NORETURN __cold void assert_fail(const char *msg, const char *func, + unsigned line); +#define ASSERT_FAIL(env, msg, func, line) \ + do { \ + (void)(env); \ + assert_fail(msg, func, line); \ + } while (0) +#endif /* MDBX_DEBUG */ + +#define ENSURE_MSG(env, expr, msg) \ + do { \ + if (unlikely(!(expr))) \ + ASSERT_FAIL(env, msg, __func__, __LINE__); \ + } while (0) + +#define ENSURE(env, expr) ENSURE_MSG(env, expr, #expr) + +/* assert(3) variant in environment context */ +#define eASSERT(env, expr) \ + do { \ + if (ASSERT_ENABLED()) \ + ENSURE(env, expr); \ + } while (0) + +/* assert(3) variant in cursor context */ +#define cASSERT(mc, expr) eASSERT((mc)->mc_txn->mt_env, expr) + +/* assert(3) variant in transaction context */ +#define tASSERT(txn, expr) eASSERT((txn)->mt_env, expr) + +#ifndef xMDBX_TOOLS /* Avoid using internal eASSERT() */ +#undef assert +#define assert(expr) eASSERT(NULL, expr) +#endif + +#endif /* __cplusplus */ + /*----------------------------------------------------------------------------*/ /* Atomics */ enum MDBX_memory_order { mo_Relaxed, - mo_AcquireRelease, - mo_SequentialConsistency + mo_AcquireRelease + /* , mo_SequentialConsistency */ }; typedef union { @@ -2117,15 +2680,15 @@ typedef union { #ifndef __cplusplus #ifdef MDBX_HAVE_C11ATOMICS -#define mdbx_memory_fence(order, write) \ +#define osal_memory_fence(order, write) \ atomic_thread_fence((write) ? mo_c11_store(order) : mo_c11_load(order)) #else /* MDBX_HAVE_C11ATOMICS */ -#define mdbx_memory_fence(order, write) \ +#define osal_memory_fence(order, write) \ do { \ - mdbx_compiler_barrier(); \ + osal_compiler_barrier(); \ if (write && order > (MDBX_CPU_WRITEBACK_INCOHERENT ? mo_Relaxed \ : mo_AcquireRelease)) \ - mdbx_memory_barrier(); \ + osal_memory_barrier(); \ } while (0) #endif /* MDBX_HAVE_C11ATOMICS */ @@ -2160,26 +2723,26 @@ atomic_store32(MDBX_atomic_uint32_t *p, const uint32_t value, atomic_store_explicit(MDBX_c11a_rw(uint32_t, p), value, mo_c11_store(order)); #else /* MDBX_HAVE_C11ATOMICS */ if (order != mo_Relaxed) - mdbx_compiler_barrier(); + osal_compiler_barrier(); p->weak = value; - mdbx_memory_fence(order, true); + osal_memory_fence(order, true); #endif /* MDBX_HAVE_C11ATOMICS */ return value; } #endif /* atomic_store32 */ #ifndef atomic_load32 -MDBX_MAYBE_UNUSED static __always_inline uint32_t -atomic_load32(const MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) { +MDBX_MAYBE_UNUSED static __always_inline uint32_t atomic_load32( + const volatile MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) { STATIC_ASSERT(sizeof(MDBX_atomic_uint32_t) == 4); #ifdef MDBX_HAVE_C11ATOMICS assert(atomic_is_lock_free(MDBX_c11a_ro(uint32_t, p))); return atomic_load_explicit(MDBX_c11a_ro(uint32_t, p), mo_c11_load(order)); #else /* MDBX_HAVE_C11ATOMICS */ - mdbx_memory_fence(order, false); + osal_memory_fence(order, false); const uint32_t value = p->weak; if (order != mo_Relaxed) - mdbx_compiler_barrier(); + osal_compiler_barrier(); return value; #endif /* MDBX_HAVE_C11ATOMICS */ } @@ -2198,7 +2761,7 @@ atomic_load32(const MDBX_atomic_uint32_t *p, enum MDBX_memory_order order) { /* FROZEN: The version number for a database's datafile format. */ #define MDBX_DATA_VERSION 3 /* The version number for a database's lockfile format. */ -#define MDBX_LOCK_VERSION 4 +#define MDBX_LOCK_VERSION 5 /* handle for the DB used to track free pages. */ #define FREE_DBI 0 @@ -2287,7 +2850,10 @@ typedef struct MDBX_meta { uint32_t mm_magic_and_version[2]; /* txnid that committed this page, the first of a two-phase-update pair */ - uint32_t mm_txnid_a[2]; + union { + MDBX_atomic_uint32_t mm_txnid_a[2]; + uint64_t unsafe_txnid; + }; uint16_t mm_extra_flags; /* extra DB flags, zero (nothing) for now */ uint8_t mm_validator_id; /* ID of checksum and page validation method, @@ -2306,11 +2872,14 @@ typedef struct MDBX_meta { #define MDBX_DATASIGN_WEAK 1u #define SIGN_IS_STEADY(sign) ((sign) > MDBX_DATASIGN_WEAK) #define META_IS_STEADY(meta) \ - SIGN_IS_STEADY(unaligned_peek_u64_volatile(4, (meta)->mm_datasync_sign)) - uint32_t mm_datasync_sign[2]; + SIGN_IS_STEADY(unaligned_peek_u64_volatile(4, (meta)->mm_sign)) + union { + uint32_t mm_sign[2]; + uint64_t unsafe_sign; + }; /* txnid that committed this page, the second of a two-phase-update pair */ - uint32_t mm_txnid_b[2]; + MDBX_atomic_uint32_t mm_txnid_b[2]; /* Number of non-meta pages which were put in GC after COW. May be 0 in case * DB was previously handled by libmdbx without corresponding feature. @@ -2347,16 +2916,12 @@ typedef struct MDBX_meta { * Each non-metapage up to MDBX_meta.mm_last_pg is reachable exactly once * in the snapshot: Either used by a database or listed in a GC record. */ typedef struct MDBX_page { - union { #define IS_FROZEN(txn, p) ((p)->mp_txnid < (txn)->mt_txnid) #define IS_SPILLED(txn, p) ((p)->mp_txnid == (txn)->mt_txnid) #define IS_SHADOWED(txn, p) ((p)->mp_txnid > (txn)->mt_txnid) #define IS_VALID(txn, p) ((p)->mp_txnid <= (txn)->mt_front) #define IS_MODIFIABLE(txn, p) ((p)->mp_txnid == (txn)->mt_front) - uint64_t - mp_txnid; /* txnid which created this page, maybe zero in legacy DB */ - struct MDBX_page *mp_next; /* for in-memory list of freed pages */ - }; + uint64_t mp_txnid; /* txnid which created page, maybe zero in legacy DB */ uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */ #define P_BRANCH 0x01u /* branch page */ #define P_LEAF 0x02u /* leaf page */ @@ -2396,14 +2961,40 @@ typedef struct MDBX_page { : PAGETYPE_WHOLE(p)) /* Size of the page header, excluding dynamic data at the end */ -#define PAGEHDRSZ ((unsigned)offsetof(MDBX_page, mp_ptrs)) +#define PAGEHDRSZ offsetof(MDBX_page, mp_ptrs) + +/* Pointer displacement without casting to char* to avoid pointer-aliasing */ +#define ptr_disp(ptr, disp) ((void *)(((intptr_t)(ptr)) + ((intptr_t)(disp)))) + +/* Pointer distance as signed number of bytes */ +#define ptr_dist(more, less) (((intptr_t)(more)) - ((intptr_t)(less))) + +#define mp_next(mp) \ + (*(MDBX_page **)ptr_disp((mp)->mp_ptrs, sizeof(void *) - sizeof(uint32_t))) #pragma pack(pop) -#if MDBX_ENABLE_PGOP_STAT +typedef struct profgc_stat { + /* Монотонное время по "настенным часам" + * затраченное на чтение и поиск внутри GC */ + uint64_t rtime_monotonic; + /* Процессорное время в режим пользователя + * на подготовку страниц извлекаемых из GC, включая подкачку с диска. */ + uint64_t xtime_cpu; + /* Количество итераций чтения-поиска внутри GC при выделении страниц */ + uint32_t rsteps; + /* Количество запросов на выделение последовательностей страниц, + * т.е. когда запрашивает выделение больше одной страницы */ + uint32_t xpages; + /* Счетчик выполнения по медленному пути (slow path execution count) */ + uint32_t spe_counter; + /* page faults (hard page faults) */ + uint32_t majflt; +} profgc_stat_t; + /* Statistics of page operations overall of all (running, completed and aborted) * transactions */ -typedef struct { +typedef struct pgop_stat { MDBX_atomic_uint64_t newly; /* Quantity of a new pages added */ MDBX_atomic_uint64_t cow; /* Quantity of pages copied for update */ MDBX_atomic_uint64_t clone; /* Quantity of parent's dirty pages clones @@ -2415,18 +3006,47 @@ typedef struct { MDBX_atomic_uint64_t wops; /* Number of explicit write operations (not a pages) to a disk */ MDBX_atomic_uint64_t - gcrtime; /* Time spending for reading/searching GC (aka FreeDB). The - unit/scale is platform-depended, see mdbx_osal_monotime(). */ -} MDBX_pgop_stat_t; -#endif /* MDBX_ENABLE_PGOP_STAT */ + msync; /* Number of explicit msync/flush-to-disk operations */ + MDBX_atomic_uint64_t + fsync; /* Number of explicit fsync/flush-to-disk operations */ + + MDBX_atomic_uint64_t prefault; /* Number of prefault write operations */ + MDBX_atomic_uint64_t mincore; /* Number of mincore() calls */ + + MDBX_atomic_uint32_t + incoherence; /* number of https://libmdbx.dqdkfa.ru/dead-github/issues/269 + caught */ + MDBX_atomic_uint32_t reserved; + + /* Статистика для профилирования GC. + * Логически эти данные может быть стоит вынести в другую структуру, + * но разница будет сугубо косметическая. */ + struct { + /* Затраты на поддержку данных пользователя */ + profgc_stat_t work; + /* Затраты на поддержку и обновления самой GC */ + profgc_stat_t self; + /* Итераций обновления GC, + * больше 1 если были повторы/перезапуски */ + uint32_t wloops; + /* Итерации слияния записей GC */ + uint32_t coalescences; + /* Уничтожения steady-точек фиксации в MDBX_UTTERLY_NOSYNC */ + uint32_t wipes; + /* Сбросы данные на диск вне MDBX_UTTERLY_NOSYNC */ + uint32_t flushes; + /* Попытки пнуть тормозящих читателей */ + uint32_t kicks; + } gc_prof; +} pgop_stat_t; #if MDBX_LOCKING == MDBX_LOCKING_WIN32FILES #define MDBX_CLOCK_SIGN UINT32_C(0xF10C) -typedef void mdbx_ipclock_t; +typedef void osal_ipclock_t; #elif MDBX_LOCKING == MDBX_LOCKING_SYSV #define MDBX_CLOCK_SIGN UINT32_C(0xF18D) -typedef mdbx_pid_t mdbx_ipclock_t; +typedef mdbx_pid_t osal_ipclock_t; #ifndef EOWNERDEAD #define EOWNERDEAD MDBX_RESULT_TRUE #endif @@ -2434,17 +3054,17 @@ typedef mdbx_pid_t mdbx_ipclock_t; #elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || \ MDBX_LOCKING == MDBX_LOCKING_POSIX2008 #define MDBX_CLOCK_SIGN UINT32_C(0x8017) -typedef pthread_mutex_t mdbx_ipclock_t; +typedef pthread_mutex_t osal_ipclock_t; #elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988 #define MDBX_CLOCK_SIGN UINT32_C(0xFC29) -typedef sem_t mdbx_ipclock_t; +typedef sem_t osal_ipclock_t; #else #error "FIXME" #endif /* MDBX_LOCKING */ #if MDBX_LOCKING > MDBX_LOCKING_SYSV && !defined(__cplusplus) -MDBX_INTERNAL_FUNC int mdbx_ipclock_stub(mdbx_ipclock_t *ipc); -MDBX_INTERNAL_FUNC int mdbx_ipclock_destroy(mdbx_ipclock_t *ipc); +MDBX_INTERNAL_FUNC int osal_ipclock_stub(osal_ipclock_t *ipc); +MDBX_INTERNAL_FUNC int osal_ipclock_destroy(osal_ipclock_t *ipc); #endif /* MDBX_LOCKING */ /* Reader Lock Table @@ -2537,6 +3157,10 @@ typedef struct MDBX_lockinfo { /* Low 32-bit of txnid with which meta-pages was synced, * i.e. for sync-polling in the MDBX_NOMETASYNC mode. */ +#define MDBX_NOMETASYNC_LAZY_UNK (UINT32_MAX / 3) +#define MDBX_NOMETASYNC_LAZY_FD (MDBX_NOMETASYNC_LAZY_UNK + UINT32_MAX / 8) +#define MDBX_NOMETASYNC_LAZY_WRITEMAP \ + (MDBX_NOMETASYNC_LAZY_UNK - UINT32_MAX / 8) MDBX_atomic_uint32_t mti_meta_sync_txnid; /* Period for timed auto-sync feature, i.e. at the every steady checkpoint @@ -2549,45 +3173,54 @@ typedef struct MDBX_lockinfo { /* Marker to distinguish uniqueness of DB/CLK. */ MDBX_atomic_uint64_t mti_bait_uniqueness; + /* Paired counter of processes that have mlock()ed part of mmapped DB. + * The (mti_mlcnt[0] - mti_mlcnt[1]) > 0 means at least one process + * lock at least one page, so therefore madvise() could return EINVAL. */ + MDBX_atomic_uint32_t mti_mlcnt[2]; + MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/ -#if MDBX_ENABLE_PGOP_STAT /* Statistics of costly ops of all (running, completed and aborted) * transactions */ - MDBX_pgop_stat_t mti_pgop_stat; -#endif /* MDBX_ENABLE_PGOP_STAT*/ + pgop_stat_t mti_pgop_stat; MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/ /* Write transaction lock. */ #if MDBX_LOCKING > 0 - mdbx_ipclock_t mti_wlock; + osal_ipclock_t mti_wlock; #endif /* MDBX_LOCKING > 0 */ atomic_txnid_t mti_oldest_reader; - /* Timestamp of the last steady sync. Value is represented in a suitable - * system-dependent form, for example clock_gettime(CLOCK_BOOTTIME) or - * clock_gettime(CLOCK_MONOTONIC). */ - MDBX_atomic_uint64_t mti_sync_timestamp; + /* Timestamp of entering an out-of-sync state. Value is represented in a + * suitable system-dependent form, for example clock_gettime(CLOCK_BOOTTIME) + * or clock_gettime(CLOCK_MONOTONIC). */ + MDBX_atomic_uint64_t mti_eoos_timestamp; /* Number un-synced-with-disk pages for auto-sync feature. */ - atomic_pgno_t mti_unsynced_pages; - - /* Number of page which was discarded last time by madvise(MADV_FREE). */ - atomic_pgno_t mti_discarded_tail; + MDBX_atomic_uint64_t mti_unsynced_pages; /* Timestamp of the last readers check. */ MDBX_atomic_uint64_t mti_reader_check_timestamp; + /* Number of page which was discarded last time by madvise(DONTNEED). */ + atomic_pgno_t mti_discarded_tail; + /* Shared anchor for tracking readahead edge and enabled/disabled status. */ pgno_t mti_readahead_anchor; + /* Shared cache for mincore() results */ + struct { + pgno_t begin[4]; + uint64_t mask[4]; + } mti_mincore_cache; + MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/ /* Readeaders registration lock. */ #if MDBX_LOCKING > 0 - mdbx_ipclock_t mti_rlock; + osal_ipclock_t mti_rlock; #endif /* MDBX_LOCKING > 0 */ /* The number of slots that have been used in the reader table. @@ -2655,7 +3288,8 @@ typedef struct MDBX_lockinfo { #endif /* MDBX_WORDBITS */ #define MDBX_READERS_LIMIT 32767 -#define MDBX_RADIXSORT_THRESHOLD 333 +#define MDBX_RADIXSORT_THRESHOLD 142 +#define MDBX_GOLD_RATIO_DBL 1.6180339887498948482 /*----------------------------------------------------------------------------*/ @@ -2680,21 +3314,15 @@ typedef txnid_t *MDBX_TXL; /* An Dirty-Page list item is an pgno/pointer pair. */ typedef struct MDBX_dp { MDBX_page *ptr; - pgno_t pgno; - union { - unsigned extra; - __anonymous_struct_extension__ struct { - unsigned multi : 1; - unsigned lru : 31; - }; - }; + pgno_t pgno, npages; } MDBX_dp; /* An DPL (dirty-page list) is a sorted array of MDBX_DPs. */ typedef struct MDBX_dpl { - unsigned sorted; - unsigned length; - unsigned detent; /* allocated size excluding the MDBX_DPL_RESERVE_GAP */ + size_t sorted; + size_t length; + size_t pages_including_loose; /* number of pages, but not an entries. */ + size_t detent; /* allocated size excluding the MDBX_DPL_RESERVE_GAP */ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ (!defined(__cplusplus) && defined(_MSC_VER)) MDBX_dp items[] /* dynamic size with holes at zero and after the last */; @@ -2702,7 +3330,8 @@ typedef struct MDBX_dpl { } MDBX_dpl; /* PNL sizes */ -#define MDBX_PNL_GRANULATE 1024 +#define MDBX_PNL_GRANULATE_LOG2 10 +#define MDBX_PNL_GRANULATE (1 << MDBX_PNL_GRANULATE_LOG2) #define MDBX_PNL_INITIAL \ (MDBX_PNL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(pgno_t)) @@ -2710,25 +3339,33 @@ typedef struct MDBX_dpl { #define MDBX_TXL_INITIAL \ (MDBX_TXL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t)) #define MDBX_TXL_MAX \ - ((1u << 17) - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t)) + ((1u << 26) - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t)) #define MDBX_PNL_ALLOCLEN(pl) ((pl)[-1]) -#define MDBX_PNL_SIZE(pl) ((pl)[0]) +#define MDBX_PNL_GETSIZE(pl) ((size_t)((pl)[0])) +#define MDBX_PNL_SETSIZE(pl, size) \ + do { \ + const size_t __size = size; \ + assert(__size < INT_MAX); \ + (pl)[0] = (pgno_t)__size; \ + } while (0) #define MDBX_PNL_FIRST(pl) ((pl)[1]) -#define MDBX_PNL_LAST(pl) ((pl)[MDBX_PNL_SIZE(pl)]) +#define MDBX_PNL_LAST(pl) ((pl)[MDBX_PNL_GETSIZE(pl)]) #define MDBX_PNL_BEGIN(pl) (&(pl)[1]) -#define MDBX_PNL_END(pl) (&(pl)[MDBX_PNL_SIZE(pl) + 1]) +#define MDBX_PNL_END(pl) (&(pl)[MDBX_PNL_GETSIZE(pl) + 1]) #if MDBX_PNL_ASCENDING +#define MDBX_PNL_EDGE(pl) ((pl) + 1) #define MDBX_PNL_LEAST(pl) MDBX_PNL_FIRST(pl) #define MDBX_PNL_MOST(pl) MDBX_PNL_LAST(pl) #else +#define MDBX_PNL_EDGE(pl) ((pl) + MDBX_PNL_GETSIZE(pl)) #define MDBX_PNL_LEAST(pl) MDBX_PNL_LAST(pl) #define MDBX_PNL_MOST(pl) MDBX_PNL_FIRST(pl) #endif -#define MDBX_PNL_SIZEOF(pl) ((MDBX_PNL_SIZE(pl) + 1) * sizeof(pgno_t)) -#define MDBX_PNL_IS_EMPTY(pl) (MDBX_PNL_SIZE(pl) == 0) +#define MDBX_PNL_SIZEOF(pl) ((MDBX_PNL_GETSIZE(pl) + 1) * sizeof(pgno_t)) +#define MDBX_PNL_IS_EMPTY(pl) (MDBX_PNL_GETSIZE(pl) == 0) /*----------------------------------------------------------------------------*/ /* Internal structures */ @@ -2745,6 +3382,18 @@ typedef struct MDBX_dbx { md_vlen_max; /* min/max value/data length for the database */ } MDBX_dbx; +typedef struct troika { + uint8_t fsm, recent, prefer_steady, tail_and_flags; +#if MDBX_WORDBITS > 32 /* Workaround for false-positives from Valgrind */ + uint32_t unused_pad; +#endif +#define TROIKA_HAVE_STEADY(troika) ((troika)->fsm & 7) +#define TROIKA_STRICT_VALID(troika) ((troika)->tail_and_flags & 64) +#define TROIKA_VALID(troika) ((troika)->tail_and_flags & 128) +#define TROIKA_TAIL(troika) ((troika)->tail_and_flags & 3) + txnid_t txnid[NUM_METAS]; +} meta_troika_t; + /* A database transaction. * Every operation requires a transaction handle. */ struct MDBX_txn { @@ -2756,12 +3405,14 @@ struct MDBX_txn { #define MDBX_TXN_RO_BEGIN_FLAGS (MDBX_TXN_RDONLY | MDBX_TXN_RDONLY_PREPARE) #define MDBX_TXN_RW_BEGIN_FLAGS \ (MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_TRY) - /* Additional flag for mdbx_sync_locked() */ + /* Additional flag for sync_locked() */ #define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000) +#define MDBX_TXN_DRAINED_GC 0x20 /* GC was depleted up to oldest reader */ + #define TXN_FLAGS \ (MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS | \ - MDBX_TXN_HAS_CHILD | MDBX_TXN_INVALID) + MDBX_TXN_HAS_CHILD | MDBX_TXN_INVALID | MDBX_TXN_DRAINED_GC) #if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) || \ ((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) & \ @@ -2791,7 +3442,7 @@ struct MDBX_txn { /* Array of MDBX_db records for each known DB */ MDBX_db *mt_dbs; /* Array of sequence numbers for each DB handle */ - unsigned *mt_dbiseqs; + MDBX_atomic_uint32_t *mt_dbiseqs; /* Transaction DBI Flags */ #define DBI_DIRTY MDBX_DBI_DIRTY /* DB was written in this txn */ @@ -2818,19 +3469,20 @@ struct MDBX_txn { MDBX_reader *reader; } to; struct { + meta_troika_t troika; /* In write txns, array of cursors for each DB */ - pgno_t *reclaimed_pglist; /* Reclaimed GC pages */ - txnid_t last_reclaimed; /* ID of last used record */ + MDBX_PNL relist; /* Reclaimed GC pages */ + txnid_t last_reclaimed; /* ID of last used record */ #if MDBX_ENABLE_REFUND pgno_t loose_refund_wl /* FIXME: describe */; #endif /* MDBX_ENABLE_REFUND */ + /* a sequence to spilling dirty page with LRU policy */ + unsigned dirtylru; /* dirtylist room: Dirty array size - dirty pages visible to this txn. * Includes ancestor txns' dirty pages not hidden by other txns' * dirty/spilled pages. Thus commit(nested txn) has room to merge * dirtylist into mt_parent after freeing hidden mt_parent pages. */ - unsigned dirtyroom; - /* a sequence to spilling dirty page with LRU policy */ - unsigned dirtylru; + size_t dirtyroom; /* For write txns: Modified pages. Sorted when not MDBX_WRITEMAP. */ MDBX_dpl *dirtylist; /* The list of reclaimed txns from GC */ @@ -2841,12 +3493,18 @@ struct MDBX_txn { * in this transaction, linked through `mp_next`. */ MDBX_page *loose_pages; /* Number of loose pages (tw.loose_pages) */ - unsigned loose_count; - unsigned spill_least_removed; - /* The sorted list of dirty pages we temporarily wrote to disk - * because the dirty list was full. page numbers in here are - * shifted left by 1, deleted slots have the LSB set. */ - MDBX_PNL spill_pages; + size_t loose_count; + union { + struct { + size_t least_removed; + /* The sorted list of dirty pages we temporarily wrote to disk + * because the dirty list was full. page numbers in here are + * shifted left by 1, deleted slots have the LSB set. */ + MDBX_PNL list; + } spilled; + size_t writemap_dirty_npages; + size_t writemap_spilled_npages; + }; } tw; }; }; @@ -2896,9 +3554,10 @@ struct MDBX_cursor { #define C_SUB 0x04 /* Cursor is a sub-cursor */ #define C_DEL 0x08 /* last op was a cursor_del */ #define C_UNTRACK 0x10 /* Un-track cursor when closing */ -#define C_RECLAIMING 0x20 /* GC lookup is prohibited */ -#define C_GCFREEZE 0x40 /* reclaimed_pglist must not be updated */ - uint8_t mc_flags; /* see mdbx_cursor */ +#define C_GCU \ + 0x20 /* Происходит подготовка к обновлению GC, поэтому \ + * можно брать страницы из GC даже для FREE_DBI */ + uint8_t mc_flags; /* Cursor checking flags. */ #define CC_BRANCH 0x01 /* same as P_BRANCH for CHECK_LEAF_TYPE() */ @@ -2909,7 +3568,7 @@ struct MDBX_cursor { #define CC_LEAF2 0x20 /* same as P_LEAF2 for CHECK_LEAF_TYPE() */ #define CC_RETIRING 0x40 /* refs to child pages may be invalid */ #define CC_PAGECHECK 0x80 /* perform page checking, see MDBX_VALIDATION */ - uint8_t mc_checking; /* page checking level */ + uint8_t mc_checking; MDBX_page *mc_pg[CURSOR_STACK]; /* stack of pushed pages */ indx_t mc_ki[CURSOR_STACK]; /* stack of page indices */ @@ -2951,42 +3610,50 @@ struct MDBX_env { #define MDBX_ENV_TXKEY UINT32_C(0x10000000) /* Legacy MDBX_MAPASYNC (prior v0.9) */ #define MDBX_DEPRECATED_MAPASYNC UINT32_C(0x100000) - /* Legacy MDBX_MAPASYNC (prior v0.12) */ + /* Legacy MDBX_COALESCE (prior v0.12) */ #define MDBX_DEPRECATED_COALESCE UINT32_C(0x2000000) #define ENV_INTERNAL_FLAGS (MDBX_FATAL_ERROR | MDBX_ENV_ACTIVE | MDBX_ENV_TXKEY) uint32_t me_flags; - mdbx_mmap_t me_dxb_mmap; /* The main data file */ -#define me_map me_dxb_mmap.dxb + osal_mmap_t me_dxb_mmap; /* The main data file */ +#define me_map me_dxb_mmap.base #define me_lazy_fd me_dxb_mmap.fd - mdbx_filehandle_t me_dsync_fd; - mdbx_mmap_t me_lck_mmap; /* The lock file */ + mdbx_filehandle_t me_dsync_fd, me_fd4meta; +#if defined(_WIN32) || defined(_WIN64) +#define me_overlapped_fd me_ioring.overlapped_fd + HANDLE me_data_lock_event; +#endif /* Windows */ + osal_mmap_t me_lck_mmap; /* The lock file */ #define me_lfd me_lck_mmap.fd struct MDBX_lockinfo *me_lck; - unsigned me_psize; /* DB page size, initialized from me_os_psize */ - unsigned me_leaf_nodemax; /* max size of a leaf-node */ - uint8_t me_psize2log; /* log2 of DB page size */ + unsigned me_psize; /* DB page size, initialized from me_os_psize */ + unsigned me_leaf_nodemax; /* max size of a leaf-node */ + unsigned me_branch_nodemax; /* max size of a branch-node */ + atomic_pgno_t me_mlocked_pgno; + uint8_t me_psize2log; /* log2 of DB page size */ int8_t me_stuck_meta; /* recovery-only: target meta page or less that zero */ uint16_t me_merge_threshold, me_merge_threshold_gc; /* pages emptier than this are candidates for merging */ - unsigned me_os_psize; /* OS page size, from mdbx_syspagesize() */ + unsigned me_os_psize; /* OS page size, from osal_syspagesize() */ unsigned me_maxreaders; /* size of the reader table */ MDBX_dbi me_maxdbs; /* size of the DB table */ uint32_t me_pid; /* process ID of this env */ - mdbx_thread_key_t me_txkey; /* thread-key for readers */ - char *me_pathname; /* path to the DB files */ + osal_thread_key_t me_txkey; /* thread-key for readers */ + pathchar_t *me_pathname; /* path to the DB files */ void *me_pbuf; /* scratch area for DUPSORT put() */ MDBX_txn *me_txn0; /* preallocated write transaction */ - MDBX_dbx *me_dbxs; /* array of static DB info */ - uint16_t *me_dbflags; /* array of flags from MDBX_db.md_flags */ - unsigned *me_dbiseqs; /* array of dbi sequence numbers */ + MDBX_dbx *me_dbxs; /* array of static DB info */ + uint16_t *me_dbflags; /* array of flags from MDBX_db.md_flags */ + MDBX_atomic_uint32_t *me_dbiseqs; /* array of dbi sequence numbers */ unsigned - me_maxgc_ov1page; /* Number of pgno_t fit in a single overflow page */ - uint32_t me_live_reader; /* have liveness lock in reader table */ - void *me_userctx; /* User-settable context */ + me_maxgc_ov1page; /* Number of pgno_t fit in a single overflow page */ + unsigned me_maxgc_per_branch; + uint32_t me_live_reader; /* have liveness lock in reader table */ + void *me_userctx; /* User-settable context */ MDBX_hsr_func *me_hsr_callback; /* Callback for kicking laggard readers */ + size_t me_madv_threshold; struct { unsigned dp_reserve_limit; @@ -2998,11 +3665,17 @@ struct MDBX_env { uint8_t spill_min_denominator; uint8_t spill_parent4child_denominator; unsigned merge_threshold_16dot16_percent; +#if !(defined(_WIN32) || defined(_WIN64)) + unsigned writethrough_threshold; +#endif /* Windows */ + bool prefault_write; union { unsigned all; /* tracks options with non-auto values but tuned by user */ struct { unsigned dp_limit : 1; + unsigned rp_augment_limit : 1; + unsigned prefault_write : 1; } non_auto; } flags; } me_options; @@ -3024,30 +3697,31 @@ struct MDBX_env { int semid; } me_sysv_ipc; #endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */ + bool me_incore; MDBX_env *me_lcklist_next; /* --------------------------------------------------- mostly volatile part */ MDBX_txn *me_txn; /* current write transaction */ - mdbx_fastmutex_t me_dbi_lock; -#if MDBX_CACHE_METAPTR - volatile const MDBX_meta *cache_last_meta; - volatile const MDBX_meta *cache_steady_meta; -#endif /* MDBX_CACHE_METAPTR */ + osal_fastmutex_t me_dbi_lock; MDBX_dbi me_numdbs; /* number of DBs opened */ + bool me_prefault_write; MDBX_page *me_dp_reserve; /* list of malloc'ed blocks for re-use */ unsigned me_dp_reserve_len; /* PNL of pages that became unused in a write txn */ MDBX_PNL me_retired_pages; + osal_ioring_t me_ioring; #if defined(_WIN32) || defined(_WIN64) - MDBX_srwlock me_remap_guard; + osal_srwlock_t me_remap_guard; /* Workaround for LockFileEx and WriteFile multithread bug */ CRITICAL_SECTION me_windowsbug_lock; + char *me_pathname_char; /* cache of multi-byte representation of pathname + to the DB files */ #else - mdbx_fastmutex_t me_remap_guard; + osal_fastmutex_t me_remap_guard; #endif /* -------------------------------------------------------------- debugging */ @@ -3059,6 +3733,7 @@ struct MDBX_env { int me_valgrind_handle; #endif #if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__) + MDBX_atomic_uint32_t me_ignore_EDEADLK; pgno_t me_poison_edge; #endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */ @@ -3066,7 +3741,7 @@ struct MDBX_env { #define xMDBX_DEBUG_SPILLING 0 #endif #if xMDBX_DEBUG_SPILLING == 2 - unsigned debug_dirtied_est, debug_dirtied_act; + size_t debug_dirtied_est, debug_dirtied_act; #endif /* xMDBX_DEBUG_SPILLING */ /* ------------------------------------------------- stub for lck-less mode */ @@ -3076,148 +3751,24 @@ struct MDBX_env { }; #ifndef __cplusplus -/*----------------------------------------------------------------------------*/ -/* Debug and Logging stuff */ - -#define MDBX_RUNTIME_FLAGS_INIT \ - ((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT - -extern uint8_t mdbx_runtime_flags; -extern uint8_t mdbx_loglevel; -extern MDBX_debug_func *mdbx_debug_logger; - -MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny) { -#if MDBX_DEBUG - if (MDBX_DBG_JITTER & mdbx_runtime_flags) - mdbx_osal_jitter(tiny); -#else - (void)tiny; -#endif -} - -MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5) - mdbx_debug_log(int level, const char *function, int line, const char *fmt, - ...) MDBX_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); - -#if MDBX_DEBUG -#define mdbx_log_enabled(msg) unlikely(msg <= mdbx_loglevel) -#define mdbx_audit_enabled() unlikely((mdbx_runtime_flags & MDBX_DBG_AUDIT)) -#else /* MDBX_DEBUG */ -#define mdbx_log_enabled(msg) (msg < MDBX_LOG_VERBOSE && msg <= mdbx_loglevel) -#define mdbx_audit_enabled() (0) -#endif /* MDBX_DEBUG */ - -#if MDBX_FORCE_ASSERTIONS -#define mdbx_assert_enabled() (1) -#elif MDBX_DEBUG -#define mdbx_assert_enabled() likely((mdbx_runtime_flags & MDBX_DBG_ASSERT)) -#else -#define mdbx_assert_enabled() (0) -#endif /* assertions */ - -#define mdbx_debug_extra(fmt, ...) \ - do { \ - if (mdbx_log_enabled(MDBX_LOG_EXTRA)) \ - mdbx_debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__); \ - } while (0) - -#define mdbx_debug_extra_print(fmt, ...) \ - do { \ - if (mdbx_log_enabled(MDBX_LOG_EXTRA)) \ - mdbx_debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__); \ - } while (0) - -#define mdbx_trace(fmt, ...) \ - do { \ - if (mdbx_log_enabled(MDBX_LOG_TRACE)) \ - mdbx_debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n", \ - __VA_ARGS__); \ - } while (0) - -#define mdbx_debug(fmt, ...) \ - do { \ - if (mdbx_log_enabled(MDBX_LOG_DEBUG)) \ - mdbx_debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n", \ - __VA_ARGS__); \ - } while (0) - -#define mdbx_verbose(fmt, ...) \ - do { \ - if (mdbx_log_enabled(MDBX_LOG_VERBOSE)) \ - mdbx_debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n", \ - __VA_ARGS__); \ - } while (0) - -#define mdbx_notice(fmt, ...) \ - do { \ - if (mdbx_log_enabled(MDBX_LOG_NOTICE)) \ - mdbx_debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n", \ - __VA_ARGS__); \ - } while (0) - -#define mdbx_warning(fmt, ...) \ - do { \ - if (mdbx_log_enabled(MDBX_LOG_WARN)) \ - mdbx_debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n", \ - __VA_ARGS__); \ - } while (0) - -#define mdbx_error(fmt, ...) \ - do { \ - if (mdbx_log_enabled(MDBX_LOG_ERROR)) \ - mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n", \ - __VA_ARGS__); \ - } while (0) - -#define mdbx_fatal(fmt, ...) \ - mdbx_debug_log(MDBX_LOG_FATAL, __func__, __LINE__, fmt "\n", __VA_ARGS__); - -#define mdbx_ensure_msg(env, expr, msg) \ - do { \ - if (unlikely(!(expr))) \ - mdbx_assert_fail(env, msg, __func__, __LINE__); \ - } while (0) - -#define mdbx_ensure(env, expr) mdbx_ensure_msg(env, expr, #expr) - -/* assert(3) variant in environment context */ -#define mdbx_assert(env, expr) \ - do { \ - if (mdbx_assert_enabled()) \ - mdbx_ensure(env, expr); \ - } while (0) - -/* assert(3) variant in cursor context */ -#define mdbx_cassert(mc, expr) mdbx_assert((mc)->mc_txn->mt_env, expr) - -/* assert(3) variant in transaction context */ -#define mdbx_tassert(txn, expr) mdbx_assert((txn)->mt_env, expr) - -#ifndef xMDBX_TOOLS /* Avoid using internal mdbx_assert() */ -#undef assert -#define assert(expr) mdbx_assert(NULL, expr) -#endif - /*----------------------------------------------------------------------------*/ /* Cache coherence and mmap invalidation */ #if MDBX_CPU_WRITEBACK_INCOHERENT -#define mdbx_flush_incoherent_cpu_writeback() mdbx_memory_barrier() +#define osal_flush_incoherent_cpu_writeback() osal_memory_barrier() #else -#define mdbx_flush_incoherent_cpu_writeback() mdbx_compiler_barrier() +#define osal_flush_incoherent_cpu_writeback() osal_compiler_barrier() #endif /* MDBX_CPU_WRITEBACK_INCOHERENT */ MDBX_MAYBE_UNUSED static __inline void -mdbx_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) { +osal_flush_incoherent_mmap(const void *addr, size_t nbytes, + const intptr_t pagesize) { #if MDBX_MMAP_INCOHERENT_FILE_WRITE char *const begin = (char *)(-pagesize & (intptr_t)addr); char *const end = (char *)(-pagesize & (intptr_t)((char *)addr + nbytes + pagesize - 1)); int err = msync(begin, end - begin, MS_SYNC | MS_INVALIDATE) ? errno : 0; - mdbx_assert(nullptr, err == 0); + eASSERT(nullptr, err == 0); (void)err; #else (void)pagesize; @@ -3227,7 +3778,7 @@ mdbx_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) { #ifdef DCACHE /* MIPS has cache coherency issues. * Note: for any nbytes >= on-chip cache size, entire is flushed. */ - cacheflush(addr, nbytes, DCACHE); + cacheflush((void *)addr, nbytes, DCACHE); #else #error "Oops, cacheflush() not available" #endif /* DCACHE */ @@ -3242,15 +3793,17 @@ mdbx_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) { /*----------------------------------------------------------------------------*/ /* Internal prototypes */ -MDBX_INTERNAL_FUNC int mdbx_cleanup_dead_readers(MDBX_env *env, int rlocked, - int *dead); -MDBX_INTERNAL_FUNC int mdbx_rthc_alloc(mdbx_thread_key_t *key, - MDBX_reader *begin, MDBX_reader *end); -MDBX_INTERNAL_FUNC void mdbx_rthc_remove(const mdbx_thread_key_t key); +MDBX_INTERNAL_FUNC int cleanup_dead_readers(MDBX_env *env, int rlocked, + int *dead); +MDBX_INTERNAL_FUNC int rthc_alloc(osal_thread_key_t *key, MDBX_reader *begin, + MDBX_reader *end); +MDBX_INTERNAL_FUNC void rthc_remove(const osal_thread_key_t key); -MDBX_INTERNAL_FUNC void mdbx_rthc_global_init(void); -MDBX_INTERNAL_FUNC void mdbx_rthc_global_dtor(void); -MDBX_INTERNAL_FUNC void mdbx_rthc_thread_dtor(void *ptr); +MDBX_INTERNAL_FUNC void global_ctor(void); +MDBX_INTERNAL_FUNC void osal_ctor(void); +MDBX_INTERNAL_FUNC void global_dtor(void); +MDBX_INTERNAL_FUNC void osal_dtor(void); +MDBX_INTERNAL_FUNC void thread_dtor(void *ptr); #endif /* !__cplusplus */ @@ -3370,12 +3923,12 @@ typedef struct MDBX_node { #error "Oops, some flags overlapped or wrong" #endif -/* max number of pages to commit in one writev() call */ -#define MDBX_COMMIT_PAGES 64 -#if defined(IOV_MAX) && IOV_MAX < MDBX_COMMIT_PAGES /* sysconf(_SC_IOV_MAX) */ -#undef MDBX_COMMIT_PAGES -#define MDBX_COMMIT_PAGES IOV_MAX -#endif +/* Max length of iov-vector passed to writev() call, used for auxilary writes */ +#define MDBX_AUXILARY_IOV_MAX 64 +#if defined(IOV_MAX) && IOV_MAX < MDBX_AUXILARY_IOV_MAX +#undef MDBX_AUXILARY_IOV_MAX +#define MDBX_AUXILARY_IOV_MAX IOV_MAX +#endif /* MDBX_AUXILARY_IOV_MAX */ /* * / @@ -3384,16 +3937,7 @@ typedef struct MDBX_node { * | 1, a > b * \ */ -#ifndef __e2k__ -/* LY: fast enough on most systems */ -#define CMP2INT(a, b) (((b) > (a)) ? -1 : (a) > (b)) -#else -/* LY: more parallelable on VLIW Elbrus */ -#define CMP2INT(a, b) (((a) > (b)) - ((b) > (a))) -#endif - -/* Do not spill pages to disk if txn is getting full, may fail instead */ -#define MDBX_NOSPILL 0x8000 +#define CMP2INT(a, b) (((a) != (b)) ? (((a) < (b)) ? -1 : 1) : 0) MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t int64pgno(int64_t i64) { @@ -3405,14 +3949,14 @@ int64pgno(int64_t i64) { MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t pgno_add(size_t base, size_t augend) { assert(base <= MAX_PAGENO + 1 && augend < MAX_PAGENO); - return int64pgno(base + augend); + return int64pgno((int64_t)base + (int64_t)augend); } MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t pgno_sub(size_t base, size_t subtrahend) { assert(base >= MIN_PAGENO && base <= MAX_PAGENO + 1 && subtrahend < MAX_PAGENO); - return int64pgno(base - subtrahend); + return int64pgno((int64_t)base - (int64_t)subtrahend); } MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline bool @@ -3432,20 +3976,24 @@ ceil_powerof2(size_t value, size_t granularity) { } MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static unsigned -log2n_powerof2(size_t value) { - assert(value > 0 && value < INT32_MAX && is_powerof2(value)); - assert((value & -(int32_t)value) == value); -#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl) - return __builtin_ctzl(value); +log2n_powerof2(size_t value_uintptr) { + assert(value_uintptr > 0 && value_uintptr < INT32_MAX && + is_powerof2(value_uintptr)); + assert((value_uintptr & -(intptr_t)value_uintptr) == value_uintptr); + const uint32_t value_uint32 = (uint32_t)value_uintptr; +#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctz) + STATIC_ASSERT(sizeof(value_uint32) <= sizeof(unsigned)); + return __builtin_ctz(value_uint32); #elif defined(_MSC_VER) unsigned long index; - _BitScanForward(&index, (unsigned long)value); + STATIC_ASSERT(sizeof(value_uint32) <= sizeof(long)); + _BitScanForward(&index, value_uint32); return index; #else static const uint8_t debruijn_ctz32[32] = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; - return debruijn_ctz32[(uint32_t)(value * 0x077CB531u) >> 27]; + return debruijn_ctz32[(uint32_t)(value_uint32 * 0x077CB531ul) >> 27]; #endif } @@ -3480,19 +4028,19 @@ MDBX_MAYBE_UNUSED static void static_checks(void) { #define MDBX_ASAN_POISON_MEMORY_REGION(addr, size) \ do { \ - mdbx_trace("POISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr), \ - (size_t)(size), __LINE__); \ + TRACE("POISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr), \ + (size_t)(size), __LINE__); \ ASAN_POISON_MEMORY_REGION(addr, size); \ } while (0) #define MDBX_ASAN_UNPOISON_MEMORY_REGION(addr, size) \ do { \ - mdbx_trace("UNPOISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr), \ - (size_t)(size), __LINE__); \ + TRACE("UNPOISON_MEMORY_REGION(%p, %zu) at %u", (void *)(addr), \ + (size_t)(size), __LINE__); \ ASAN_UNPOISON_MEMORY_REGION(addr, size); \ } while (0) // -// Copyright (c) 2020-2022, Leonid Yuriev . +// Copyright (c) 2020-2023, Leonid Yuriev . // SPDX-License-Identifier: Apache-2.0 // // Non-inline part of the libmdbx C++ API @@ -3505,7 +4053,13 @@ MDBX_MAYBE_UNUSED static void static_checks(void) { #if (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)) && \ !defined(__USE_MINGW_ANSI_STDIO) #define __USE_MINGW_ANSI_STDIO 1 -#endif /* __USE_MINGW_ANSI_STDIO */ +#endif /* MinGW */ + +/* Workaround for MSVC' header `extern "C"` vs `std::` redefinition bug */ +#if defined(_MSC_VER) && defined(__SANITIZE_ADDRESS__) && \ + !defined(_DISABLE_VECTOR_ANNOTATION) +#define _DISABLE_VECTOR_ANNOTATION +#endif /* _DISABLE_VECTOR_ANNOTATION */ @@ -3692,64 +4246,6 @@ __cold bug::~bug() noexcept {} #endif /* Unused*/ -//------------------------------------------------------------------------------ - -template struct path_to_pchar { - const std::string str; - path_to_pchar(const PATH &path) : str(path.generic_string()) {} - operator const char *() const { return str.c_str(); } -}; - -template -MDBX_MAYBE_UNUSED PATH pchar_to_path(const char *c_str) { - return PATH(c_str); -} - -#if defined(_WIN32) || defined(_WIN64) - -#ifndef WC_ERR_INVALID_CHARS -static const DWORD WC_ERR_INVALID_CHARS = - (6 /* Windows Vista */ <= /* MajorVersion */ LOBYTE(LOWORD(GetVersion()))) - ? 0x00000080 - : 0; -#endif /* WC_ERR_INVALID_CHARS */ - -template <> struct path_to_pchar { - std::string str; - path_to_pchar(const std::wstring &path) { - if (!path.empty()) { - const int chars = - WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, path.data(), - int(path.size()), nullptr, 0, nullptr, nullptr); - if (chars == 0) - mdbx::error::throw_exception(GetLastError()); - str.append(chars, '\0'); - WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, path.data(), - int(path.size()), const_cast(str.data()), - chars, nullptr, nullptr); - } - } - operator const char *() const { return str.c_str(); } -}; - -template <> -MDBX_MAYBE_UNUSED std::wstring pchar_to_path(const char *c_str) { - std::wstring wstr; - if (c_str && *c_str) { - const int chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, c_str, - int(strlen(c_str)), nullptr, 0); - if (chars == 0) - mdbx::error::throw_exception(GetLastError()); - wstr.append(chars, '\0'); - MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, c_str, - int(strlen(c_str)), const_cast(wstr.data()), - chars); - } - return wstr; -} - -#endif /* Windows */ - } // namespace //------------------------------------------------------------------------------ @@ -3776,6 +4272,10 @@ namespace mdbx { "into an incompatible memory allocation scheme."); } +[[noreturn]] __cold void throw_bad_value_size() { + throw bad_value_size(MDBX_BAD_VALSIZE); +} + __cold exception::exception(const ::mdbx::error &error) noexcept : base(error.what()), error_(error) {} @@ -3824,7 +4324,7 @@ DEFINE_EXCEPTION(something_busy) DEFINE_EXCEPTION(thread_mismatch) DEFINE_EXCEPTION(transaction_full) DEFINE_EXCEPTION(transaction_overlapping) - +DEFINE_EXCEPTION(duplicated_lck_file) #undef DEFINE_EXCEPTION __cold const char *error::what() const noexcept { @@ -3910,6 +4410,7 @@ __cold void error::throw_exception() const { CASE_EXCEPTION(thread_mismatch, MDBX_THREAD_MISMATCH); CASE_EXCEPTION(transaction_full, MDBX_TXN_FULL); CASE_EXCEPTION(transaction_overlapping, MDBX_TXN_OVERLAPPING); + CASE_EXCEPTION(duplicated_lck_file, MDBX_DUPLICATED_CLK); #undef CASE_EXCEPTION default: if (is_mdbx_error()) @@ -4026,6 +4527,109 @@ bool slice::is_printable(bool disable_utf8) const noexcept { return true; } +#ifdef MDBX_U128_TYPE +MDBX_U128_TYPE slice::as_uint128() const { + static_assert(sizeof(MDBX_U128_TYPE) == 16, "WTF?"); + if (size() == 16) { + MDBX_U128_TYPE r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_uint64(); +} +#endif /* MDBX_U128_TYPE */ + +uint64_t slice::as_uint64() const { + static_assert(sizeof(uint64_t) == 8, "WTF?"); + if (size() == 8) { + uint64_t r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_uint32(); +} + +uint32_t slice::as_uint32() const { + static_assert(sizeof(uint32_t) == 4, "WTF?"); + if (size() == 4) { + uint32_t r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_uint16(); +} + +uint16_t slice::as_uint16() const { + static_assert(sizeof(uint16_t) == 2, "WTF?"); + if (size() == 2) { + uint16_t r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_uint8(); +} + +uint8_t slice::as_uint8() const { + static_assert(sizeof(uint8_t) == 1, "WTF?"); + if (size() == 1) + return *static_cast(data()); + else if (size() == 0) + return 0; + else + MDBX_CXX20_UNLIKELY throw_bad_value_size(); +} + +#ifdef MDBX_I128_TYPE +MDBX_I128_TYPE slice::as_int128() const { + static_assert(sizeof(MDBX_I128_TYPE) == 16, "WTF?"); + if (size() == 16) { + MDBX_I128_TYPE r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_int64(); +} +#endif /* MDBX_I128_TYPE */ + +int64_t slice::as_int64() const { + static_assert(sizeof(int64_t) == 8, "WTF?"); + if (size() == 8) { + uint64_t r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_int32(); +} + +int32_t slice::as_int32() const { + static_assert(sizeof(int32_t) == 4, "WTF?"); + if (size() == 4) { + int32_t r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_int16(); +} + +int16_t slice::as_int16() const { + static_assert(sizeof(int16_t) == 2, "WTF?"); + if (size() == 2) { + int16_t r; + memcpy(&r, data(), sizeof(r)); + return r; + } else + return as_int8(); +} + +int8_t slice::as_int8() const { + if (size() == 1) + return *static_cast(data()); + else if (size() == 0) + return 0; + else + MDBX_CXX20_UNLIKELY throw_bad_value_size(); +} + //------------------------------------------------------------------------------ char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const { @@ -4730,31 +5334,14 @@ bool env::is_pristine() const { bool env::is_empty() const { return get_stat().ms_leaf_pages == 0; } -#ifdef MDBX_STD_FILESYSTEM_PATH -env &env::copy(const MDBX_STD_FILESYSTEM_PATH &destination, bool compactify, - bool force_dynamic_size) { - const path_to_pchar utf8(destination); - error::success_or_throw( - ::mdbx_env_copy(handle_, utf8, - (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) | - (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE - : MDBX_CP_DEFAULTS))); - return *this; -} -#endif /* MDBX_STD_FILESYSTEM_PATH */ - -#if defined(_WIN32) || defined(_WIN64) -env &env::copy(const ::std::wstring &destination, bool compactify, - bool force_dynamic_size) { - const path_to_pchar<::std::wstring> utf8(destination); +env &env::copy(filehandle fd, bool compactify, bool force_dynamic_size) { error::success_or_throw( - ::mdbx_env_copy(handle_, utf8, - (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) | - (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE - : MDBX_CP_DEFAULTS))); + ::mdbx_env_copy2fd(handle_, fd, + (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) | + (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE + : MDBX_CP_DEFAULTS))); return *this; } -#endif /* Windows */ env &env::copy(const char *destination, bool compactify, bool force_dynamic_size) { @@ -4771,37 +5358,43 @@ env &env::copy(const ::std::string &destination, bool compactify, return copy(destination.c_str(), compactify, force_dynamic_size); } -env &env::copy(filehandle fd, bool compactify, bool force_dynamic_size) { +#if defined(_WIN32) || defined(_WIN64) +env &env::copy(const wchar_t *destination, bool compactify, + bool force_dynamic_size) { error::success_or_throw( - ::mdbx_env_copy2fd(handle_, fd, - (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) | - (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE - : MDBX_CP_DEFAULTS))); + ::mdbx_env_copyW(handle_, destination, + (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) | + (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE + : MDBX_CP_DEFAULTS))); return *this; } -path env::get_path() const { - const char *c_str; - error::success_or_throw(::mdbx_env_get_path(handle_, &c_str)); - return pchar_to_path(c_str); +env &env::copy(const ::std::wstring &destination, bool compactify, + bool force_dynamic_size) { + return copy(destination.c_str(), compactify, force_dynamic_size); } +#endif /* Windows */ #ifdef MDBX_STD_FILESYSTEM_PATH -bool env::remove(const MDBX_STD_FILESYSTEM_PATH &pathname, - const remove_mode mode) { - const path_to_pchar utf8(pathname); - return error::boolean_or_throw( - ::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode))); +env &env::copy(const MDBX_STD_FILESYSTEM_PATH &destination, bool compactify, + bool force_dynamic_size) { + return copy(destination.native(), compactify, force_dynamic_size); } #endif /* MDBX_STD_FILESYSTEM_PATH */ +path env::get_path() const { #if defined(_WIN32) || defined(_WIN64) -bool env::remove(const ::std::wstring &pathname, const remove_mode mode) { - const path_to_pchar<::std::wstring> utf8(pathname); - return error::boolean_or_throw( - ::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode))); + const wchar_t *c_wstr; + error::success_or_throw(::mdbx_env_get_pathW(handle_, &c_wstr)); + static_assert(sizeof(path::value_type) == sizeof(wchar_t), "Oops"); + return path(c_wstr); +#else + const char *c_str; + error::success_or_throw(::mdbx_env_get_path(handle_, &c_str)); + static_assert(sizeof(path::value_type) == sizeof(char), "Oops"); + return path(c_str); +#endif } -#endif /* Windows */ bool env::remove(const char *pathname, const remove_mode mode) { return error::boolean_or_throw( @@ -4812,6 +5405,24 @@ bool env::remove(const ::std::string &pathname, const remove_mode mode) { return remove(pathname.c_str(), mode); } +#if defined(_WIN32) || defined(_WIN64) +bool env::remove(const wchar_t *pathname, const remove_mode mode) { + return error::boolean_or_throw( + ::mdbx_env_deleteW(pathname, MDBX_env_delete_mode_t(mode))); +} + +bool env::remove(const ::std::wstring &pathname, const remove_mode mode) { + return remove(pathname.c_str(), mode); +} +#endif /* Windows */ + +#ifdef MDBX_STD_FILESYSTEM_PATH +bool env::remove(const MDBX_STD_FILESYSTEM_PATH &pathname, + const remove_mode mode) { + return remove(pathname.native(), mode); +} +#endif /* MDBX_STD_FILESYSTEM_PATH */ + //------------------------------------------------------------------------------ static inline MDBX_env *create_env() { @@ -4848,87 +5459,62 @@ __cold void env_managed::setup(unsigned max_maps, unsigned max_readers) { error::success_or_throw(::mdbx_env_set_maxdbs(handle_, max_maps)); } -#ifdef MDBX_STD_FILESYSTEM_PATH -__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname, +__cold env_managed::env_managed(const char *pathname, const operate_parameters &op, bool accede) : env_managed(create_env()) { setup(op.max_maps, op.max_readers); - const path_to_pchar utf8(pathname); error::success_or_throw( - ::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0)); + ::mdbx_env_open(handle_, pathname, op.make_flags(accede), 0)); if (op.options.nested_write_transactions && !get_options().nested_write_transactions) MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE); } -__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname, +__cold env_managed::env_managed(const char *pathname, const env_managed::create_parameters &cp, const env::operate_parameters &op, bool accede) : env_managed(create_env()) { setup(op.max_maps, op.max_readers); - const path_to_pchar utf8(pathname); set_geometry(cp.geometry); - error::success_or_throw( - ::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory), - cp.file_mode_bits)); + error::success_or_throw(::mdbx_env_open( + handle_, pathname, op.make_flags(accede, cp.use_subdirectory), + cp.file_mode_bits)); if (op.options.nested_write_transactions && !get_options().nested_write_transactions) MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE); } -#endif /* MDBX_STD_FILESYSTEM_PATH */ -#if defined(_WIN32) || defined(_WIN64) -__cold env_managed::env_managed(const ::std::wstring &pathname, +__cold env_managed::env_managed(const ::std::string &pathname, const operate_parameters &op, bool accede) - : env_managed(create_env()) { - setup(op.max_maps, op.max_readers); - const path_to_pchar<::std::wstring> utf8(pathname); - error::success_or_throw( - ::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0)); - - if (op.options.nested_write_transactions && - !get_options().nested_write_transactions) - MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE); -} + : env_managed(pathname.c_str(), op, accede) {} -__cold env_managed::env_managed(const ::std::wstring &pathname, +__cold env_managed::env_managed(const ::std::string &pathname, const env_managed::create_parameters &cp, const env::operate_parameters &op, bool accede) - : env_managed(create_env()) { - setup(op.max_maps, op.max_readers); - const path_to_pchar<::std::wstring> utf8(pathname); - set_geometry(cp.geometry); - error::success_or_throw( - ::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory), - cp.file_mode_bits)); - - if (op.options.nested_write_transactions && - !get_options().nested_write_transactions) - MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE); -} -#endif /* Windows */ + : env_managed(pathname.c_str(), cp, op, accede) {} -__cold env_managed::env_managed(const char *pathname, +#if defined(_WIN32) || defined(_WIN64) +__cold env_managed::env_managed(const wchar_t *pathname, const operate_parameters &op, bool accede) : env_managed(create_env()) { setup(op.max_maps, op.max_readers); error::success_or_throw( - ::mdbx_env_open(handle_, pathname, op.make_flags(accede), 0)); + ::mdbx_env_openW(handle_, pathname, op.make_flags(accede), 0)); if (op.options.nested_write_transactions && !get_options().nested_write_transactions) MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE); } -__cold env_managed::env_managed(const char *pathname, +__cold env_managed::env_managed(const wchar_t *pathname, const env_managed::create_parameters &cp, const env::operate_parameters &op, bool accede) : env_managed(create_env()) { setup(op.max_maps, op.max_readers); set_geometry(cp.geometry); - error::success_or_throw(::mdbx_env_open( + error::success_or_throw(::mdbx_env_openW( handle_, pathname, op.make_flags(accede, cp.use_subdirectory), cp.file_mode_bits)); @@ -4937,14 +5523,26 @@ __cold env_managed::env_managed(const char *pathname, MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE); } -__cold env_managed::env_managed(const ::std::string &pathname, +__cold env_managed::env_managed(const ::std::wstring &pathname, const operate_parameters &op, bool accede) : env_managed(pathname.c_str(), op, accede) {} -__cold env_managed::env_managed(const ::std::string &pathname, +__cold env_managed::env_managed(const ::std::wstring &pathname, const env_managed::create_parameters &cp, const env::operate_parameters &op, bool accede) : env_managed(pathname.c_str(), cp, op, accede) {} +#endif /* Windows */ + +#ifdef MDBX_STD_FILESYSTEM_PATH +__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname, + const operate_parameters &op, bool accede) + : env_managed(pathname.native(), op, accede) {} + +__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname, + const env_managed::create_parameters &cp, + const env::operate_parameters &op, bool accede) + : env_managed(pathname.native(), cp, op, accede) {} +#endif /* MDBX_STD_FILESYSTEM_PATH */ //------------------------------------------------------------------------------ @@ -4979,6 +5577,15 @@ void txn_managed::commit() { MDBX_CXX20_UNLIKELY err.throw_exception(); } +void txn_managed::commit(commit_latency *latency) { + const error err = + static_cast(::mdbx_txn_commit_ex(handle_, latency)); + if (MDBX_LIKELY(err.code() != MDBX_THREAD_MISMATCH)) + MDBX_CXX20_LIKELY handle_ = nullptr; + if (MDBX_UNLIKELY(err.code() != MDBX_SUCCESS)) + MDBX_CXX20_UNLIKELY err.throw_exception(); +} + //------------------------------------------------------------------------------ bool txn::drop_map(const char *name, bool throw_if_absent) { diff --git a/mdbxdist/mdbx.h b/mdbxdist/mdbx.h index cc42298..ece77ed 100644 --- a/mdbxdist/mdbx.h +++ b/mdbxdist/mdbx.h @@ -1876,7 +1876,8 @@ enum MDBX_error_t { MDBX_BAD_RSLOT = -30783, /** Transaction is not valid for requested operation, - * e.g. had errored and be must aborted, has a child, or is invalid */ + * e.g. had errored and be must aborted, has a child/nested transaction, + * or is invalid */ MDBX_BAD_TXN = -30782, /** Invalid size or alignment of key or data for target database, @@ -1936,7 +1937,7 @@ enum MDBX_error_t { MDBX_DUPLICATED_CLK = -30413, /* The last of MDBX-added error codes */ - MDBX_LAST_ADDED_ERRCODE = MDBX_TXN_OVERLAPPING, + MDBX_LAST_ADDED_ERRCODE = MDBX_DUPLICATED_CLK, #if defined(_WIN32) || defined(_WIN64) MDBX_ENODATA = ERROR_HANDLE_EOF, @@ -2699,11 +2700,12 @@ MDBX_DEPRECATED LIBMDBX_INLINE_API(int, mdbx_env_info, * success. The \ref MDBX_RESULT_TRUE means no data pending for flush * to disk, and 0 otherwise. Some possible errors are: * - * \retval MDBX_EACCES the environment is read-only. - * \retval MDBX_BUSY the environment is used by other thread + * \retval MDBX_EACCES The environment is read-only. + * \retval MDBX_BUSY The environment is used by other thread * and `nonblock=true`. - * \retval MDBX_EINVAL an invalid parameter was specified. - * \retval MDBX_EIO an error occurred during synchronization. */ + * \retval MDBX_EINVAL An invalid parameter was specified. + * \retval MDBX_EIO An error occurred during the flushing/writing data + * to a storage medium/disk. */ LIBMDBX_API int mdbx_env_sync_ex(MDBX_env *env, bool force, bool nonblock); /** \brief The shortcut to calling \ref mdbx_env_sync_ex() with @@ -2846,9 +2848,9 @@ LIBMDBX_INLINE_API(int, mdbx_env_get_syncperiod, * * Only a single thread may call this function. All transactions, databases, * and cursors must already be closed before calling this function. Attempts - * to use any such handles after calling this function will cause a `SIGSEGV`. - * The environment handle will be freed and must not be used again after this - * call. + * to use any such handles after calling this function is UB and would cause + * a `SIGSEGV`. The environment handle will be freed and must not be used again + * after this call. * * \param [in] env An environment handle returned by * \ref mdbx_env_create(). @@ -2878,7 +2880,8 @@ LIBMDBX_INLINE_API(int, mdbx_env_get_syncperiod, * is expected, i.e. \ref MDBX_env instance was freed in * proper manner. * - * \retval MDBX_EIO An error occurred during synchronization. */ + * \retval MDBX_EIO An error occurred during the flushing/writing data + * to a storage medium/disk. */ LIBMDBX_API int mdbx_env_close_ex(MDBX_env *env, bool dont_sync); /** \brief The shortcut to calling \ref mdbx_env_close_ex() with @@ -3918,7 +3921,8 @@ LIBMDBX_API int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency); * by current thread. * \retval MDBX_EINVAL Transaction handle is NULL. * \retval MDBX_ENOSPC No more disk space. - * \retval MDBX_EIO A system-level I/O error occurred. + * \retval MDBX_EIO An error occurred during the flushing/writing + * data to a storage medium/disk. * \retval MDBX_ENOMEM Out of memory. */ LIBMDBX_INLINE_API(int, mdbx_txn_commit, (MDBX_txn * txn)) { return mdbx_txn_commit_ex(txn, NULL); @@ -4031,7 +4035,7 @@ LIBMDBX_API int mdbx_txn_renew(MDBX_txn *txn); /** \brief The fours integers markers (aka "canary") associated with the * environment. * \ingroup c_crud - * \see mdbx_canary_set() + * \see mdbx_canary_put() * \see mdbx_canary_get() * * The `x`, `y` and `z` values could be set by \ref mdbx_canary_put(), while the @@ -4069,10 +4073,10 @@ LIBMDBX_API int mdbx_canary_put(MDBX_txn *txn, const MDBX_canary *canary); /** \brief Returns fours integers markers (aka "canary") associated with the * environment. * \ingroup c_crud - * \see mdbx_canary_set() + * \see mdbx_canary_put() * * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). - * \param [in] canary The address of an MDBX_canary structure where the + * \param [in] canary The address of an \ref MDBX_canary structure where the * information will be copied. * * \returns A non-zero error value on failure and 0 on success. */ @@ -4084,9 +4088,9 @@ LIBMDBX_API int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary); * \see mdbx_get_datacmp \see mdbx_dcmp() * * \anchor avoid_custom_comparators - * It is recommend not using custom comparison functions, but instead - * converting the keys to one of the forms that are suitable for built-in - * comparators (for instance take look to the \ref value2key). + * \deprecated It is recommend not using custom comparison functions, but + * instead converting the keys to one of the forms that are suitable for + * built-in comparators (for instance take look to the \ref value2key). * The reasons to not using custom comparators are: * - The order of records could not be validated without your code. * So `mdbx_chk` utility will reports "wrong order" errors @@ -4316,7 +4320,7 @@ LIBMDBX_API int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi, enum MDBX_dbi_state_t { /** DB was written in this txn */ MDBX_DBI_DIRTY = 0x01, - /** Named-DB record is older than txnID */ + /** Cached Named-DB record is older than txnID */ MDBX_DBI_STALE = 0x02, /** Named-DB handle opened in this txn */ MDBX_DBI_FRESH = 0x04, @@ -4398,9 +4402,14 @@ LIBMDBX_API int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, bool del); * items requires the use of \ref mdbx_cursor_get(). * * \note The memory pointed to by the returned values is owned by the - * database. The caller need not dispose of the memory, and may not - * modify it in any way. For values returned in a read-only transaction - * any modification attempts will cause a `SIGSEGV`. + * database. The caller MUST not dispose of the memory, and MUST not modify it + * in any way regardless in a read-only nor read-write transactions! + * For case a database opened without the \ref MDBX_WRITEMAP modification + * attempts likely will cause a `SIGSEGV`. However, when a database opened with + * the \ref MDBX_WRITEMAP or in case values returned inside read-write + * transaction are located on a "dirty" (modified and pending to commit) pages, + * such modification will silently accepted and likely will lead to DB and/or + * data corruption. * * \note Values returned from the database are valid only until a * subsequent update operation, or the end of the transaction. @@ -4650,7 +4659,7 @@ LIBMDBX_API int mdbx_replace_ex(MDBX_txn *txn, MDBX_dbi dbi, LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, const MDBX_val *data); -/** \brief Create a cursor handle but not bind it to transaction nor DBI handle. +/** \brief Create a cursor handle but not bind it to transaction nor DBI-handle. * \ingroup c_cursors * * A cursor cannot be used when its database handle is closed. Nor when its @@ -4674,7 +4683,7 @@ LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, * \returns Created cursor handle or NULL in case out of memory. */ LIBMDBX_API MDBX_cursor *mdbx_cursor_create(void *context); -/** \brief Set application information associated with the \ref MDBX_cursor. +/** \brief Set application information associated with the cursor. * \ingroup c_cursors * \see mdbx_cursor_get_userctx() * @@ -4697,11 +4706,11 @@ LIBMDBX_API int mdbx_cursor_set_userctx(MDBX_cursor *cursor, void *ctx); MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void * mdbx_cursor_get_userctx(const MDBX_cursor *cursor); -/** \brief Bind cursor to specified transaction and DBI handle. +/** \brief Bind cursor to specified transaction and DBI-handle. * \ingroup c_cursors * * Using of the `mdbx_cursor_bind()` is equivalent to calling - * \ref mdbx_cursor_renew() but with specifying an arbitrary dbi handle. + * \ref mdbx_cursor_renew() but with specifying an arbitrary DBI-handle. * * A cursor may be associated with a new transaction, and referencing a new or * the same database handle as it was created with. This may be done whether the @@ -4715,7 +4724,7 @@ mdbx_cursor_get_userctx(const MDBX_cursor *cursor); * * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). * \param [in] dbi A database handle returned by \ref mdbx_dbi_open(). - * \param [out] cursor A cursor handle returned by \ref mdbx_cursor_create(). + * \param [in] cursor A cursor handle returned by \ref mdbx_cursor_create(). * * \returns A non-zero error value on failure and 0 on success, * some possible errors are: @@ -4774,15 +4783,14 @@ LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, * or \ref mdbx_cursor_create(). */ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); -/** \brief Renew a cursor handle. +/** \brief Renew a cursor handle for use within the given transaction. * \ingroup c_cursors * - * The cursor may be associated with a new transaction, and referencing a new or - * the same database handle as it was created with. This may be done whether the - * previous transaction is live or dead. + * A cursor may be associated with a new transaction whether the previous + * transaction is running or finished. * * Using of the `mdbx_cursor_renew()` is equivalent to calling - * \ref mdbx_cursor_bind() with the DBI handle that previously + * \ref mdbx_cursor_bind() with the DBI-handle that previously * the cursor was used with. * * \note In contrast to LMDB, the MDBX allow any cursor to be re-used by using @@ -4796,7 +4804,9 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. - * \retval MDBX_EINVAL An invalid parameter was specified. */ + * \retval MDBX_EINVAL An invalid parameter was specified. + * \retval MDBX_BAD_DBI The cursor was not bound to a DBI-handle + * or such a handle became invalid. */ LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor); /** \brief Return the cursor's transaction handle. @@ -4834,6 +4844,16 @@ LIBMDBX_API int mdbx_cursor_copy(const MDBX_cursor *src, MDBX_cursor *dest); * to which data refers. * \see mdbx_get() * + * \note The memory pointed to by the returned values is owned by the + * database. The caller MUST not dispose of the memory, and MUST not modify it + * in any way regardless in a read-only nor read-write transactions! + * For case a database opened without the \ref MDBX_WRITEMAP modification + * attempts likely will cause a `SIGSEGV`. However, when a database opened with + * the \ref MDBX_WRITEMAP or in case values returned inside read-write + * transaction are located on a "dirty" (modified and pending to commit) pages, + * such modification will silently accepted and likely will lead to DB and/or + * data corruption. + * * \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open(). * \param [in,out] key The key for a retrieved item. * \param [in,out] data The data of a retrieved item. @@ -4860,6 +4880,16 @@ LIBMDBX_API int mdbx_cursor_get(MDBX_cursor *cursor, MDBX_val *key, * array to which `pairs` refers. * \see mdbx_cursor_get() * + * \note The memory pointed to by the returned values is owned by the + * database. The caller MUST not dispose of the memory, and MUST not modify it + * in any way regardless in a read-only nor read-write transactions! + * For case a database opened without the \ref MDBX_WRITEMAP modification + * attempts likely will cause a `SIGSEGV`. However, when a database opened with + * the \ref MDBX_WRITEMAP or in case values returned inside read-write + * transaction are located on a "dirty" (modified and pending to commit) pages, + * such modification will silently accepted and likely will lead to DB and/or + * data corruption. + * * \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open(). * \param [out] count The number of key and value item returned, on success * it always be the even because the key-value diff --git a/mdbxdist/mdbx.h++ b/mdbxdist/mdbx.h++ index 64143c4..d4cd707 100644 --- a/mdbxdist/mdbx.h++ +++ b/mdbxdist/mdbx.h++ @@ -1,7 +1,7 @@ /// \file mdbx.h++ /// \brief The libmdbx C++ API header file. /// -/// \author Copyright (c) 2020-2022, Leonid Yuriev . +/// \author Copyright (c) 2020-2023, Leonid Yuriev . /// \copyright SPDX-License-Identifier: Apache-2.0 /// /// Tested with: @@ -80,10 +80,16 @@ #if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L #include -#elif __has_include() +#elif defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L && \ + __has_include() #include #endif +#if __cplusplus >= 201103L +#include +#include +#endif + #include "mdbx.h" #if (defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L) || \ @@ -223,17 +229,18 @@ #endif /* MDBX_CXX20_UNLIKELY */ #ifndef MDBX_HAVE_CXX20_CONCEPTS -#if defined(DOXYGEN) || \ - (defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L) +#if defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L #include #define MDBX_HAVE_CXX20_CONCEPTS 1 +#elif defined(DOXYGEN) +#define MDBX_HAVE_CXX20_CONCEPTS 1 #else #define MDBX_HAVE_CXX20_CONCEPTS 0 #endif /* */ #endif /* MDBX_HAVE_CXX20_CONCEPTS */ #ifndef MDBX_CXX20_CONCEPT -#if MDBX_HAVE_CXX20_CONCEPTS +#if MDBX_HAVE_CXX20_CONCEPTS || defined(DOXYGEN) #define MDBX_CXX20_CONCEPT(CONCEPT, NAME) CONCEPT NAME #else #define MDBX_CXX20_CONCEPT(CONCEPT, NAME) typename NAME @@ -241,7 +248,7 @@ #endif /* MDBX_CXX20_CONCEPT */ #ifndef MDBX_ASSERT_CXX20_CONCEPT_SATISFIED -#if MDBX_HAVE_CXX20_CONCEPTS +#if MDBX_HAVE_CXX20_CONCEPTS || defined(DOXYGEN) #define MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(CONCEPT, TYPE) \ static_assert(CONCEPT) #else @@ -287,7 +294,7 @@ namespace mdbx { // To enable all kinds of an compiler optimizations we use a byte-like type // that don't presumes aliases for pointers as does the `char` type and its // derivatives/typedefs. -// Please see todo4recovery://erased_by_github/libmdbx/issues/263 +// Please see https://libmdbx.dqdkfa.ru/dead-github/issues/263 // for reasoning of the use of `char8_t` type and switching to `__restrict__`. using byte = char8_t; #else @@ -350,6 +357,9 @@ class cursor_managed; __cpp_lib_memory_resource >= 201603L && _GLIBCXX_USE_CXX11_ABI) /// \brief Default polymorphic allocator for modern code. using polymorphic_allocator = ::std::pmr::string::allocator_type; +using default_allocator = polymorphic_allocator; +#else +using default_allocator = legacy_allocator; #endif /* __cpp_lib_memory_resource >= 201603L */ /// \brief Default singe-byte string. @@ -359,6 +369,7 @@ using string = ::std::basic_string, ALLOCATOR>; using filehandle = ::mdbx_filehandle_t; #if defined(DOXYGEN) || \ (defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \ + defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L && \ (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || \ __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) && \ (!defined(__IPHONE_OS_VERSION_MIN_REQUIRED) || \ @@ -385,6 +396,21 @@ using path = ::std::wstring; using path = ::std::string; #endif /* mdbx::path */ +#if defined(__SIZEOF_INT128__) || \ + (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) +#ifndef MDBX_U128_TYPE +#define MDBX_U128_TYPE __uint128_t +#endif /* MDBX_U128_TYPE */ +#ifndef MDBX_I128_TYPE +#define MDBX_I128_TYPE __int128_t +#endif /* MDBX_I128_TYPE */ +#endif /* __SIZEOF_INT128__ || _INTEGRAL_MAX_BITS >= 128 */ + +#if __cplusplus >= 201103L || defined(DOXYGEN) +/// \brief Duration in 1/65536 units of second. +using duration = ::std::chrono::duration>; +#endif /* Duration for C++11 */ + /// \defgroup cxx_exceptions exceptions and errors /// @{ @@ -532,12 +558,14 @@ MDBX_DECLARE_EXCEPTION(something_busy); MDBX_DECLARE_EXCEPTION(thread_mismatch); MDBX_DECLARE_EXCEPTION(transaction_full); MDBX_DECLARE_EXCEPTION(transaction_overlapping); +MDBX_DECLARE_EXCEPTION(duplicated_lck_file); #undef MDBX_DECLARE_EXCEPTION [[noreturn]] LIBMDBX_API void throw_too_small_target_buffer(); [[noreturn]] LIBMDBX_API void throw_max_length_exceeded(); [[noreturn]] LIBMDBX_API void throw_out_range(); [[noreturn]] LIBMDBX_API void throw_allocators_mismatch(); +[[noreturn]] LIBMDBX_API void throw_bad_value_size(); static MDBX_CXX14_CONSTEXPR size_t check_length(size_t bytes); static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom, size_t payload); @@ -551,8 +579,11 @@ static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom, size_t payload, /// \defgroup cxx_data slices and buffers /// @{ -#if MDBX_HAVE_CXX20_CONCEPTS +#if MDBX_HAVE_CXX20_CONCEPTS || defined(DOXYGEN) +/** \concept MutableByteProducer + * \interface MutableByteProducer + * \brief MutableByteProducer C++20 concept */ template concept MutableByteProducer = requires(T a, char array[42]) { { a.is_empty() } -> std::same_as; @@ -560,6 +591,9 @@ concept MutableByteProducer = requires(T a, char array[42]) { { a.write_bytes(&array[0], size_t(42)) } -> std::same_as; }; +/** \concept ImmutableByteProducer + * \interface ImmutableByteProducer + * \brief ImmutableByteProducer C++20 concept */ template concept ImmutableByteProducer = requires(const T &a, char array[42]) { { a.is_empty() } -> std::same_as; @@ -567,12 +601,15 @@ concept ImmutableByteProducer = requires(const T &a, char array[42]) { { a.write_bytes(&array[0], size_t(42)) } -> std::same_as; }; +/** \concept SliceTranscoder + * \interface SliceTranscoder + * \brief SliceTranscoder C++20 concept */ template -concept SliceTranscoder = ImmutableByteProducer && - requires(const slice &source, const T &a) { - T(source); - { a.is_erroneous() } -> std::same_as; -}; +concept SliceTranscoder = + ImmutableByteProducer && requires(const slice &source, const T &a) { + T(source); + { a.is_erroneous() } -> std::same_as; + }; #endif /* MDBX_HAVE_CXX20_CONCEPTS */ @@ -1006,6 +1043,35 @@ struct LIBMDBX_API_TYPE slice : public ::MDBX_val { return slice(size_t(-1)); } + template MDBX_CXX14_CONSTEXPR POD as_pod() const { + static_assert(::std::is_standard_layout::value && + !::std::is_pointer::value, + "Must be a standard layout type!"); + if (MDBX_LIKELY(size() == sizeof(POD))) + MDBX_CXX20_LIKELY { + POD r; + memcpy(&r, data(), sizeof(r)); + return r; + } + throw_bad_value_size(); + } + +#ifdef MDBX_U128_TYPE + MDBX_U128_TYPE as_uint128() const; +#endif /* MDBX_U128_TYPE */ + uint64_t as_uint64() const; + uint32_t as_uint32() const; + uint16_t as_uint16() const; + uint8_t as_uint8() const; + +#ifdef MDBX_I128_TYPE + MDBX_I128_TYPE as_int128() const; +#endif /* MDBX_I128_TYPE */ + int64_t as_int64() const; + int32_t as_int32() const; + int16_t as_int16() const; + int8_t as_int8() const; + protected: MDBX_CXX11_CONSTEXPR slice(size_t invalid_length) noexcept : ::MDBX_val({nullptr, invalid_length}) {} @@ -2269,6 +2335,10 @@ public: return buffer(::mdbx::slice::wrap(pod), make_reference, allocator); } + template MDBX_CXX14_CONSTEXPR POD as_pod() const { + return slice_.as_pod(); + } + /// \brief Reserves storage space. void reserve(size_t wanna_headroom, size_t wanna_tailroom) { wanna_headroom = ::std::min(::std::max(headroom(), wanna_headroom), @@ -2639,45 +2709,69 @@ public: return buffer(src, make_reference); } - static buffer key_from(const silo &&src) noexcept { + static buffer key_from(silo &&src) noexcept { return buffer(::std::move(src)); } - static buffer key_from(const double ieee754_64bit) { + static buffer key_from_double(const double ieee754_64bit) { return wrap(::mdbx_key_from_double(ieee754_64bit)); } + static buffer key_from(const double ieee754_64bit) { + return key_from_double(ieee754_64bit); + } + static buffer key_from(const double *ieee754_64bit) { return wrap(::mdbx_key_from_ptrdouble(ieee754_64bit)); } - static buffer key_from(const uint64_t unsigned_int64) { + static buffer key_from_u64(const uint64_t unsigned_int64) { return wrap(unsigned_int64); } - static buffer key_from(const int64_t signed_int64) { + static buffer key_from(const uint64_t unsigned_int64) { + return key_from_u64(unsigned_int64); + } + + static buffer key_from_i64(const int64_t signed_int64) { return wrap(::mdbx_key_from_int64(signed_int64)); } + static buffer key_from(const int64_t signed_int64) { + return key_from_i64(signed_int64); + } + static buffer key_from_jsonInteger(const int64_t json_integer) { return wrap(::mdbx_key_from_jsonInteger(json_integer)); } - static buffer key_from(const float ieee754_32bit) { + static buffer key_from_float(const float ieee754_32bit) { return wrap(::mdbx_key_from_float(ieee754_32bit)); } + static buffer key_from(const float ieee754_32bit) { + return key_from_float(ieee754_32bit); + } + static buffer key_from(const float *ieee754_32bit) { return wrap(::mdbx_key_from_ptrfloat(ieee754_32bit)); } - static buffer key_from(const uint32_t unsigned_int32) { + static buffer key_from_u32(const uint32_t unsigned_int32) { return wrap(unsigned_int32); } - static buffer key_from(const int32_t signed_int32) { + static buffer key_from(const uint32_t unsigned_int32) { + return key_from_u32(unsigned_int32); + } + + static buffer key_from_i32(const int32_t signed_int32) { return wrap(::mdbx_key_from_int32(signed_int32)); } + + static buffer key_from(const int32_t signed_int32) { + return key_from_i32(signed_int32); + } }; template = 201103L || defined(DOXYGEN) /// \brief Sets relative period since the last unsteady commit to force flush /// the data buffers to disk, for non-sync durability modes. /// - /// The relative period value affects all processes which operates with given - /// environment until the last process close environment or a new value will - /// be settled. - /// Data is always written to disk when \ref txn_managed::commit() is called, - /// but the operating system may keep it buffered. MDBX always flushes the OS - /// buffers upon commit as well, unless the environment was opened with \ref - /// whole_fragile, \ref lazy_weak_tail or in part \ref - /// half_synchronous_weak_last. Settled period don't checked asynchronously, - /// but only by the \ref txn_managed::commit() and \ref env::sync_to_disk() - /// functions. Therefore, in cases where transactions are committed - /// infrequently and/or irregularly, polling by \ref env::poll_sync_to_disk() - /// may be a reasonable solution to timeout enforcement. The default is 0, - /// than mean no any timeout checked, and no additional flush will be made. + /// \details The relative period value affects all processes which operates + /// with given environment until the last process close environment or a new + /// value will be settled. Data is always written to disk when \ref + /// txn_managed::commit() is called, but the operating system may keep it + /// buffered. MDBX always flushes the OS buffers upon commit as well, unless + /// the environment was opened with \ref whole_fragile, \ref lazy_weak_tail or + /// in part \ref half_synchronous_weak_last. Settled period don't checked + /// asynchronously, but only by the \ref txn_managed::commit() and \ref + /// env::sync_to_disk() functions. Therefore, in cases where transactions are + /// committed infrequently and/or irregularly, polling by \ref + /// env::poll_sync_to_disk() may be a reasonable solution to timeout + /// enforcement. /// + /// The default is 0, than mean no any timeout checked, and no additional + /// flush will be made. + /// \see extra_runtime_option::sync_period + inline env &set_sync_period(const duration &period); + + /// \brief Gets relative period since the last unsteady commit that used to + /// force flush the data buffers to disk, for non-sync durability modes. + /// \copydetails set_sync_period(const duration&) + /// \see set_sync_period(const duration&) + /// \see extra_runtime_option::sync_period + inline duration sync_period() const; +#endif + + /// \copydoc set_sync_period(const duration&) /// \param [in] seconds_16dot16 The period in 1/65536 of second when a /// synchronous flush would be made since the last unsteady commit. - inline env &set_sync_period(unsigned seconds_16dot16); + inline env &set_sync_period__seconds_16dot16(unsigned seconds_16dot16); - /// \brief Sets relative period since the last unsteady commit to force flush - /// the data buffers to disk, for non-sync durability modes. - /// - /// The relative period value affects all processes which operates with given - /// environment until the last process close environment or a new value will - /// be settled. - /// Data is always written to disk when \ref txn_managed::commit() is called, - /// but the operating system may keep it buffered. MDBX always flushes the OS - /// buffers upon commit as well, unless the environment was opened with \ref - /// whole_fragile, \ref lazy_weak_tail or in part \ref - /// half_synchronous_weak_last. Settled period don't checked asynchronously, - /// but only by the \ref txn_managed::commit() and \ref env::sync_to_disk() - /// functions. Therefore, in cases where transactions are committed - /// infrequently and/or irregularly, polling by \ref env::poll_sync_to_disk() - /// may be a reasonable solution to timeout enforcement. The default is 0, - /// than mean no any timeout checked, and no additional flush will be made. - /// + /// \copydoc sync_period() + /// \see sync_period__seconds_16dot16(unsigned) + inline unsigned sync_period__seconds_16dot16() const; + + /// \copydoc set_sync_period(const duration&) /// \param [in] seconds The period in second when a synchronous flush would /// be made since the last unsteady commit. - inline env &set_sync_period(double seconds); + inline env &set_sync_period__seconds_double(double seconds); + + /// \copydoc sync_period() + /// \see set_sync_period__seconds_double(double) + inline double sync_period__seconds_double() const; + + /// \copydoc MDBX_option_t + enum class extra_runtime_option { + /// \copydoc MDBX_opt_max_db + /// \see max_maps() \see env::operate_parameters::max_maps + max_maps = MDBX_opt_max_db, + /// \copydoc MDBX_opt_max_readers + /// \see max_readers() \see env::operate_parameters::max_readers + max_readers = MDBX_opt_max_readers, + /// \copydoc MDBX_opt_sync_bytes + /// \see sync_threshold() \see set_sync_threshold() + sync_bytes = MDBX_opt_sync_bytes, + /// \copydoc MDBX_opt_sync_period + /// \see sync_period() \see set_sync_period() + sync_period = MDBX_opt_sync_period, + /// \copydoc MDBX_opt_rp_augment_limit + rp_augment_limit = MDBX_opt_rp_augment_limit, + /// \copydoc MDBX_opt_loose_limit + loose_limit = MDBX_opt_loose_limit, + /// \copydoc MDBX_opt_dp_reserve_limit + dp_reserve_limit = MDBX_opt_dp_reserve_limit, + /// \copydoc MDBX_opt_txn_dp_limit + dp_limit = MDBX_opt_txn_dp_limit, + /// \copydoc MDBX_opt_txn_dp_initial + dp_initial = MDBX_opt_txn_dp_initial, + /// \copydoc MDBX_opt_spill_max_denominator + spill_max_denominator = MDBX_opt_spill_max_denominator, + /// \copydoc MDBX_opt_spill_min_denominator + spill_min_denominator = MDBX_opt_spill_min_denominator, + /// \copydoc MDBX_opt_spill_parent4child_denominator + spill_parent4child_denominator = MDBX_opt_spill_parent4child_denominator, + /// \copydoc MDBX_opt_merge_threshold_16dot16_percent + merge_threshold_16dot16_percent = MDBX_opt_merge_threshold_16dot16_percent, + /// \copydoc MDBX_opt_writethrough_threshold + writethrough_threshold = MDBX_opt_writethrough_threshold, + /// \copydoc MDBX_opt_prefault_write_enable + prefault_write_enable = MDBX_opt_prefault_write_enable, + }; + + /// \copybrief mdbx_env_set_option() + inline env &set_extra_option(extra_runtime_option option, uint64_t value); + + /// \copybrief mdbx_env_get_option() + inline uint64_t extra_option(extra_runtime_option option) const; /// \brief Alter environment flags. inline env &alter_flags(MDBX_env_flags_t flags, bool on_off); @@ -3416,7 +3610,7 @@ public: /// transactions since the current read /// transaction started. size_t bytes_used; ///< The number of last used page in the MVCC-snapshot - ///< which being read, i.e. database file can't shrinked + ///< which being read, i.e. database file can't be shrunk ///< beyond this. size_t bytes_retained; ///< The total size of the database pages that ///< were retired by committed write transactions @@ -3507,6 +3701,8 @@ public: #if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN) env_managed(const ::std::wstring &pathname, const operate_parameters &, bool accede = true); + explicit env_managed(const wchar_t *pathname, const operate_parameters &, + bool accede = true); #endif /* Windows */ env_managed(const ::std::string &pathname, const operate_parameters &, bool accede = true); @@ -3514,6 +3710,8 @@ public: bool accede = true); /// \brief Additional parameters for creating a new database. + /// \see env_managed(const ::std::string &pathname, const create_parameters &, + /// const operate_parameters &, bool accede) struct create_parameters { env::geometry geometry; mdbx_mode_t file_mode_bits{0640}; @@ -3531,6 +3729,8 @@ public: #if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN) env_managed(const ::std::wstring &pathname, const create_parameters &, const operate_parameters &, bool accede = true); + explicit env_managed(const wchar_t *pathname, const create_parameters &, + const operate_parameters &, bool accede = true); #endif /* Windows */ env_managed(const ::std::string &pathname, const create_parameters &, const operate_parameters &, bool accede = true); @@ -3553,7 +3753,7 @@ public: void close(bool dont_sync = false); env_managed(env_managed &&) = default; - env_managed &operator=(env_managed &&other) { + env_managed &operator=(env_managed &&other) noexcept { if (MDBX_UNLIKELY(handle_)) MDBX_CXX20_UNLIKELY { assert(handle_ != other.handle_); @@ -3822,10 +4022,20 @@ public: size_t values_count, put_mode mode, bool allow_partial = false); template + size_t put_multiple(map_handle map, const slice &key, + const VALUE *values_array, size_t values_count, + put_mode mode, bool allow_partial = false) { + static_assert(::std::is_standard_layout::value && + !::std::is_pointer::value && + !::std::is_array::value, + "Must be a standard layout type!"); + return put_multiple(map, key, sizeof(VALUE), values_array, values_count, + mode, allow_partial); + } + template void put_multiple(map_handle map, const slice &key, const ::std::vector &vector, put_mode mode) { - put_multiple(map, key, sizeof(VALUE), vector.data(), vector.size(), mode, - false); + put_multiple(map, key, vector.data(), vector.size(), mode); } inline ptrdiff_t estimate(map_handle map, pair from, pair to) const; @@ -3852,7 +4062,7 @@ class LIBMDBX_API_TYPE txn_managed : public txn { public: MDBX_CXX11_CONSTEXPR txn_managed() noexcept = default; txn_managed(txn_managed &&) = default; - txn_managed &operator=(txn_managed &&other) { + txn_managed &operator=(txn_managed &&other) noexcept { if (MDBX_UNLIKELY(handle_)) MDBX_CXX20_UNLIKELY { assert(handle_ != other.handle_); @@ -3867,12 +4077,31 @@ public: //---------------------------------------------------------------------------- - /// \brief Abandon all the operations of the transaction instead of saving - /// them. + /// \brief Abandon all the operations of the transaction + /// instead of saving ones. void abort(); /// \brief Commit all the operations of a transaction into the database. void commit(); + + using commit_latency = MDBX_commit_latency; + + /// \brief Commit all the operations of a transaction into the database + /// and collect latency information. + void commit(commit_latency *); + + /// \brief Commit all the operations of a transaction into the database + /// and collect latency information. + void commit(commit_latency &latency) { return commit(&latency); } + + /// \brief Commit all the operations of a transaction into the database + /// and return latency information. + /// \returns latency information of commit stages. + commit_latency commit_get_latency() { + commit_latency result; + commit(&result); + return result; + } }; /// \brief Unmanaged cursor. @@ -4055,7 +4284,7 @@ public: void close(); cursor_managed(cursor_managed &&) = default; - cursor_managed &operator=(cursor_managed &&other) { + cursor_managed &operator=(cursor_managed &&other) noexcept { if (MDBX_UNLIKELY(handle_)) MDBX_CXX20_UNLIKELY { assert(handle_ != other.handle_); @@ -4855,6 +5084,56 @@ inline size_t env::limits::value_max(const env &env, value_mode mode) { return value_max(env, MDBX_db_flags_t(mode)); } +inline size_t env::limits::pairsize4page_max(intptr_t pagesize, + MDBX_db_flags_t flags) { + const intptr_t result = mdbx_limits_pairsize4page_max(pagesize, flags); + if (result < 0) + MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL); + return static_cast(result); +} + +inline size_t env::limits::pairsize4page_max(intptr_t pagesize, + value_mode mode) { + return pairsize4page_max(pagesize, MDBX_db_flags_t(mode)); +} + +inline size_t env::limits::pairsize4page_max(const env &env, + MDBX_db_flags_t flags) { + const intptr_t result = mdbx_env_get_pairsize4page_max(env, flags); + if (result < 0) + MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL); + return static_cast(result); +} + +inline size_t env::limits::pairsize4page_max(const env &env, value_mode mode) { + return pairsize4page_max(env, MDBX_db_flags_t(mode)); +} + +inline size_t env::limits::valsize4page_max(intptr_t pagesize, + MDBX_db_flags_t flags) { + const intptr_t result = mdbx_limits_valsize4page_max(pagesize, flags); + if (result < 0) + MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL); + return static_cast(result); +} + +inline size_t env::limits::valsize4page_max(intptr_t pagesize, + value_mode mode) { + return valsize4page_max(pagesize, MDBX_db_flags_t(mode)); +} + +inline size_t env::limits::valsize4page_max(const env &env, + MDBX_db_flags_t flags) { + const intptr_t result = mdbx_env_get_valsize4page_max(env, flags); + if (result < 0) + MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL); + return static_cast(result); +} + +inline size_t env::limits::valsize4page_max(const env &env, value_mode mode) { + return valsize4page_max(env, MDBX_db_flags_t(mode)); +} + inline size_t env::limits::transaction_size_max(intptr_t pagesize) { const intptr_t result = mdbx_limits_txnsize_max(pagesize); if (result < 0) @@ -4918,7 +5197,7 @@ inline filehandle env::get_filehandle() const { } inline MDBX_env_flags_t env::get_flags() const { - unsigned bits; + unsigned bits = 0; error::success_or_throw(::mdbx_env_get_flags(handle_, &bits)); return MDBX_env_flags_t(bits); } @@ -4949,13 +5228,53 @@ inline env &env::set_sync_threshold(size_t bytes) { return *this; } -inline env &env::set_sync_period(unsigned seconds_16dot16) { +inline size_t env::sync_threshold() const { + size_t bytes; + error::success_or_throw(::mdbx_env_get_syncbytes(handle_, &bytes)); + return bytes; +} + +inline env &env::set_sync_period__seconds_16dot16(unsigned seconds_16dot16) { error::success_or_throw(::mdbx_env_set_syncperiod(handle_, seconds_16dot16)); return *this; } -inline env &env::set_sync_period(double seconds) { - return set_sync_period(unsigned(seconds * 65536)); +inline unsigned env::sync_period__seconds_16dot16() const { + unsigned seconds_16dot16; + error::success_or_throw(::mdbx_env_get_syncperiod(handle_, &seconds_16dot16)); + return seconds_16dot16; +} + +inline env &env::set_sync_period__seconds_double(double seconds) { + return set_sync_period__seconds_16dot16(unsigned(seconds * 65536)); +} + +inline double env::sync_period__seconds_double() const { + return sync_period__seconds_16dot16() / 65536.0; +} + +#if __cplusplus >= 201103L +inline env &env::set_sync_period(const duration &period) { + return set_sync_period__seconds_16dot16(period.count()); +} + +inline duration env::sync_period() const { + return duration(sync_period__seconds_16dot16()); +} +#endif + +inline env &env::set_extra_option(enum env::extra_runtime_option option, + uint64_t value) { + error::success_or_throw( + ::mdbx_env_set_option(handle_, ::MDBX_option_t(option), value)); + return *this; +} + +inline uint64_t env::extra_option(enum env::extra_runtime_option option) const { + uint64_t value; + error::success_or_throw( + ::mdbx_env_get_option(handle_, ::MDBX_option_t(option), &value)); + return value; } inline env &env::alter_flags(MDBX_env_flags_t flags, bool on_off) { diff --git a/mdbxdist/mdbx_chk.c b/mdbxdist/mdbx_chk.c index 45bbb71..9b767c7 100644 --- a/mdbxdist/mdbx_chk.c +++ b/mdbxdist/mdbx_chk.c @@ -34,7 +34,7 @@ * top-level directory of the distribution or, alternatively, at * . */ -#define MDBX_BUILD_SOURCERY 748ccee885a921bfe8ef7b24e71957dd3922fe37083ceb8048cb89c28c5d8f9b_v0_12_7_20_g2b0eae08 +#define MDBX_BUILD_SOURCERY d7603e99410126db376215bd0ceb9c2e32eba2af6c4988c85272497a38e29e56_v0_12_8_6_ged8c7ead #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -2073,8 +2073,7 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; /** Controls using Unix' mincore() to determine whether DB-pages * are resident in memory. */ #ifndef MDBX_ENABLE_MINCORE -#if MDBX_ENABLE_PREFAULT && \ - (defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64))) +#if defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64)) #define MDBX_ENABLE_MINCORE 1 #else #define MDBX_ENABLE_MINCORE 0 diff --git a/mdbxdist/mdbx_copy.c b/mdbxdist/mdbx_copy.c index fdfc2b8..e075a16 100644 --- a/mdbxdist/mdbx_copy.c +++ b/mdbxdist/mdbx_copy.c @@ -34,7 +34,7 @@ * top-level directory of the distribution or, alternatively, at * . */ -#define MDBX_BUILD_SOURCERY 748ccee885a921bfe8ef7b24e71957dd3922fe37083ceb8048cb89c28c5d8f9b_v0_12_7_20_g2b0eae08 +#define MDBX_BUILD_SOURCERY d7603e99410126db376215bd0ceb9c2e32eba2af6c4988c85272497a38e29e56_v0_12_8_6_ged8c7ead #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -2073,8 +2073,7 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; /** Controls using Unix' mincore() to determine whether DB-pages * are resident in memory. */ #ifndef MDBX_ENABLE_MINCORE -#if MDBX_ENABLE_PREFAULT && \ - (defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64))) +#if defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64)) #define MDBX_ENABLE_MINCORE 1 #else #define MDBX_ENABLE_MINCORE 0 diff --git a/mdbxdist/mdbx_drop.c b/mdbxdist/mdbx_drop.c index d742c85..8382bd7 100644 --- a/mdbxdist/mdbx_drop.c +++ b/mdbxdist/mdbx_drop.c @@ -36,7 +36,7 @@ * top-level directory of the distribution or, alternatively, at * . */ -#define MDBX_BUILD_SOURCERY 748ccee885a921bfe8ef7b24e71957dd3922fe37083ceb8048cb89c28c5d8f9b_v0_12_7_20_g2b0eae08 +#define MDBX_BUILD_SOURCERY d7603e99410126db376215bd0ceb9c2e32eba2af6c4988c85272497a38e29e56_v0_12_8_6_ged8c7ead #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -2075,8 +2075,7 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; /** Controls using Unix' mincore() to determine whether DB-pages * are resident in memory. */ #ifndef MDBX_ENABLE_MINCORE -#if MDBX_ENABLE_PREFAULT && \ - (defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64))) +#if defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64)) #define MDBX_ENABLE_MINCORE 1 #else #define MDBX_ENABLE_MINCORE 0 diff --git a/mdbxdist/mdbx_dump.c b/mdbxdist/mdbx_dump.c index fbf3101..a445ea6 100644 --- a/mdbxdist/mdbx_dump.c +++ b/mdbxdist/mdbx_dump.c @@ -34,7 +34,7 @@ * top-level directory of the distribution or, alternatively, at * . */ -#define MDBX_BUILD_SOURCERY 748ccee885a921bfe8ef7b24e71957dd3922fe37083ceb8048cb89c28c5d8f9b_v0_12_7_20_g2b0eae08 +#define MDBX_BUILD_SOURCERY d7603e99410126db376215bd0ceb9c2e32eba2af6c4988c85272497a38e29e56_v0_12_8_6_ged8c7ead #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -2073,8 +2073,7 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; /** Controls using Unix' mincore() to determine whether DB-pages * are resident in memory. */ #ifndef MDBX_ENABLE_MINCORE -#if MDBX_ENABLE_PREFAULT && \ - (defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64))) +#if defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64)) #define MDBX_ENABLE_MINCORE 1 #else #define MDBX_ENABLE_MINCORE 0 diff --git a/mdbxdist/mdbx_load.c b/mdbxdist/mdbx_load.c index 98b89ac..3d98775 100644 --- a/mdbxdist/mdbx_load.c +++ b/mdbxdist/mdbx_load.c @@ -34,7 +34,7 @@ * top-level directory of the distribution or, alternatively, at * . */ -#define MDBX_BUILD_SOURCERY 748ccee885a921bfe8ef7b24e71957dd3922fe37083ceb8048cb89c28c5d8f9b_v0_12_7_20_g2b0eae08 +#define MDBX_BUILD_SOURCERY d7603e99410126db376215bd0ceb9c2e32eba2af6c4988c85272497a38e29e56_v0_12_8_6_ged8c7ead #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -2073,8 +2073,7 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; /** Controls using Unix' mincore() to determine whether DB-pages * are resident in memory. */ #ifndef MDBX_ENABLE_MINCORE -#if MDBX_ENABLE_PREFAULT && \ - (defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64))) +#if defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64)) #define MDBX_ENABLE_MINCORE 1 #else #define MDBX_ENABLE_MINCORE 0 diff --git a/mdbxdist/mdbx_stat.c b/mdbxdist/mdbx_stat.c index 0ddaca9..27d3258 100644 --- a/mdbxdist/mdbx_stat.c +++ b/mdbxdist/mdbx_stat.c @@ -34,7 +34,7 @@ * top-level directory of the distribution or, alternatively, at * . */ -#define MDBX_BUILD_SOURCERY 748ccee885a921bfe8ef7b24e71957dd3922fe37083ceb8048cb89c28c5d8f9b_v0_12_7_20_g2b0eae08 +#define MDBX_BUILD_SOURCERY d7603e99410126db376215bd0ceb9c2e32eba2af6c4988c85272497a38e29e56_v0_12_8_6_ged8c7ead #ifdef MDBX_CONFIG_H #include MDBX_CONFIG_H #endif @@ -2073,8 +2073,7 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor; /** Controls using Unix' mincore() to determine whether DB-pages * are resident in memory. */ #ifndef MDBX_ENABLE_MINCORE -#if MDBX_ENABLE_PREFAULT && \ - (defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64))) +#if defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64)) #define MDBX_ENABLE_MINCORE 1 #else #define MDBX_ENABLE_MINCORE 0