Skip to content

File mdbx.h

File List > docs > mdbx.h

Go to the documentation of this file



#pragma once
/*
 * Tested with, since 2026:
 *  - Elbrus LCC >= 1.28 (http://www.mcst.ru/lcc);
 *  - GNU C >= 11.3;
 *  - CLANG >= 14.0;
 *  - MSVC >= 19.44 (Visual Studio 2022 toolchain v143),
 * before 2026:
 *  - Elbrus LCC >= 1.23 (http://www.mcst.ru/lcc);
 *  - GNU C >= 4.8;
 *  - CLANG >= 3.9;
 *  - MSVC >= 14.0 (Visual Studio 2015),
 *    but 19.2x could hang due optimizer bug;
 *  - AppleClang.
 */

#ifndef LIBMDBX_H
#define LIBMDBX_H

#if defined(__riscv) || defined(__riscv__) || defined(__RISCV) || defined(__RISCV__)
#warning "The RISC-V architecture is intentionally insecure by design. \
  Please delete this admonition at your own risk, \
  if you make such decision informed and consciously. \
  Refer to https://clck.ru/32d9xH for more information."
#endif /* RISC-V */

#ifdef _MSC_VER
#pragma warning(push, 1)
#pragma warning(disable : 4548) /* expression before comma has no effect;                                              \
                                   expected expression with side - effect */
#pragma warning(disable : 4530) /* C++ exception handler used, but unwind                                              \
                                 * semantics are not enabled. Specify /EHsc */
#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling                                          \
                                 * mode specified; termination on exception is                                         \
                                 * not guaranteed. Specify /EHsc */
#endif                          /* _MSC_VER (warnings) */

/* *INDENT-OFF* */
/* clang-format off */
/* *INDENT-ON* */
/* clang-format on */

#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#if !defined(assert)
#include <assert.h>
#endif /* assert */

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#include <winnt.h>
#ifndef __mode_t_defined
typedef unsigned short mdbx_mode_t;
#else
typedef mode_t mdbx_mode_t;
#endif /* __mode_t_defined */
typedef HANDLE mdbx_filehandle_t;
typedef DWORD mdbx_pid_t;
typedef DWORD mdbx_tid_t;
#else                  /* Windows */
#include <errno.h>     /* for error codes */
#include <pthread.h>   /* for pthread_t */
#include <sys/types.h> /* for pid_t */
#include <sys/uio.h>   /* for struct iovec */
#define HAVE_STRUCT_IOVEC 1
typedef int mdbx_filehandle_t;
typedef pid_t mdbx_pid_t;
typedef pthread_t mdbx_tid_t;
typedef mode_t mdbx_mode_t;
#endif /* !Windows */

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#define MDBX_AMALGAMATED_SOURCE 1


/*----------------------------------------------------------------------------*/

#ifndef __has_attribute
#define __has_attribute(x) (0)
#endif /* __has_attribute */

#ifndef __has_c_attribute
#define __has_c_attribute(x) (0)
#define __has_c_attribute_qualified(x) 0
#elif !defined(__STDC_VERSION__) || __STDC_VERSION__ < 202311L
#define __has_c_attribute_qualified(x) 0
#elif defined(_MSC_VER)
/* MSVC don't support `namespace::attr` syntax */
#define __has_c_attribute_qualified(x) 0
#else
#define __has_c_attribute_qualified(x) __has_c_attribute(x)
#endif /* __has_c_attribute */

#ifndef __has_cpp_attribute
#define __has_cpp_attribute(x) 0
#define __has_cpp_attribute_qualified(x) 0
#elif defined(_MSC_VER) || (__clang__ && __clang__ < 14)
/* MSVC don't support `namespace::attr` syntax */
#define __has_cpp_attribute_qualified(x) 0
#else
#define __has_cpp_attribute_qualified(x) __has_cpp_attribute(x)
#endif /* __has_cpp_attribute */

#ifndef __has_C23_or_CXX_attribute
#if defined(__cplusplus)
#define __has_C23_or_CXX_attribute(x) __has_cpp_attribute_qualified(x)
#else
#define __has_C23_or_CXX_attribute(x) __has_c_attribute_qualified(x)
#endif
#endif /* __has_C23_or_CXX_attribute */

#ifndef __has_feature
#define __has_feature(x) (0)
#define __has_exceptions_disabled (0)
#elif !defined(__has_exceptions_disabled)
#define __has_exceptions_disabled (__has_feature(cxx_noexcept) && !__has_feature(cxx_exceptions))
#endif /* __has_feature */

#ifndef __has_extension
#define __has_extension(x) __has_feature(x)
#endif /* __has_extension */

#ifndef __has_builtin
#define __has_builtin(x) (0)
#endif /* __has_builtin */

#if defined(DOXYGEN)
#define MDBX_PURE_FUNCTION [[gnu::pure]]
#elif __has_C23_or_CXX_attribute(gnu::pure)
#define MDBX_PURE_FUNCTION [[gnu::pure]]
#elif (defined(__GNUC__) || __has_attribute(__pure__)) &&                                                              \
    (!defined(__clang__) /* https://bugs.llvm.org/show_bug.cgi?id=43275 */ || !defined(__cplusplus) ||                 \
     __has_exceptions_disabled)
#define MDBX_PURE_FUNCTION __attribute__((__pure__))
#else
#define MDBX_PURE_FUNCTION
#endif /* MDBX_PURE_FUNCTION */

#if defined(DOXYGEN)
#define MDBX_NOTHROW_PURE_FUNCTION [[gnu::pure, gnu::nothrow]]
#elif __has_C23_or_CXX_attribute(gnu::pure)
#if __has_C23_or_CXX_attribute(gnu::nothrow)
#define MDBX_NOTHROW_PURE_FUNCTION [[gnu::pure, gnu::nothrow]]
#else
#define MDBX_NOTHROW_PURE_FUNCTION [[gnu::pure]]
#endif
#elif defined(__GNUC__) || (__has_attribute(__pure__) && __has_attribute(__nothrow__))
#define MDBX_NOTHROW_PURE_FUNCTION __attribute__((__pure__, __nothrow__))
#elif __has_cpp_attribute(pure)
#define MDBX_NOTHROW_PURE_FUNCTION [[pure]]
#else
#define MDBX_NOTHROW_PURE_FUNCTION
#endif /* MDBX_NOTHROW_PURE_FUNCTION */

#if defined(DOXYGEN)
#define MDBX_CONST_FUNCTION [[gnu::const]]
#elif __has_C23_or_CXX_attribute(gnu::const)
#define MDBX_CONST_FUNCTION [[gnu::const]]
#elif (defined(__GNUC__) || __has_attribute(__const__)) &&                                                             \
    (!defined(__clang__) /* https://bugs.llvm.org/show_bug.cgi?id=43275 */ || !defined(__cplusplus) ||                 \
     __has_exceptions_disabled)
#define MDBX_CONST_FUNCTION __attribute__((__const__))
#else
#define MDBX_CONST_FUNCTION MDBX_PURE_FUNCTION
#endif /* MDBX_CONST_FUNCTION */

#if defined(DOXYGEN)
#define MDBX_NOTHROW_CONST_FUNCTION [[gnu::const, gnu::nothrow]]
#elif __has_C23_or_CXX_attribute(gnu::const)
#if __has_C23_or_CXX_attribute(gnu::nothrow)
#define MDBX_NOTHROW_CONST_FUNCTION [[gnu::const, gnu::nothrow]]
#else
#define MDBX_NOTHROW_CONST_FUNCTION [[gnu::const]]
#endif
#elif defined(__GNUC__) || (__has_attribute(__const__) && __has_attribute(__nothrow__))
#define MDBX_NOTHROW_CONST_FUNCTION __attribute__((__const__, __nothrow__))
#elif __has_cpp_attribute_qualified(const)
#define MDBX_NOTHROW_CONST_FUNCTION [[const]]
#else
#define MDBX_NOTHROW_CONST_FUNCTION MDBX_NOTHROW_PURE_FUNCTION
#endif /* MDBX_NOTHROW_CONST_FUNCTION */

#ifndef MDBX_DEPRECATED
#ifdef __deprecated
#define MDBX_DEPRECATED __deprecated
#elif defined(DOXYGEN) || ((!defined(__GNUC__) || (defined(__clang__) && __clang__ > 19) || __GNUC__ > 5) &&           \
                           ((defined(__cplusplus) && __cplusplus >= 201403L && __has_cpp_attribute(deprecated) &&      \
                             __has_cpp_attribute(deprecated) >= 201309L) ||                                            \
                            (!defined(__cplusplus) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202304L)))
#define MDBX_DEPRECATED [[deprecated]]
#elif (defined(__GNUC__) && __GNUC__ > 5) ||                                                                           \
    (__has_attribute(__deprecated__) && (!defined(__GNUC__) || defined(__clang__) || __GNUC__ > 5))
#define MDBX_DEPRECATED __attribute__((__deprecated__))
#elif defined(_MSC_VER)
#define MDBX_DEPRECATED __declspec(deprecated)
#else
#define MDBX_DEPRECATED
#endif
#endif /* MDBX_DEPRECATED */

#ifndef MDBX_DEPRECATED_ENUM
#ifdef __deprecated_enum
#define MDBX_DEPRECATED_ENUM __deprecated_enum
#elif defined(DOXYGEN) ||                                                                                              \
    (!defined(_MSC_VER) || (defined(__cplusplus) && __cplusplus >= 201403L && __has_cpp_attribute(deprecated) &&       \
                            __has_cpp_attribute(deprecated) >= 201309L))
#define MDBX_DEPRECATED_ENUM MDBX_DEPRECATED
#else
#define MDBX_DEPRECATED_ENUM /* avoid madness MSVC */
#endif
#endif /* MDBX_DEPRECATED_ENUM */

#ifndef __dll_export
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) || defined(__MINGW__) || defined(__MINGW32__) ||         \
    defined(__MINGW64__)
#if defined(__GNUC__) || __has_attribute(__dllexport__)
#define __dll_export __attribute__((__dllexport__))
#elif defined(_MSC_VER)
#define __dll_export __declspec(dllexport)
#else
#define __dll_export
#endif
#elif defined(__GNUC__) || defined(__clang__) || __has_attribute(__visibility__)
#define __dll_export __attribute__((__visibility__("default")))
#else
#define __dll_export
#endif
#endif /* __dll_export */

#ifndef __dll_import
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) || defined(__MINGW__) || defined(__MINGW32__) ||         \
    defined(__MINGW64__)
#if defined(__GNUC__) || __has_attribute(__dllimport__)
#define __dll_import __attribute__((__dllimport__))
#elif defined(_MSC_VER)
#define __dll_import __declspec(dllimport)
#else
#define __dll_import
#endif
#else
#define __dll_import
#endif
#endif /* __dll_import */

#if defined(LIBMDBX_INTERNALS) && !defined(LIBMDBX_NO_EXPORTS_LEGACY_API)
#define LIBMDBX_INLINE_API(TYPE, NAME, ARGS)                                                                           \
  /* proto of exported which uses common impl */ LIBMDBX_API TYPE NAME ARGS;                                           \
  /* definition of common impl */ static __inline TYPE __inline_##NAME ARGS
#else
#define LIBMDBX_INLINE_API(TYPE, NAME, ARGS) static __inline TYPE NAME ARGS
#endif /* LIBMDBX_INLINE_API */

#ifndef MDBX_STRINGIFY
#define MDBX_STRINGIFY_HELPER(x) #x
#define MDBX_STRINGIFY(x) MDBX_STRINGIFY_HELPER(x)
#endif /* MDBX_STRINGIFY */

/*----------------------------------------------------------------------------*/

#ifndef __cplusplus
#ifndef bool
#define bool _Bool
#endif
#ifndef true
#define true (1)
#endif
#ifndef false
#define false (0)
#endif
#endif /* bool without __cplusplus */

#if defined(DOXYGEN)
#define MDBX_CXX17_NOEXCEPT noexcept
#elif !defined(__cpp_noexcept_function_type) || __cpp_noexcept_function_type < 201510L
#define MDBX_CXX17_NOEXCEPT
#else
#define MDBX_CXX17_NOEXCEPT noexcept
#endif /* MDBX_CXX17_NOEXCEPT */

#if defined(DOXYGEN)
#define MDBX_CXX01_CONSTEXPR constexpr
#define MDBX_CXX01_CONSTEXPR_VAR constexpr
#elif !defined(__cplusplus)
#define MDBX_CXX01_CONSTEXPR __inline
#define MDBX_CXX01_CONSTEXPR_VAR const
#elif !defined(DOXYGEN) &&                                                                                             \
    ((__cplusplus < 201103L && defined(__cpp_constexpr) && __cpp_constexpr < 200704L) ||                               \
     (defined(__LCC__) && __LCC__ < 124) ||                                                                            \
     (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 407) && !defined(__clang__) && !defined(__LCC__)) ||     \
     (defined(_MSC_VER) && _MSC_VER < 1910) || (defined(__clang__) && __clang_major__ < 4))
#define MDBX_CXX01_CONSTEXPR inline
#define MDBX_CXX01_CONSTEXPR_VAR const
#else
#define MDBX_CXX01_CONSTEXPR constexpr
#define MDBX_CXX01_CONSTEXPR_VAR constexpr
#endif /* MDBX_CXX01_CONSTEXPR */

#if defined(DOXYGEN)
#define MDBX_CXX11_CONSTEXPR constexpr
#define MDBX_CXX11_CONSTEXPR_VAR constexpr
#elif !defined(__cplusplus)
#define MDBX_CXX11_CONSTEXPR __inline
#define MDBX_CXX11_CONSTEXPR_VAR const
#elif !defined(DOXYGEN) &&                                                                                             \
    (!defined(__cpp_constexpr) || __cpp_constexpr < 201304L || (defined(__LCC__) && __LCC__ < 124) ||                  \
     (defined(__GNUC__) && __GNUC__ < 6 && !defined(__clang__) && !defined(__LCC__)) ||                                \
     (defined(_MSC_VER) && _MSC_VER < 1910) || (defined(__clang__) && __clang_major__ < 5))
#define MDBX_CXX11_CONSTEXPR inline
#define MDBX_CXX11_CONSTEXPR_VAR const
#else
#define MDBX_CXX11_CONSTEXPR constexpr
#define MDBX_CXX11_CONSTEXPR_VAR constexpr
#endif /* MDBX_CXX11_CONSTEXPR */

#if defined(DOXYGEN)
#define MDBX_CXX14_CONSTEXPR constexpr
#define MDBX_CXX14_CONSTEXPR_VAR constexpr
#elif !defined(__cplusplus)
#define MDBX_CXX14_CONSTEXPR __inline
#define MDBX_CXX14_CONSTEXPR_VAR const
#elif defined(DOXYGEN) ||                                                                                              \
    defined(__cpp_constexpr) && __cpp_constexpr >= 201304L &&                                                          \
        ((defined(_MSC_VER) && _MSC_VER >= 1910) || (defined(__clang__) && __clang_major__ > 4) ||                     \
         (defined(__GNUC__) && __GNUC__ > 6) || (!defined(__GNUC__) && !defined(__clang__) && !defined(_MSC_VER)))
#define MDBX_CXX14_CONSTEXPR constexpr
#define MDBX_CXX14_CONSTEXPR_VAR constexpr
#else
#define MDBX_CXX14_CONSTEXPR inline
#define MDBX_CXX14_CONSTEXPR_VAR const
#endif /* MDBX_CXX14_CONSTEXPR */

#if defined(__noreturn)
#define MDBX_NORETURN __noreturn
#elif defined(_Noreturn)
#define MDBX_NORETURN _Noreturn
#elif defined(DOXYGEN) || (defined(__cplusplus) && __cplusplus >= 201103L) ||                                          \
    (!defined(__cplusplus) && defined(__STDC_VERSION__) && __STDC_VERSION__ > 202005L)
#define MDBX_NORETURN [[noreturn]]
#elif defined(__GNUC__) || __has_attribute(__noreturn__)
#define MDBX_NORETURN __attribute__((__noreturn__))
#elif defined(_MSC_VER) && !defined(__clang__)
#define MDBX_NORETURN __declspec(noreturn)
#else
#define MDBX_NORETURN
#endif /* MDBX_NORETURN */

#ifndef MDBX_PRINTF_ARGS
#if defined(__GNUC__) || __has_attribute(__format__) || defined(DOXYGEN)
#if defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)
#define MDBX_PRINTF_ARGS(format_index, first_arg) __attribute__((__format__(__gnu_printf__, format_index, first_arg)))
#else
#define MDBX_PRINTF_ARGS(format_index, first_arg) __attribute__((__format__(__printf__, format_index, first_arg)))
#endif /* MinGW */
#else
#define MDBX_PRINTF_ARGS(format_index, first_arg)
#endif
#endif /* MDBX_PRINTF_ARGS */

#if defined(DOXYGEN) ||                                                                                                \
    (defined(__cplusplus) && __cplusplus >= 201603L && __has_cpp_attribute(maybe_unused) &&                            \
     __has_cpp_attribute(maybe_unused) >= 201603L && (!defined(__clang__) || __clang__ > 19)) ||                       \
    (!defined(__cplusplus) && defined(__STDC_VERSION__) && __STDC_VERSION__ > 202005L)
#define MDBX_MAYBE_UNUSED [[maybe_unused]]
#elif defined(__GNUC__) || __has_attribute(__unused__)
#define MDBX_MAYBE_UNUSED __attribute__((__unused__))
#else
#define MDBX_MAYBE_UNUSED
#endif /* MDBX_MAYBE_UNUSED */

#if __has_attribute(no_sanitize) || defined(DOXYGEN)
#define MDBX_NOSANITIZE_ENUM __attribute((__no_sanitize__("enum")))
#else
#define MDBX_NOSANITIZE_ENUM
#endif /* MDBX_NOSANITIZE_ENUM */

/* Oh, below are some songs and dances since:
 *  - C++ requires explicit definition of the necessary operators.
 *  - the proper implementation of DEFINE_ENUM_FLAG_OPERATORS for C++ required
 *    the constexpr feature which is broken in most old compilers;
 *  - DEFINE_ENUM_FLAG_OPERATORS may be defined broken as in the Windows SDK. */
#if !defined(MDBX_DEFINE_ENUM_FLAG_OPERATORS) && !defined(DOXYGEN)

#ifdef __cplusplus
#if !defined(__cpp_constexpr) || __cpp_constexpr < 200704L || (defined(__LCC__) && __LCC__ < 124) ||                   \
    (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 407) && !defined(__clang__) && !defined(__LCC__)) ||      \
    (defined(_MSC_VER) && _MSC_VER < 1910) || (defined(__clang__) && __clang_major__ < 4)
/* The constexpr feature is not available or (may be) broken */
#define MDBX_CONSTEXPR_ENUM_FLAGS_OPERATIONS 0
#else
/* C always allows these operators for enums */
#define MDBX_CONSTEXPR_ENUM_FLAGS_OPERATIONS 1
#endif /* __cpp_constexpr */

#define MDBX_DEFINE_ENUM_FLAG_OPERATORS(ENUM)                                                                          \
  extern "C++" {                                                                                                       \
  MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator|(ENUM a, ENUM b) { return ENUM(unsigned(a) | unsigned(b)); } \
  MDBX_NOSANITIZE_ENUM MDBX_CXX14_CONSTEXPR ENUM &operator|=(ENUM &a, ENUM b) { return a = a | b; }                    \
  MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator&(ENUM a, ENUM b) { return ENUM(unsigned(a) & unsigned(b)); } \
  MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator&(ENUM a, unsigned b) { return ENUM(unsigned(a) & b); }       \
  MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator&(unsigned a, ENUM b) { return ENUM(a & unsigned(b)); }       \
  MDBX_NOSANITIZE_ENUM MDBX_CXX14_CONSTEXPR ENUM &operator&=(ENUM &a, ENUM b) { return a = a & b; }                    \
  MDBX_NOSANITIZE_ENUM MDBX_CXX14_CONSTEXPR ENUM &operator&=(ENUM &a, unsigned b) { return a = a & b; }                \
  MDBX_CXX01_CONSTEXPR unsigned operator~(ENUM a) { return ~unsigned(a); }                                             \
  MDBX_NOSANITIZE_ENUM MDBX_CXX01_CONSTEXPR ENUM operator^(ENUM a, ENUM b) { return ENUM(unsigned(a) ^ unsigned(b)); } \
  MDBX_NOSANITIZE_ENUM MDBX_CXX14_CONSTEXPR ENUM &operator^=(ENUM &a, ENUM b) { return a = a ^ b; }                    \
  }
#else /* __cplusplus */
/* nope for C since it always allows these operators for enums */
#define MDBX_DEFINE_ENUM_FLAG_OPERATORS(ENUM)
#define MDBX_CONSTEXPR_ENUM_FLAGS_OPERATIONS 1
#endif /* !__cplusplus */

#elif !defined(MDBX_CONSTEXPR_ENUM_FLAGS_OPERATIONS)

#ifdef __cplusplus
/* MDBX_DEFINE_ENUM_FLAG_OPERATORS may be defined broken as in the Windows SDK */
#define MDBX_CONSTEXPR_ENUM_FLAGS_OPERATIONS 0
#else
/* C always allows these operators for enums */
#define MDBX_CONSTEXPR_ENUM_FLAGS_OPERATIONS 1
#endif

#endif /* MDBX_DEFINE_ENUM_FLAG_OPERATORS */

#ifndef MDBX_LIKELY
#if defined(DOXYGEN) || (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
#define MDBX_LIKELY(cond) __builtin_expect(!!(cond), 1)
#else
#define MDBX_LIKELY(x) (x)
#endif
#endif /* MDBX_LIKELY */

#ifndef MDBX_UNLIKELY
#if defined(DOXYGEN) || (defined(__GNUC__) || __has_builtin(__builtin_expect)) && !defined(__COVERITY__)
#define MDBX_UNLIKELY(cond) __builtin_expect(!!(cond), 0)
#else
#define MDBX_UNLIKELY(x) (x)
#endif
#endif /* MDBX_UNLIKELY */

#if defined(DOXYGEN) || (defined(MDBX_CHECKING) && MDBX_CHECKING > 0) || (defined(MDBX_DEBUG) && MDBX_DEBUG > 0)
#define MDBX_INLINE_API_ASSERT(expr)                                                                                   \
  do {                                                                                                                 \
    if (MDBX_UNLIKELY(!(expr)))                                                                                        \
      mdbx_assert_fail(#expr, __func__, __LINE__);                                                                     \
  } while (0)
#else
/* clang-format off */
#define MDBX_INLINE_API_ASSERT(expr) do {} while(0)
/* clang-format on */
#endif /* MDBX_INLINE_API_ASSERT */


/*----------------------------------------------------------------------------*/


#ifdef __cplusplus
extern "C" {
#endif

/* MDBX version 0.15.x, but it is unstable/under-development yet. */
#define MDBX_VERSION_UNSTABLE
#define MDBX_VERSION_MAJOR 0
#define MDBX_VERSION_MINOR 15

#ifndef LIBMDBX_API
#if defined(LIBMDBX_EXPORTS) || defined(DOXYGEN)
#define LIBMDBX_API __dll_export
#elif defined(LIBMDBX_IMPORTS)
#define LIBMDBX_API __dll_import
#else
#define LIBMDBX_API
#endif
#endif /* LIBMDBX_API */

#ifdef __cplusplus
#if defined(__clang__) || __has_attribute(type_visibility) || defined(DOXYGEN)
#define LIBMDBX_API_TYPE LIBMDBX_API __attribute__((type_visibility("default")))
#else
#define LIBMDBX_API_TYPE LIBMDBX_API
#endif
#else
#define LIBMDBX_API_TYPE
#endif /* LIBMDBX_API_TYPE */

#if defined(LIBMDBX_IMPORTS)
#define LIBMDBX_VERINFO_API __dll_import
#else
#define LIBMDBX_VERINFO_API __dll_export
#endif /* LIBMDBX_VERINFO_API */

extern LIBMDBX_VERINFO_API const struct MDBX_version_info {
  uint16_t major;                
  uint16_t minor;                
  uint16_t patch;                
  uint16_t tweak;                
  const char *semver_prerelease; 
  struct {
    const char *datetime; 
    const char *tree;     
    const char *commit;   
    const char *describe; 
  } git;                  
  const char *sourcery;   
}  mdbx_version;

extern LIBMDBX_VERINFO_API const struct MDBX_build_info {
  const char *datetime; 
  const char *target;   
  const char *options;  
  const char *compiler; 
  const char *flags;    
  const char *metadata; 
}  mdbx_build;

#if (defined(_WIN32) || defined(_WIN64)) && !MDBX_BUILD_SHARED_LIBRARY
/* MDBX internally uses global and thread local storage destructors to
 * automatically (de)initialization, releasing reader lock table slots
 * and so on.
 *
 * If MDBX built as a DLL this is done out-of-the-box by DllEntry() function,
 * which called automatically by Windows core with passing corresponding reason
 * argument.
 *
 * Otherwise, if MDBX was built not as a DLL, some black magic
 * may be required depending of Windows version:
 *
 *  - Modern Windows versions, including Windows Vista and later, provides
 *    support for "TLS Directory" (e.g .CRT$XL[A-Z] sections in executable
 *    or dll file). In this case, MDBX capable of doing all automatically,
 *    therefore you DON'T NEED to call mdbx_module_handler()
 *    so the MDBX_MANUAL_MODULE_HANDLER defined as 0.
 *
 *  - Obsolete versions of Windows, prior to Windows Vista, REQUIRES calling
 *    mdbx_module_handler() manually from corresponding DllMain() or WinMain()
 *    of your DLL or application,
 *    so the MDBX_MANUAL_MODULE_HANDLER defined as 1.
 *
 * Therefore, building MDBX as a DLL is recommended for all version of Windows.
 * So, if you doubt, just build MDBX as the separate DLL and don't care about
 * the MDBX_MANUAL_MODULE_HANDLER. */

#ifndef _WIN32_WINNT
#error Non-dll build libmdbx requires target Windows version \
  to be explicitly defined via _WIN32_WINNT for properly \
  handling thread local storage destructors.
#endif /* _WIN32_WINNT */

#if _WIN32_WINNT >= 0x0600 /* Windows Vista */
/* As described above mdbx_module_handler() is NOT needed for Windows Vista
 * and later. */
#define MDBX_MANUAL_MODULE_HANDLER 0
#else
/* As described above mdbx_module_handler() IS REQUIRED for Windows versions
 * prior to Windows Vista. */
#define MDBX_MANUAL_MODULE_HANDLER 1
void LIBMDBX_API NTAPI mdbx_module_handler(PVOID module, DWORD reason, PVOID reserved);
#endif

#endif /* Windows && !DLL && MDBX_MANUAL_MODULE_HANDLER */

/* OPACITY STRUCTURES *********************************************************/

#ifndef __cplusplus
typedef struct MDBX_env MDBX_env;
#else
struct MDBX_env;
#endif

#ifndef __cplusplus
typedef struct MDBX_txn MDBX_txn;
#else
struct MDBX_txn;
#endif

typedef uint32_t MDBX_dbi;

#ifndef __cplusplus
typedef struct MDBX_cursor MDBX_cursor;
#else
struct MDBX_cursor;
#endif

#ifndef HAVE_STRUCT_IOVEC
struct iovec {
  void *iov_base; 
  size_t iov_len; 
};
#define HAVE_STRUCT_IOVEC
#endif /* HAVE_STRUCT_IOVEC */

#if defined(__sun) || defined(__SVR4) || defined(__svr4__)
/* The `iov_len` is signed on Sun/Solaris.
 * So define custom MDBX_val to avoid a lot of warnings. */
struct MDBX_val {
  void *iov_base; 
  size_t iov_len; 
};
#ifndef __cplusplus
typedef struct MDBX_val MDBX_val;
#endif
#else  /* SunOS */
typedef struct iovec MDBX_val;
#endif /* ! SunOS */

enum MDBX_constants {
  MDBX_MAX_DBI = UINT32_C(32765),

  MDBX_MAXDATASIZE = UINT32_C(0x7fff0000),

  MDBX_MIN_PAGESIZE = 256,

  MDBX_MAX_PAGESIZE = 65536,
};

/* THE FILES *******************************************************************
 * At the file system level, the environment corresponds to a pair of files. */

#ifndef MDBX_LOCKNAME
#if !(defined(_WIN32) || defined(_WIN64))
#define MDBX_LOCKNAME "/mdbx.lck"
#else
#define MDBX_LOCKNAME_W L"\\mdbx.lck"
#define MDBX_LOCKNAME_A "\\mdbx.lck"
#ifdef UNICODE
#define MDBX_LOCKNAME MDBX_LOCKNAME_W
#else
#define MDBX_LOCKNAME MDBX_LOCKNAME_A
#endif /* UNICODE */
#endif /* Windows */
#endif /* MDBX_LOCKNAME */
#ifndef MDBX_DATANAME
#if !(defined(_WIN32) || defined(_WIN64))
#define MDBX_DATANAME "/mdbx.dat"
#else
#define MDBX_DATANAME_W L"\\mdbx.dat"
#define MDBX_DATANAME_A "\\mdbx.dat"
#ifdef UNICODE
#define MDBX_DATANAME MDBX_DATANAME_W
#else
#define MDBX_DATANAME MDBX_DATANAME_A
#endif /* UNICODE */
#endif /* Windows */
#endif /* MDBX_DATANAME */

#ifndef MDBX_LOCK_SUFFIX
#if !(defined(_WIN32) || defined(_WIN64))
#define MDBX_LOCK_SUFFIX "-lck"
#else
#define MDBX_LOCK_SUFFIX_W L"-lck"
#define MDBX_LOCK_SUFFIX_A "-lck"
#ifdef UNICODE
#define MDBX_LOCK_SUFFIX MDBX_LOCK_SUFFIX_W
#else
#define MDBX_LOCK_SUFFIX MDBX_LOCK_SUFFIX_A
#endif /* UNICODE */
#endif /* Windows */
#endif /* MDBX_LOCK_SUFFIX */

/* DEBUG & LOGGING ************************************************************/


typedef enum MDBX_log_level {
  MDBX_LOG_DONTCHANGE = -1,

  MDBX_LOG_FATAL = 0,

  MDBX_LOG_ERROR = 1,

  MDBX_LOG_WARN = 2,

  MDBX_LOG_NOTICE = 3,

  MDBX_LOG_VERBOSE = 4,

  MDBX_LOG_DEBUG = 5,

  MDBX_LOG_TRACE = 6,

  MDBX_LOG_EXTRA = 7,

  MDBX_LOG_MAX = 7
} MDBX_log_level_t;

typedef enum MDBX_debug_flags {
  MDBX_DBG_DONTCHANGE = -1,

  MDBX_DBG_NONE = 0,

  MDBX_DBG_ASSERT = 1,

  MDBX_DBG_AUDIT = 2,

  MDBX_DBG_JITTER = 4,

  MDBX_DBG_DUMP = 8,

  MDBX_DBG_LEGACY_MULTIOPEN = 16,

  MDBX_DBG_LEGACY_OVERLAP = 32,

  MDBX_DBG_DONT_UPGRADE = 64,

  MDBX_DBG_MAX = ((unsigned)MDBX_LOG_MAX) << 16 | 127
} MDBX_debug_flags_t;
MDBX_DEFINE_ENUM_FLAG_OPERATORS(MDBX_debug_flags)


typedef void (*MDBX_debug_func)(MDBX_log_level_t log_level, const char *function, int line, const char *fmt,
                                va_list args) MDBX_CXX17_NOEXCEPT;

#define MDBX_LOGGER_DONTCHANGE ((MDBX_debug_func)(intptr_t)-1)

LIBMDBX_API int mdbx_setup_debug(MDBX_log_level_t log_level, MDBX_debug_flags_t debug_flags, MDBX_debug_func logger);

typedef void (*MDBX_debug_func_nofmt)(MDBX_log_level_t log_level, const char *function, int line, const char *msg,
                                      unsigned length) MDBX_CXX17_NOEXCEPT;

#define MDBX_LOGGER_NOFMT_DONTCHANGE ((MDBX_debug_func_nofmt)(intptr_t)-1)

LIBMDBX_API int mdbx_setup_debug_nofmt(MDBX_log_level_t log_level, MDBX_debug_flags_t debug_flags,
                                       MDBX_debug_func_nofmt logger, char *logger_buffer, size_t logger_buffer_size);

typedef void (*MDBX_panic_func)(const char *msg, const char *function, unsigned line, const void *obj,
                                const char *obj_class) MDBX_CXX17_NOEXCEPT;

MDBX_NORETURN LIBMDBX_API void mdbx_assert_fail(const char *msg, const char *func, unsigned line);

LIBMDBX_API void mdbx_set_panic(MDBX_panic_func func);

LIBMDBX_API const char *mdbx_dump_val(const MDBX_val *key, char *const buf, const size_t bufsize);


typedef enum MDBX_env_flags {
  MDBX_ENV_DEFAULTS = 0,

  MDBX_VALIDATION = UINT32_C(0x00002000),

  MDBX_NOSUBDIR = UINT32_C(0x4000),

  MDBX_RDONLY = UINT32_C(0x20000),

  MDBX_EXCLUSIVE = UINT32_C(0x400000),

  MDBX_ACCEDE = UINT32_C(0x40000000),

  MDBX_WRITEMAP = UINT32_C(0x80000),

  MDBX_NOSTICKYTHREADS = UINT32_C(0x200000),

  MDBX_NORDAHEAD = UINT32_C(0x800000),

  MDBX_NOMEMINIT = UINT32_C(0x1000000),

  MDBX_LIFORECLAIM = UINT32_C(0x4000000),

  MDBX_PAGEPERTURB = UINT32_C(0x8000000),

  /* SYNC MODES****************************************************************/

  MDBX_SYNC_DURABLE = 0,

  MDBX_NOMETASYNC = UINT32_C(0x40000),

  MDBX_SAFE_NOSYNC = UINT32_C(0x10000),

  MDBX_UTTERLY_NOSYNC = MDBX_SAFE_NOSYNC | UINT32_C(0x100000),

} MDBX_env_flags_t;
MDBX_DEFINE_ENUM_FLAG_OPERATORS(MDBX_env_flags)


typedef enum MDBX_txn_flags {
  MDBX_TXN_READWRITE = 0,

  MDBX_TXN_RDONLY = MDBX_RDONLY,

#if MDBX_CONSTEXPR_ENUM_FLAGS_OPERATIONS || defined(DOXYGEN)
  MDBX_TXN_RDONLY_PREPARE = MDBX_RDONLY | MDBX_NOMEMINIT,
#else
  MDBX_TXN_RDONLY_PREPARE = uint32_t(MDBX_RDONLY) | uint32_t(MDBX_NOMEMINIT),
#endif

  MDBX_TXN_TRY = UINT32_C(0x10000000),

  MDBX_TXN_NOWEAKING = 0,

  MDBX_TXN_NOMETASYNC = MDBX_NOMETASYNC,

  MDBX_TXN_NOSYNC = MDBX_SAFE_NOSYNC,

  /* Transaction state flags ---------------------------------------------- */

  MDBX_TXN_INVALID = INT32_MIN,

  MDBX_TXN_FINISHED = 0x01,

  MDBX_TXN_ERROR = 0x02,

  MDBX_TXN_DIRTY = 0x04,

  MDBX_TXN_SPILLS = 0x08,

  MDBX_TXN_HAS_CHILD = 0x10,

  MDBX_TXN_PARKED = 0x20,

  MDBX_TXN_AUTOUNPARK = 0x40,

  MDBX_TXN_OUSTED = 0x80,

  MDBX_TXN_BLOCKED = MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_HAS_CHILD | MDBX_TXN_PARKED
} MDBX_txn_flags_t;
MDBX_DEFINE_ENUM_FLAG_OPERATORS(MDBX_txn_flags)


typedef enum MDBX_db_flags {
  MDBX_DB_DEFAULTS = 0,

  MDBX_REVERSEKEY = UINT32_C(0x02),

  MDBX_DUPSORT = UINT32_C(0x04),

  MDBX_INTEGERKEY = UINT32_C(0x08),

  MDBX_DUPFIXED = UINT32_C(0x10),

  MDBX_INTEGERDUP = UINT32_C(0x20),

  MDBX_REVERSEDUP = UINT32_C(0x40),

  MDBX_CREATE = UINT32_C(0x40000),

  MDBX_DB_ACCEDE = MDBX_ACCEDE
} MDBX_db_flags_t;
MDBX_DEFINE_ENUM_FLAG_OPERATORS(MDBX_db_flags)


typedef enum MDBX_put_flags {
  MDBX_UPSERT = 0,

  MDBX_NOOVERWRITE = UINT32_C(0x10),

  MDBX_NODUPDATA = UINT32_C(0x20),

  MDBX_CURRENT = UINT32_C(0x40),

  MDBX_ALLDUPS = UINT32_C(0x80),

  MDBX_RESERVE = UINT32_C(0x10000),

  MDBX_APPEND = UINT32_C(0x20000),

  MDBX_APPENDDUP = UINT32_C(0x40000),

  MDBX_MULTIPLE = UINT32_C(0x80000)
} MDBX_put_flags_t;
MDBX_DEFINE_ENUM_FLAG_OPERATORS(MDBX_put_flags)


typedef enum MDBX_copy_flags {
  MDBX_CP_DEFAULTS = 0,

  MDBX_CP_COMPACT = 1u,

  MDBX_CP_FORCE_DYNAMIC_SIZE = 2u,

  MDBX_CP_DONT_FLUSH = 4u,

  MDBX_CP_THROTTLE_MVCC = 8u,

  MDBX_CP_DISPOSE_TXN = 16u,

  MDBX_CP_RENEW_TXN = 32u,

  MDBX_CP_OVERWRITE = 64u

} MDBX_copy_flags_t;
MDBX_DEFINE_ENUM_FLAG_OPERATORS(MDBX_copy_flags)


typedef enum MDBX_cursor_op {
  MDBX_FIRST,

  MDBX_FIRST_DUP,

  MDBX_GET_BOTH,

  MDBX_GET_BOTH_RANGE,

  MDBX_GET_CURRENT,

  MDBX_GET_MULTIPLE,

  MDBX_LAST,

  MDBX_LAST_DUP,

  MDBX_NEXT,

  MDBX_NEXT_DUP,

  MDBX_NEXT_MULTIPLE,

  MDBX_NEXT_NODUP,

  MDBX_PREV,

  MDBX_PREV_DUP,

  MDBX_PREV_NODUP,

  MDBX_SET,

  MDBX_SET_KEY,

  MDBX_SET_RANGE,

  MDBX_PREV_MULTIPLE,

  MDBX_SET_LOWERBOUND,

  MDBX_SET_UPPERBOUND,

  MDBX_TO_KEY_LESSER_THAN,
  MDBX_TO_KEY_LESSER_OR_EQUAL ,
  MDBX_TO_KEY_EQUAL ,
  MDBX_TO_KEY_GREATER_OR_EQUAL ,
  MDBX_TO_KEY_GREATER_THAN ,

  MDBX_TO_EXACT_KEY_VALUE_LESSER_THAN,
  MDBX_TO_EXACT_KEY_VALUE_LESSER_OR_EQUAL ,
  MDBX_TO_EXACT_KEY_VALUE_EQUAL ,
  MDBX_TO_EXACT_KEY_VALUE_GREATER_OR_EQUAL ,
  MDBX_TO_EXACT_KEY_VALUE_GREATER_THAN ,

  MDBX_TO_PAIR_LESSER_THAN,
  MDBX_TO_PAIR_LESSER_OR_EQUAL ,
  MDBX_TO_PAIR_EQUAL ,
  MDBX_TO_PAIR_GREATER_OR_EQUAL ,
  MDBX_TO_PAIR_GREATER_THAN ,

  MDBX_SEEK_AND_GET_MULTIPLE
} MDBX_cursor_op;

typedef enum MDBX_error {
  MDBX_SUCCESS = 0,

  MDBX_RESULT_FALSE = MDBX_SUCCESS,

  MDBX_RESULT_TRUE = -1,

  MDBX_KEYEXIST = -30799,

  MDBX_FIRST_LMDB_ERRCODE = MDBX_KEYEXIST,

  MDBX_NOTFOUND = -30798,

  MDBX_PAGE_NOTFOUND = -30797,

  MDBX_CORRUPTED = -30796,

  MDBX_PANIC = -30795,

  MDBX_VERSION_MISMATCH = -30794,

  MDBX_INVALID = -30793,

  MDBX_MAP_FULL = -30792,

  MDBX_DBS_FULL = -30791,

  MDBX_READERS_FULL = -30790,

  MDBX_TXN_FULL = -30788,

  MDBX_CURSOR_FULL = -30787,

  MDBX_PAGE_FULL = -30786,

  MDBX_UNABLE_EXTEND_MAPSIZE = -30785,

  MDBX_INCOMPATIBLE = -30784,

  MDBX_BAD_RSLOT = -30783,

  MDBX_BAD_TXN = -30782,

  MDBX_BAD_VALSIZE = -30781,

  MDBX_BAD_DBI = -30780,

  MDBX_PROBLEM = -30779,

  MDBX_LAST_LMDB_ERRCODE = MDBX_PROBLEM,

  MDBX_BUSY = -30778,

  MDBX_FIRST_ADDED_ERRCODE = MDBX_BUSY,

  MDBX_EMULTIVAL = -30421,

  MDBX_EBADSIGN = -30420,

  MDBX_WANNA_RECOVERY = -30419,

  MDBX_EKEYMISMATCH = -30418,

  MDBX_TOO_LARGE = -30417,

  MDBX_THREAD_MISMATCH = -30416,

  MDBX_TXN_OVERLAPPING = -30415,

  MDBX_BACKLOG_DEPLETED = -30414,

  MDBX_DUPLICATED_LCK = -30413,

  MDBX_DANGLING_DBI = -30412,

  MDBX_OUSTED = -30411,

  MDBX_MVCC_RETARDED = -30410,

  MDBX_LAGGARD_READER = -30409,

  /* The last of MDBX-added error codes */
  MDBX_LAST_ADDED_ERRCODE = MDBX_LAGGARD_READER,

#if defined(_WIN32) || defined(_WIN64)
  MDBX_ENODATA = ERROR_HANDLE_EOF,
  MDBX_EINVAL = ERROR_INVALID_PARAMETER,
  MDBX_EACCESS = ERROR_ACCESS_DENIED,
  MDBX_ENOMEM = ERROR_OUTOFMEMORY,
  MDBX_EROFS = ERROR_FILE_READ_ONLY,
  MDBX_ENOSYS = ERROR_NOT_SUPPORTED,
  MDBX_EIO = ERROR_WRITE_FAULT,
  MDBX_EPERM = ERROR_INVALID_FUNCTION,
  MDBX_EINTR = ERROR_CANCELLED,
  MDBX_EEXIST = ERROR_FILE_EXISTS,
  MDBX_ENOFILE = ERROR_FILE_NOT_FOUND,
  MDBX_EREMOTE = ERROR_REMOTE_STORAGE_MEDIA_ERROR,
  MDBX_EDEADLK = ERROR_POSSIBLE_DEADLOCK
#else /* Windows */
#if defined(ENODATA) || defined(DOXYGEN)
  MDBX_ENODATA = ENODATA,
#else
  MDBX_ENODATA = 9919 /* for compatibility with LLVM's C++ libraries/headers */,
#endif /* ENODATA */
  MDBX_EINVAL = EINVAL,
  MDBX_EACCESS = EACCES,
  MDBX_ENOMEM = ENOMEM,
  MDBX_EROFS = EROFS,
#if defined(ENOTSUP) || defined(DOXYGEN)
  MDBX_ENOSYS = ENOTSUP,
#else
  MDBX_ENOSYS = ENOSYS,
#endif /* ENOTSUP */
  MDBX_EIO = EIO,
  MDBX_EPERM = EPERM,
  MDBX_EINTR = EINTR,
  MDBX_EEXIST = EEXIST,
  MDBX_ENOFILE = ENOENT,
#if defined(EREMOTEIO) || defined(DOXYGEN)
  MDBX_EREMOTE = EREMOTEIO,
#else
  MDBX_EREMOTE = ENOTBLK,
#endif /* EREMOTEIO */
  MDBX_EDEADLK = EDEADLK
#endif /* !Windows */
} MDBX_error_t;

LIBMDBX_API const char *mdbx_strerror(int errnum);

LIBMDBX_API const char *mdbx_strerror_r(int errnum, char *buf, size_t buflen);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API const char *mdbx_liberr2str(int errnum);

#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
LIBMDBX_API const char *mdbx_strerror_ANSI2OEM(int errnum);

LIBMDBX_API const char *mdbx_strerror_r_ANSI2OEM(int errnum, char *buf, size_t buflen);
#endif /* Bit of Windows' madness */

LIBMDBX_API int mdbx_env_create(MDBX_env **penv);

typedef enum MDBX_option {
  MDBX_opt_max_db,

  MDBX_opt_max_readers,

  MDBX_opt_sync_bytes,

  MDBX_opt_sync_period,

  MDBX_opt_rp_augment_limit,

  MDBX_opt_loose_limit,

  MDBX_opt_dp_reserve_limit,

  MDBX_opt_txn_dp_limit,

  MDBX_opt_txn_dp_initial,

  MDBX_opt_spill_max_denominator,

  MDBX_opt_spill_min_denominator,

  MDBX_opt_spill_parent4child_denominator,

  MDBX_opt_merge_threshold,

  MDBX_opt_writethrough_threshold,

  MDBX_opt_prefault_write_enable,

  MDBX_opt_gc_time_limit,

  MDBX_opt_prefer_waf_insteadof_balance,

  MDBX_opt_subpage_limit,

  MDBX_opt_subpage_room_threshold,

  MDBX_opt_subpage_reserve_prereq,

  MDBX_opt_subpage_reserve_limit,

  MDBX_opt_split_reserve,
  MDBX_opt_presync_threshold
} MDBX_option_t;

LIBMDBX_API int mdbx_env_set_option(MDBX_env *env, const MDBX_option_t option, uint64_t value);

LIBMDBX_API int mdbx_env_get_option(const MDBX_env *env, const MDBX_option_t option, uint64_t *pvalue);

LIBMDBX_API int mdbx_env_open(MDBX_env *env, const char *pathname, MDBX_env_flags_t flags, mdbx_mode_t mode);

#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
LIBMDBX_API int mdbx_env_openW(MDBX_env *env, const wchar_t *pathname, MDBX_env_flags_t flags, mdbx_mode_t mode);
#define mdbx_env_openT(env, pathname, flags, mode) mdbx_env_openW(env, pathname, flags, mode)
#else
#define mdbx_env_openT(env, pathname, flags, mode) mdbx_env_open(env, pathname, flags, mode)
#endif /* Windows */

typedef enum MDBX_env_delete_mode {
  MDBX_ENV_JUST_DELETE = 0,
  MDBX_ENV_ENSURE_UNUSED = 1,
  MDBX_ENV_WAIT_FOR_UNUSED = 2,
} MDBX_env_delete_mode_t;

LIBMDBX_API int mdbx_env_delete(const char *pathname, MDBX_env_delete_mode_t mode);

#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
LIBMDBX_API int mdbx_env_deleteW(const wchar_t *pathname, MDBX_env_delete_mode_t mode);
#define mdbx_env_deleteA(pathname, mode) mdbx_env_delete(pathname, mode)
#ifdef UNICODE
#define mdbx_env_deleteT(pathname, mode) mdbx_env_deleteW(pathname, mode)
#else
#define mdbx_env_deleteT(pathname, mode) mdbx_env_deleteA(pathname, mode)
#endif /* UNICODE */
#else
#define mdbx_env_deleteT(pathname, mode) mdbx_env_delete(pathname, mode)
#endif /* Windows */

LIBMDBX_API int mdbx_env_copy(MDBX_env *env, const char *dest, MDBX_copy_flags_t flags);

LIBMDBX_API int mdbx_txn_copy2pathname(MDBX_txn *txn, const char *dest, MDBX_copy_flags_t flags);

#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
LIBMDBX_API int mdbx_env_copyW(MDBX_env *env, const wchar_t *dest, MDBX_copy_flags_t flags);
#define mdbx_env_copyT(env, dest, flags) mdbx_env_copyW(env, dest, flags)

LIBMDBX_API int mdbx_txn_copy2pathnameW(MDBX_txn *txn, const wchar_t *dest, MDBX_copy_flags_t flags);
#define mdbx_txn_copy2pathnameT(txn, dest, flags) mdbx_txn_copy2pathnameW(txn, dest, path)
#else
#define mdbx_env_copyT(env, dest, flags) mdbx_env_copy(env, dest, flags)
#define mdbx_txn_copy2pathnameT(txn, dest, flags) mdbx_txn_copy2pathname(txn, dest, path)
#endif /* Windows */

LIBMDBX_API int mdbx_env_copy2fd(MDBX_env *env, mdbx_filehandle_t fd, MDBX_copy_flags_t flags);

LIBMDBX_API int mdbx_txn_copy2fd(MDBX_txn *txn, mdbx_filehandle_t fd, MDBX_copy_flags_t flags);

struct MDBX_stat {
  uint32_t ms_psize;          
  uint32_t ms_depth;          
  uint64_t ms_branch_pages;   
  uint64_t ms_leaf_pages;     
  uint64_t ms_overflow_pages; 
  uint64_t ms_entries;        
  uint64_t ms_mod_txnid;      
};
#ifndef __cplusplus
typedef struct MDBX_stat MDBX_stat;
#endif

LIBMDBX_API int mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn, MDBX_stat *stat, size_t bytes);

MDBX_DEPRECATED inline int mdbx_env_stat(const MDBX_env *env, MDBX_stat *stat, size_t bytes) {
  return mdbx_env_stat_ex(env, NULL, stat, bytes);
}

struct MDBX_envinfo {
  /* TODO: add st_nlink (filesystem link count of the database file) into
   * MDBX_envinfo — needed to detect unlink() of the database from under a
   * live process (used by shared-graph-memory module via mdbx_env_get_fd +
   * fstat). */
  struct {
    uint64_t lower;   
    uint64_t upper;   
    uint64_t current; 
    uint64_t shrink;  
    uint64_t grow;    
  } mi_geo;
  uint64_t mi_mapsize;                  
  uint64_t mi_dxb_fsize;                
  uint64_t mi_dxb_fallocated;           
  uint64_t mi_last_pgno;                
  uint64_t mi_recent_txnid;             
  uint64_t mi_latter_reader_txnid;      
  uint64_t mi_self_latter_reader_txnid; 
  uint64_t mi_meta_txnid[3], mi_meta_sign[3];
  uint32_t mi_maxreaders;   
  uint32_t mi_numreaders;   
  uint32_t mi_dxb_pagesize; 
  uint32_t mi_sys_pagesize; 
  uint32_t mi_sys_upcblk;   
  uint32_t mi_sys_ioblk;    

  struct {
    struct {
      uint64_t x, y;
    } current, meta[3];
  } mi_bootid;

  uint64_t mi_unsync_volume;
  uint64_t mi_autosync_threshold;
  uint32_t mi_since_sync_seconds16dot16;
  uint32_t mi_autosync_period_seconds16dot16;
  uint32_t mi_since_reader_check_seconds16dot16;
  uint32_t mi_mode;

  struct {
    uint64_t newly;    
    uint64_t cow;      
    uint64_t clone;    
    uint64_t split;    
    uint64_t merge;    
    uint64_t spill;    
    uint64_t unspill;  
    uint64_t wops;     
    uint64_t prefault; 
    uint64_t mincore;  
    uint64_t msync;    
    uint64_t fsync;    
  } mi_pgop_stat;

  /* GUID of the database DXB file. */
  struct {
    uint64_t x, y;
  } mi_dxbid;
};
#ifndef __cplusplus
typedef struct MDBX_envinfo MDBX_envinfo;
#endif

LIBMDBX_API int mdbx_env_info_ex(const MDBX_env *env, const MDBX_txn *txn, MDBX_envinfo *info, size_t bytes);
MDBX_DEPRECATED inline int mdbx_env_info(const MDBX_env *env, MDBX_envinfo *info, size_t bytes) {
  return mdbx_env_info_ex(env, NULL, info, bytes);
}

LIBMDBX_API int mdbx_env_sync_ex(MDBX_env *env, bool force, bool nonblock);

inline int mdbx_env_sync(MDBX_env * env) { return mdbx_env_sync_ex(env, true, false); }

inline int mdbx_env_sync_poll(MDBX_env * env) { return mdbx_env_sync_ex(env, false, true); }

inline int mdbx_env_set_syncbytes(MDBX_env * env, size_t threshold) {
  return mdbx_env_set_option(env, MDBX_opt_sync_bytes, threshold);
}

inline int mdbx_env_get_syncbytes(const MDBX_env *env, size_t *threshold) {
  int rc = MDBX_EINVAL;
  if (threshold) {
    uint64_t proxy = 0;
    rc = mdbx_env_get_option(env, MDBX_opt_sync_bytes, &proxy);
    MDBX_INLINE_API_ASSERT(proxy <= SIZE_MAX);
    *threshold = (size_t)proxy;
  }
  return rc;
}

inline int mdbx_env_set_syncperiod(MDBX_env * env, unsigned seconds_16dot16) {
  return mdbx_env_set_option(env, MDBX_opt_sync_period, seconds_16dot16);
}

inline int mdbx_env_get_syncperiod(const MDBX_env *env, unsigned *period_seconds_16dot16) {
  int rc = MDBX_EINVAL;
  if (period_seconds_16dot16) {
    uint64_t proxy = 0;
    rc = mdbx_env_get_option(env, MDBX_opt_sync_period, &proxy);
    MDBX_INLINE_API_ASSERT(proxy <= UINT32_MAX);
    *period_seconds_16dot16 = (unsigned)proxy;
  }
  return rc;
}

LIBMDBX_API int mdbx_env_close_ex(MDBX_env *env, bool dont_sync);

inline int mdbx_env_close(MDBX_env * env) { return mdbx_env_close_ex(env, false); }

#if defined(DOXYGEN) || !(defined(_WIN32) || defined(_WIN64))
LIBMDBX_API int mdbx_env_resurrect_after_fork(MDBX_env *env);
#endif /* Windows */

typedef enum MDBX_warmup_flags {
  MDBX_warmup_default = 0,

  MDBX_warmup_force = 1,

  MDBX_warmup_oomsafe = 2,

  MDBX_warmup_lock = 4,

  MDBX_warmup_touchlimit = 8,

  MDBX_warmup_release = 16,
} MDBX_warmup_flags_t;
MDBX_DEFINE_ENUM_FLAG_OPERATORS(MDBX_warmup_flags)


LIBMDBX_API int mdbx_env_warmup(const MDBX_env *env, const MDBX_txn *txn, MDBX_warmup_flags_t flags,
                                unsigned timeout_seconds_16dot16);

LIBMDBX_API int mdbx_env_set_flags(MDBX_env *env, MDBX_env_flags_t flags, bool onoff);

LIBMDBX_API int mdbx_env_get_flags(const MDBX_env *env, unsigned *flags);

LIBMDBX_API int mdbx_env_get_path(const MDBX_env *env, const char **dest);

#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
LIBMDBX_API int mdbx_env_get_pathW(const MDBX_env *env, const wchar_t **dest);
#define mdbx_env_get_pathT(env, dest) mdbx_env_get_pathW(env, dest)
#else
#define mdbx_env_get_pathT(env, dest) mdbx_env_get_path(env, dest)
#endif /* Windows */

LIBMDBX_API int mdbx_env_get_fd(const MDBX_env *env, mdbx_filehandle_t *fd);

LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t size_now, intptr_t size_upper,
                                      intptr_t growth_step, intptr_t shrink_threshold, intptr_t pagesize);

MDBX_DEPRECATED inline int mdbx_env_set_mapsize(MDBX_env * env, size_t size) {
  return mdbx_env_set_geometry(env, size, size, size, -1, -1, -1);
}

LIBMDBX_API int mdbx_is_readahead_reasonable(size_t volume, intptr_t redundancy);

MDBX_NOTHROW_CONST_FUNCTION inline intptr_t mdbx_limits_pgsize_min(void) { return MDBX_MIN_PAGESIZE; }

MDBX_NOTHROW_CONST_FUNCTION inline intptr_t mdbx_limits_pgsize_max(void) { return MDBX_MAX_PAGESIZE; }

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t mdbx_limits_dbsize_min(intptr_t pagesize);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t mdbx_limits_dbsize_max(intptr_t pagesize);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t mdbx_limits_keysize_max(intptr_t pagesize, MDBX_db_flags_t flags);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t mdbx_limits_keysize_min(MDBX_db_flags_t flags);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t mdbx_limits_valsize_max(intptr_t pagesize, MDBX_db_flags_t flags);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t mdbx_limits_valsize_min(MDBX_db_flags_t flags);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t mdbx_limits_pairsize4page_max(intptr_t pagesize,
                                                                               MDBX_db_flags_t flags);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t mdbx_limits_valsize4page_max(intptr_t pagesize, MDBX_db_flags_t flags);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t mdbx_limits_txnsize_max(intptr_t pagesize);

inline int mdbx_env_set_maxreaders(MDBX_env * env, unsigned readers) {
  return mdbx_env_set_option(env, MDBX_opt_max_readers, readers);
}

inline int mdbx_env_get_maxreaders(const MDBX_env *env, unsigned *readers) {
  int rc = MDBX_EINVAL;
  if (readers) {
    uint64_t proxy = 0;
    rc = mdbx_env_get_option(env, MDBX_opt_max_readers, &proxy);
    *readers = (unsigned)proxy;
  }
  return rc;
}

inline int mdbx_env_set_maxdbs(MDBX_env * env, MDBX_dbi dbs) {
  return mdbx_env_set_option(env, MDBX_opt_max_db, dbs);
}

inline int mdbx_env_get_maxdbs(const MDBX_env *env, MDBX_dbi *dbs) {
  int rc = MDBX_EINVAL;
  if (dbs) {
    uint64_t proxy = 0;
    rc = mdbx_env_get_option(env, MDBX_opt_max_db, &proxy);
    *dbs = (MDBX_dbi)proxy;
  }
  return rc;
}

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API size_t mdbx_default_pagesize(void);

LIBMDBX_API int mdbx_get_sysraminfo(intptr_t *page_size, intptr_t *total_pages, intptr_t *avail_pages);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_env_get_maxkeysize_ex(const MDBX_env *env, MDBX_db_flags_t flags);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_env_get_maxvalsize_ex(const MDBX_env *env, MDBX_db_flags_t flags);

MDBX_NOTHROW_PURE_FUNCTION MDBX_DEPRECATED LIBMDBX_API int mdbx_env_get_maxkeysize(const MDBX_env *env);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_env_get_pairsize4page_max(const MDBX_env *env, MDBX_db_flags_t flags);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_env_get_valsize4page_max(const MDBX_env *env, MDBX_db_flags_t flags);

LIBMDBX_API int mdbx_env_set_userctx(MDBX_env *env, void *ctx);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *mdbx_env_get_userctx(const MDBX_env *env);

LIBMDBX_API int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, MDBX_txn **txn,
                                  void *context);

inline int mdbx_txn_begin(MDBX_env * env, MDBX_txn *parent, MDBX_txn_flags_t flags, MDBX_txn **txn) {
  return mdbx_txn_begin_ex(env, parent, flags, txn, NULL);
}

LIBMDBX_API int mdbx_txn_clone(const MDBX_txn *origin, MDBX_txn **in_out_clone, void *context);

LIBMDBX_API int mdbx_txn_set_userctx(MDBX_txn *txn, void *ctx);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *mdbx_txn_get_userctx(const MDBX_txn *txn);

struct MDBX_txn_info {
  uint64_t txn_id;

  uint64_t txn_reader_lag;

  uint64_t txn_space_used;

  uint64_t txn_space_limit_soft;

  uint64_t txn_space_limit_hard;

  uint64_t txn_space_retired;

  uint64_t txn_space_leftover;

  uint64_t txn_space_dirty;

  uint64_t txn_pget;
};
#ifndef __cplusplus
typedef struct MDBX_txn_info MDBX_txn_info;
#endif

LIBMDBX_API int mdbx_txn_info(const MDBX_txn *txn, MDBX_txn_info *info, bool scan_rlt);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API MDBX_env *mdbx_txn_env(const MDBX_txn *txn);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API MDBX_txn_flags_t mdbx_txn_flags(const MDBX_txn *txn);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API uint64_t mdbx_txn_id(const MDBX_txn *txn);

struct MDBX_commit_latency {
  uint32_t preparation;
  uint32_t gc_wallclock;
  uint32_t audit;
  uint32_t write;
  uint32_t sync;
  uint32_t ending;
  uint32_t whole;
  uint32_t gc_cputime;

  struct {
    uint32_t wloops;
    uint32_t coalescences;
    uint32_t wipes;
    uint32_t flushes;
    uint32_t kicks;

    uint32_t work_counter;
    uint32_t work_rtime_monotonic;
    uint32_t work_xtime_cpu;
    uint32_t work_rsteps;
    uint32_t work_xpages;
    uint32_t work_majflt;

    uint32_t self_counter;
    uint32_t self_rtime_monotonic;
    uint32_t self_xtime_cpu;
    uint32_t self_rsteps;
    uint32_t self_xpages;
    uint32_t self_majflt;
    struct {
      uint32_t time;
      uint64_t volume;
      uint32_t calls;
    } pnl_merge_work, pnl_merge_self;
    uint32_t max_reader_lag;
    uint32_t max_retained_pages;
  } gc_prof;
};
#ifndef __cplusplus
typedef struct MDBX_commit_latency MDBX_commit_latency;
#endif

LIBMDBX_API int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency);

LIBMDBX_API int mdbx_txn_checkpoint(MDBX_txn *txn, MDBX_txn_flags_t weakening_durability, MDBX_commit_latency *latency);

LIBMDBX_API int mdbx_txn_commit_embark_read(MDBX_txn **ptxn, MDBX_commit_latency *latency);

LIBMDBX_API int mdbx_txn_amend(MDBX_txn *read_txn, MDBX_txn **ptr_write_txn, MDBX_txn_flags_t flags, void *context);

LIBMDBX_API int mdbx_txn_rollback(MDBX_txn *txn);

inline int mdbx_txn_commit(MDBX_txn * txn) { return mdbx_txn_commit_ex(txn, NULL); }

LIBMDBX_API int mdbx_txn_abort_ex(MDBX_txn *txn, MDBX_commit_latency *latency);

inline int mdbx_txn_abort(MDBX_txn * txn) { return mdbx_txn_abort_ex(txn, NULL); }

LIBMDBX_API int mdbx_txn_break(MDBX_txn *txn);

LIBMDBX_API int mdbx_txn_reset(MDBX_txn *txn);

LIBMDBX_API int mdbx_txn_park(MDBX_txn *txn, bool autounpark);

LIBMDBX_API int mdbx_txn_unpark(MDBX_txn *txn, bool restart_if_ousted);

LIBMDBX_API int mdbx_txn_renew(MDBX_txn *txn);

LIBMDBX_API int mdbx_txn_refresh(MDBX_txn *txn);

struct MDBX_canary {
  uint64_t x, y, z, v;
};
#ifndef __cplusplus
typedef struct MDBX_canary MDBX_canary;
#endif

LIBMDBX_API int mdbx_canary_put(MDBX_txn *txn, const MDBX_canary *canary);

LIBMDBX_API int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary);

typedef int (*MDBX_cmp_func)(const MDBX_val *a, const MDBX_val *b) MDBX_CXX17_NOEXCEPT;

LIBMDBX_API int mdbx_dbi_open(MDBX_txn *txn, const char *name, MDBX_db_flags_t flags, MDBX_dbi *dbi);
LIBMDBX_API int mdbx_dbi_open2(MDBX_txn *txn, const MDBX_val *name, MDBX_db_flags_t flags, MDBX_dbi *dbi);

MDBX_DEPRECATED LIBMDBX_API int mdbx_dbi_open_ex(MDBX_txn *txn, const char *name, MDBX_db_flags_t flags, MDBX_dbi *dbi,
                                                 MDBX_cmp_func keycmp, MDBX_cmp_func datacmp);
MDBX_DEPRECATED LIBMDBX_API int mdbx_dbi_open_ex2(MDBX_txn *txn, const MDBX_val *name, MDBX_db_flags_t flags,
                                                  MDBX_dbi *dbi, MDBX_cmp_func keycmp, MDBX_cmp_func datacmp);

LIBMDBX_API int mdbx_dbi_rename(MDBX_txn *txn, MDBX_dbi dbi, const char *name);
LIBMDBX_API int mdbx_dbi_rename2(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *name);

typedef int (*MDBX_table_enum_func)(void *ctx, const MDBX_txn *txn, const MDBX_val *name, MDBX_db_flags_t flags,
                                    const struct MDBX_stat *stat, MDBX_dbi dbi) MDBX_CXX17_NOEXCEPT;

LIBMDBX_API int mdbx_enumerate_tables(const MDBX_txn *txn, MDBX_table_enum_func func, void *ctx);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API uint64_t mdbx_key_from_jsonInteger(const int64_t json_integer);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API uint64_t mdbx_key_from_double(const double ieee754_64bit);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API uint64_t mdbx_key_from_ptrdouble(const double *const ieee754_64bit);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API uint32_t mdbx_key_from_float(const float ieee754_32bit);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API uint32_t mdbx_key_from_ptrfloat(const float *const ieee754_32bit);

MDBX_NOTHROW_CONST_FUNCTION inline uint64_t mdbx_key_from_int64(const int64_t i64) {
  return UINT64_C(0x8000000000000000) + i64;
}

MDBX_NOTHROW_CONST_FUNCTION inline uint32_t mdbx_key_from_int32(const int32_t i32) {
  return UINT32_C(0x80000000) + i32;
}

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int64_t mdbx_jsonInteger_from_key(const MDBX_val);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API double mdbx_double_from_key(const MDBX_val);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API float mdbx_float_from_key(const MDBX_val);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int32_t mdbx_int32_from_key(const MDBX_val);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int64_t mdbx_int64_from_key(const MDBX_val);

LIBMDBX_API int mdbx_dbi_stat(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *stat, size_t bytes);

LIBMDBX_API int mdbx_dbi_dupsort_depthmask(const MDBX_txn *txn, MDBX_dbi dbi, uint32_t *mask);

typedef enum MDBX_dbi_state {
  MDBX_DBI_DIRTY = 0x01,
  MDBX_DBI_STALE = 0x02,
  MDBX_DBI_FRESH = 0x04,
  MDBX_DBI_CREAT = 0x08,
} MDBX_dbi_state_t;
MDBX_DEFINE_ENUM_FLAG_OPERATORS(MDBX_dbi_state)


LIBMDBX_API int mdbx_dbi_flags_ex(const MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags, unsigned *state);
inline int mdbx_dbi_flags(const MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags) {
  unsigned state;
  return mdbx_dbi_flags_ex(txn, dbi, flags, &state);
}

LIBMDBX_API int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi);

LIBMDBX_API int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, bool del);

LIBMDBX_API int mdbx_get(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data);

LIBMDBX_API int mdbx_get_ex(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data, size_t *values_count);

LIBMDBX_API int mdbx_get_equal_or_great(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data);

typedef struct MDBX_cache_entry {
  uint64_t trunk_txnid;          
  uint64_t last_confirmed_txnid; 
  size_t offset;                 
  uint32_t length;               
} MDBX_cache_entry_t;

inline void mdbx_cache_init(MDBX_cache_entry_t * entry) {
  entry->offset = 0;
  entry->length = 0;
  entry->trunk_txnid = 0;
  entry->last_confirmed_txnid = 0;
}

typedef enum MDBX_cache_status {
  MDBX_CACHE_ERROR = -3,

  MDBX_CACHE_BEHIND = -2,

  MDBX_CACHE_UNABLE = -1,

  MDBX_CACHE_RACE = 0,

  MDBX_CACHE_DIRTY = 1,

  MDBX_CACHE_HIT = 2,

  MDBX_CACHE_CONFIRMED = 3,

  MDBX_CACHE_REFRESHED = 4
} MDBX_cache_status_t;

typedef struct MDBX_cache_result {
  MDBX_error_t errcode;
  MDBX_cache_status_t status;
} MDBX_cache_result_t;

LIBMDBX_API MDBX_cache_result_t mdbx_cache_get(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data,
                                               volatile MDBX_cache_entry_t *entry);

LIBMDBX_API MDBX_cache_result_t mdbx_cache_get_SingleThreaded(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
                                                              MDBX_val *data, MDBX_cache_entry_t *entry);

LIBMDBX_API int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, MDBX_put_flags_t flags);

LIBMDBX_API int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *new_data, MDBX_val *old_data,
                             MDBX_put_flags_t flags);

typedef int (*MDBX_preserve_func)(void *context, MDBX_val *target, const void *src, size_t bytes);

LIBMDBX_API int mdbx_replace_ex(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *new_data,
                                MDBX_val *old_data, MDBX_put_flags_t flags, MDBX_preserve_func preserver,
                                void *preserver_context);

LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, const MDBX_val *data);

LIBMDBX_API MDBX_cursor *mdbx_cursor_create(void *context);

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);

LIBMDBX_API int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *cursor, MDBX_dbi dbi);

LIBMDBX_API int mdbx_cursor_unbind(MDBX_cursor *cursor);

LIBMDBX_API int mdbx_cursor_reset(MDBX_cursor *cursor);

LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **cursor);

LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor);

LIBMDBX_API int mdbx_cursor_close2(MDBX_cursor *cursor);

LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count);

inline int mdbx_txn_release_all_cursors(const MDBX_txn *txn, bool unbind) {
  return mdbx_txn_release_all_cursors_ex(txn, unbind, NULL);
}

LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API MDBX_txn *mdbx_cursor_txn(const MDBX_cursor *cursor);

LIBMDBX_API MDBX_dbi mdbx_cursor_dbi(const MDBX_cursor *cursor);

LIBMDBX_API int mdbx_cursor_copy(const MDBX_cursor *src, MDBX_cursor *dest);

LIBMDBX_API int mdbx_cursor_compare(const MDBX_cursor *left, const MDBX_cursor *right, bool ignore_multival);

LIBMDBX_API int mdbx_cursor_get(MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data, MDBX_cursor_op op);

LIBMDBX_API int mdbx_cursor_ignord(MDBX_cursor *cursor);

typedef int (*MDBX_predicate_func)(void *context, MDBX_val *key, MDBX_val *value, void *arg) MDBX_CXX17_NOEXCEPT;

LIBMDBX_API int mdbx_cursor_scan(MDBX_cursor *cursor, MDBX_predicate_func predicate, void *context,
                                 MDBX_cursor_op start_op, MDBX_cursor_op turn_op, void *arg);

LIBMDBX_API int mdbx_cursor_scan_from(MDBX_cursor *cursor, MDBX_predicate_func predicate, void *context,
                                      MDBX_cursor_op from_op, MDBX_val *from_key, MDBX_val *from_value,
                                      MDBX_cursor_op turn_op, void *arg);

LIBMDBX_API int mdbx_cursor_get_batch(MDBX_cursor *cursor, size_t *count, MDBX_val *pairs, size_t limit,
                                      MDBX_cursor_op op);

LIBMDBX_API int mdbx_cursor_put(MDBX_cursor *cursor, const MDBX_val *key, MDBX_val *data, MDBX_put_flags_t flags);

LIBMDBX_API int mdbx_cursor_del(MDBX_cursor *cursor, MDBX_put_flags_t flags);

LIBMDBX_API int mdbx_cursor_delete_range(MDBX_cursor *begin, MDBX_cursor *end, bool end_including,
                                         uint64_t *number_of_affected);

LIBMDBX_API int mdbx_cursor_distance(const MDBX_cursor *first, const MDBX_cursor *last, intptr_t *distance,
                                     unsigned deepness);

LIBMDBX_API int mdbx_cursor_scroll(MDBX_cursor *cursor, intptr_t amount, unsigned deepness);

LIBMDBX_API int mdbx_cursor_distribute(const MDBX_cursor *first, const MDBX_cursor *last, MDBX_cursor **array,
                                       intptr_t count, unsigned deepness);

typedef enum MDBX_bunch_action {
  MDBX_DELETE_CURRENT_VALUE,
  MDBX_DELETE_CURRENT_MULTIVAL_BEFORE_EXCLUDING,
  MDBX_DELETE_CURRENT_MULTIVAL_BEFORE_INCLUDING,
  MDBX_DELETE_CURRENT_MULTIVAL_AFTER_INCLUDING,
  MDBX_DELETE_CURRENT_MULTIVAL_AFTER_EXCLUDING,
  MDBX_DELETE_CURRENT_MULTIVAL_ALL,
  MDBX_DELETE_BEFORE_EXCLUDING,
  MDBX_DELETE_BEFORE_INCLUDING,
  MDBX_DELETE_AFTER_INCLUDING,
  MDBX_DELETE_AFTER_EXCLUDING,
  MDBX_DELETE_WHOLE,
} MDBX_bunch_action_t;

LIBMDBX_API int mdbx_cursor_bunch_delete(MDBX_cursor *cursor, MDBX_bunch_action_t action, uint64_t *number_of_affected);

LIBMDBX_API int mdbx_cursor_count(const MDBX_cursor *cursor, size_t *count);

LIBMDBX_API int mdbx_cursor_count_ex(const MDBX_cursor *cursor, size_t *count, MDBX_stat *stat, size_t bytes);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_cursor_eof(const MDBX_cursor *cursor);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_cursor_on_first(const MDBX_cursor *cursor);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_cursor_on_first_dup(const MDBX_cursor *cursor);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_cursor_on_last(const MDBX_cursor *cursor);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_cursor_on_last_dup(const MDBX_cursor *cursor);


LIBMDBX_API int mdbx_estimate_distance(const MDBX_cursor *first, const MDBX_cursor *last, ptrdiff_t *distance_items);

LIBMDBX_API int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data, MDBX_cursor_op move_op,
                                   ptrdiff_t *distance_items);

LIBMDBX_API int mdbx_estimate_range(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *begin_key,
                                    const MDBX_val *begin_data, const MDBX_val *end_key, const MDBX_val *end_data,
                                    ptrdiff_t *distance_items);

#define MDBX_EPSILON ((MDBX_val *)((ptrdiff_t)-1))

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr);

LIBMDBX_API int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result, uint64_t increment);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_cmp(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
                                                    const MDBX_val *b);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API MDBX_cmp_func mdbx_get_keycmp(MDBX_db_flags_t flags);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_dcmp(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
                                                     const MDBX_val *b);

MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API MDBX_cmp_func mdbx_get_datacmp(MDBX_db_flags_t flags);

typedef int (*MDBX_reader_list_func)(void *ctx, int num, int slot, mdbx_pid_t pid, mdbx_tid_t thread, uint64_t txnid,
                                     uint64_t lag, size_t bytes_used, size_t bytes_retained) MDBX_CXX17_NOEXCEPT;

LIBMDBX_API int mdbx_reader_list(const MDBX_env *env, MDBX_reader_list_func func, void *ctx);

LIBMDBX_API int mdbx_reader_check(MDBX_env *env, int *dead);

MDBX_DEPRECATED LIBMDBX_API int mdbx_txn_straggler(const MDBX_txn *txn, int *percent);

LIBMDBX_API int mdbx_thread_register(const MDBX_env *env);

LIBMDBX_API int mdbx_thread_unregister(const MDBX_env *env);

typedef int (*MDBX_hsr_func)(const MDBX_env *env, const MDBX_txn *txn, mdbx_pid_t pid, mdbx_tid_t tid, uint64_t laggard,
                             unsigned gap, size_t space, int retry) MDBX_CXX17_NOEXCEPT;

LIBMDBX_API int mdbx_env_set_hsr(MDBX_env *env, MDBX_hsr_func hsr_callback);

MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API MDBX_hsr_func mdbx_env_get_hsr(const MDBX_env *env);


LIBMDBX_API int mdbx_txn_lock(MDBX_env *env, bool dont_wait);

LIBMDBX_API int mdbx_txn_unlock(MDBX_env *env);

LIBMDBX_API int mdbx_env_open_for_recovery(MDBX_env *env, const char *pathname, unsigned target_meta, bool writeable);

#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
LIBMDBX_API int mdbx_env_open_for_recoveryW(MDBX_env *env, const wchar_t *pathname, unsigned target_meta,
                                            bool writeable);
#define mdbx_env_open_for_recoveryT(env, pathname, target_mets, writeable)                                             \
  mdbx_env_open_for_recoveryW(env, pathname, target_mets, writeable)
#else
#define mdbx_env_open_for_recoveryT(env, pathname, target_mets, writeable)                                             \
  mdbx_env_open_for_recovery(env, pathname, target_mets, writeable)
#endif /* Windows */

LIBMDBX_API int mdbx_env_turn_for_recovery(MDBX_env *env, unsigned target_meta);

LIBMDBX_API int mdbx_preopen_snapinfo(const char *pathname, MDBX_envinfo *info, size_t bytes);
#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
LIBMDBX_API int mdbx_preopen_snapinfoW(const wchar_t *pathname, MDBX_envinfo *info, size_t bytes);
#define mdbx_preopen_snapinfoT(pathname, info, bytes) mdbx_preopen_snapinfoW(pathname, info, bytes)
#else
#define mdbx_preopen_snapinfoT(pathname, info, bytes) mdbx_preopen_snapinfo(pathname, info, bytes)
#endif /* Windows */

typedef enum MDBX_chk_flags {
  MDBX_CHK_DEFAULTS = 0,

  MDBX_CHK_READWRITE = 1,

  MDBX_CHK_SKIP_BTREE_TRAVERSAL = 2,

  MDBX_CHK_SKIP_KV_TRAVERSAL = 4,

  MDBX_CHK_IGNORE_ORDER = 8
} MDBX_chk_flags_t;
MDBX_DEFINE_ENUM_FLAG_OPERATORS(MDBX_chk_flags)


typedef enum MDBX_chk_severity {
  MDBX_chk_severity_prio_shift = 4,
  MDBX_chk_severity_kind_mask = 0xF,
  MDBX_chk_fatal = 0x00u,
  MDBX_chk_error = 0x11u,
  MDBX_chk_warning = 0x22u,
  MDBX_chk_notice = 0x33u,
  MDBX_chk_result = 0x44u,
  MDBX_chk_resolution = 0x55u,
  MDBX_chk_processing = 0x56u,
  MDBX_chk_info = 0x67u,
  MDBX_chk_verbose = 0x78u,
  MDBX_chk_details = 0x89u,
  MDBX_chk_extra = 0x9Au
} MDBX_chk_severity_t;

typedef enum MDBX_chk_stage {
  MDBX_chk_none,
  MDBX_chk_init,
  MDBX_chk_lock,
  MDBX_chk_meta,
  MDBX_chk_tree,
  MDBX_chk_gc,
  MDBX_chk_space,
  MDBX_chk_maindb,
  MDBX_chk_tables,
  MDBX_chk_conclude,
  MDBX_chk_unlock,
  MDBX_chk_finalize
} MDBX_chk_stage_t;

typedef struct MDBX_chk_line {
  struct MDBX_chk_context *ctx;
  uint8_t severity, scope_depth, empty;
  char *begin, *end, *out;
} MDBX_chk_line_t;

typedef struct MDBX_chk_issue {
  struct MDBX_chk_issue *next;
  size_t count;
  const char *caption;
} MDBX_chk_issue_t;

typedef struct MDBX_chk_scope {
  MDBX_chk_issue_t *issues;
  struct MDBX_chk_internal *internal;
  const void *object;
  MDBX_chk_stage_t stage;
  MDBX_chk_severity_t verbosity;
  size_t subtotal_issues;
  union {
    void *ptr;
    size_t number;
  } usr_z, usr_v, usr_o;
} MDBX_chk_scope_t;

typedef struct MDBX_chk_user_table_cookie MDBX_chk_user_table_cookie_t;

struct MDBX_chk_histogram {
  size_t amount, count, le1_amount, le1_count;
  struct {
    size_t begin, end, amount, count;
  } ranges[9];
};

typedef struct MDBX_chk_table {
  MDBX_chk_user_table_cookie_t *cookie;

#define MDBX_CHK_MAIN ((void *)((ptrdiff_t)0))
#define MDBX_CHK_GC ((void *)((ptrdiff_t)-1))
#define MDBX_CHK_META ((void *)((ptrdiff_t)-2))

  MDBX_val name;
  MDBX_db_flags_t flags;
  int id;

  size_t payload_bytes, lost_bytes;
  struct {
    size_t all, empty, broken;
    size_t branch, leaf;
    size_t nested_branch, nested_leaf, nested_subleaf;
  } pages;
  struct {
    struct MDBX_chk_histogram height;
    struct MDBX_chk_histogram large_pages;
    struct MDBX_chk_histogram nested_height_or_gc_span_length;
    struct MDBX_chk_histogram key_len;
    struct MDBX_chk_histogram val_len;
    struct MDBX_chk_histogram multival;
    struct MDBX_chk_histogram tree_density;
    struct MDBX_chk_histogram large_or_nested_density;
    struct MDBX_chk_histogram page_age;
    struct MDBX_chk_histogram pgno;
  } histogram;
} MDBX_chk_table_t;

typedef struct MDBX_chk_context {
  struct MDBX_chk_internal *internal;
  MDBX_env *env;
  MDBX_txn *txn;
  MDBX_chk_scope_t *scope;
  uint8_t scope_nesting;
  struct {
    size_t total_payload_bytes;
    size_t table_total, table_processed;
    size_t total_unused_bytes, unused_pages;
    size_t processed_pages, reclaimable_pages, gc_pages, alloc_pages, backed_pages;
    size_t problems_meta, tree_problems, gc_tree_problems, kv_tree_problems, problems_gc, problems_kv, total_problems;
    uint64_t steady_txnid, recent_txnid;
    struct MDBX_chk_histogram histogram_page_age;
    struct MDBX_chk_histogram histogram_pgno_payload;
    struct MDBX_chk_histogram histogram_pgno_retained;
    const MDBX_chk_table_t *const *tables;
  } result;
} MDBX_chk_context_t;

typedef struct MDBX_chk_callbacks {
  bool (*check_break)(MDBX_chk_context_t *ctx);
  int (*scope_push)(MDBX_chk_context_t *ctx, MDBX_chk_scope_t *outer, MDBX_chk_scope_t *inner, const char *fmt,
                    va_list args);
  int (*scope_conclude)(MDBX_chk_context_t *ctx, MDBX_chk_scope_t *outer, MDBX_chk_scope_t *inner, int err);
  void (*scope_pop)(MDBX_chk_context_t *ctx, MDBX_chk_scope_t *outer, MDBX_chk_scope_t *inner);
  void (*issue)(MDBX_chk_context_t *ctx, const char *object, uint64_t entry_number, const char *issue,
                const char *extra_fmt, va_list extra_args);
  MDBX_chk_user_table_cookie_t *(*table_filter)(MDBX_chk_context_t *ctx, const MDBX_val *name, MDBX_db_flags_t flags);
  int (*table_conclude)(MDBX_chk_context_t *ctx, const MDBX_chk_table_t *table, MDBX_cursor *cursor, int err);
  void (*table_dispose)(MDBX_chk_context_t *ctx, const MDBX_chk_table_t *table);

  int (*table_handle_kv)(MDBX_chk_context_t *ctx, const MDBX_chk_table_t *table, size_t entry_number,
                         const MDBX_val *key, const MDBX_val *value);

  int (*stage_begin)(MDBX_chk_context_t *ctx, MDBX_chk_stage_t);
  int (*stage_end)(MDBX_chk_context_t *ctx, MDBX_chk_stage_t, int err);

  MDBX_chk_line_t *(*print_begin)(MDBX_chk_context_t *ctx, MDBX_chk_severity_t severity);
  void (*print_flush)(MDBX_chk_line_t *);
  void (*print_done)(MDBX_chk_line_t *);
  void (*print_chars)(MDBX_chk_line_t *, const char *str, size_t len);
  void (*print_format)(MDBX_chk_line_t *, const char *fmt, va_list args);
  void (*print_size)(MDBX_chk_line_t *, const char *prefix, const uint64_t value, const char *suffix);
} MDBX_chk_callbacks_t;

LIBMDBX_API int mdbx_env_chk(MDBX_env *env, const MDBX_chk_callbacks_t *cb, MDBX_chk_context_t *ctx,
                             const MDBX_chk_flags_t flags, MDBX_chk_severity_t verbosity,
                             unsigned timeout_seconds_16dot16);

LIBMDBX_API int mdbx_env_chk_encount_problem(MDBX_chk_context_t *ctx);

LIBMDBX_API const char *mdbx_ratio2digits(uint64_t numerator, uint64_t denominator, int precision, char *buffer,
                                          size_t buffer_size);

LIBMDBX_API const char *mdbx_ratio2percents(uint64_t value, uint64_t whole, char *buffer, size_t buffer_size);


typedef int (*MDBX_gc_iter_func)(void *ctx, const MDBX_txn *txn, uint64_t span_txnid, size_t span_pgno,
                                 size_t span_length, bool span_is_reclaimable) MDBX_CXX17_NOEXCEPT;

typedef struct MDBX_gc_info {
  size_t pages_total;     
  size_t pages_backed;    
  size_t pages_allocated; 
  size_t pages_gc;        
  struct {
    size_t pages; 
    struct MDBX_chk_histogram
        span_histogram; 
    struct MDBX_chk_histogram pgno_distribution; 
  } gc_reclaimable;
  size_t max_reader_lag;
  size_t max_retained_pages;
} MDBX_gc_info_t;

LIBMDBX_API int mdbx_gc_info(MDBX_txn *txn, MDBX_gc_info_t *info, size_t bytes, MDBX_gc_iter_func iter_func,
                             void *iter_ctx);

typedef enum MDBX_defrag_stopping_reasons {
  MDBX_defrag_noobstacles = 0,
  MDBX_defrag_step_size = 1,         
  MDBX_defrag_large_chunk = 2,       
  MDBX_defrag_discontinued = 4,      
  MDBX_defrag_laggard_reader = 8,    
  MDBX_defrag_enough_threshold = 16, 
  MDBX_defrag_time_limit = 32,       
  MDBX_defrag_aborted = 64,          
  MDBX_defrag_error = 128            
} MDBX_defrag_stopping_reasons_t;
MDBX_DEFINE_ENUM_FLAG_OPERATORS(MDBX_defrag_stopping_reasons)


typedef struct MDBX_defrag_result {
  intptr_t pages_shrinked;

  size_t pages_moved;

  size_t pages_scheduled;

  size_t pages_retained;

  size_t pages_left;

  size_t pages_whole;

  size_t obstructed_pgno;

  size_t obstructed_span;

  uint64_t obstructed_txnid;
  mdbx_tid_t obstructor_tid;
  mdbx_pid_t obstructor_pid;

  unsigned rough_estimation_cycle_progress_permille;

  unsigned cycles;

  unsigned stopping_reasons;

  size_t spent_time_dot16;
} MDBX_defrag_result_t;

typedef int (*MDBX_defrag_notify_func)(void *ctx, const MDBX_defrag_result_t *progress) MDBX_CXX17_NOEXCEPT;

LIBMDBX_API int mdbx_env_defrag(MDBX_env *env, size_t defrag_atleast, size_t time_atleast_dot16, size_t defrag_enough,
                                size_t time_limit_dot16, intptr_t acceptable_backlash, intptr_t preferred_batch,
                                MDBX_defrag_notify_func progress_callback, void *ctx, MDBX_defrag_result_t *result);


#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* LIBMDBX_H */