mirror of
https://github.com/isar/libmdbx.git
synced 2024-12-28 18:38:48 +08:00
mdbx++: Initial C++ API (some extra methods are not implemented).
Change-Id: I0478d0c94dcd12b52916e87815e5731817407c3c
This commit is contained in:
parent
e3f0db7708
commit
88a4b8cb9b
@ -62,7 +62,8 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/version.c.in" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/man1" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/mdbx_chk.c")
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/mdbx_chk.c" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/mdbx.c++")
|
||||
set(MDBX_AMALGAMATED_SOURCE FALSE)
|
||||
find_program(GIT git)
|
||||
if(NOT GIT)
|
||||
@ -71,6 +72,7 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git" AND
|
||||
set(MDBX_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/mdbx.c" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/mdbx.c++" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/man1" AND
|
||||
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/mdbx_chk.c")
|
||||
@ -294,14 +296,30 @@ else()
|
||||
endif(SUBPROJECT)
|
||||
|
||||
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)
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_17 HAS_CXX17)
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_20 HAS_CXX20)
|
||||
if(NOT DEFINED MDBX_CXX_STANDARD)
|
||||
if(DEFINED CMAKE_CXX_STANDARD)
|
||||
set(MDBX_CXX_STANDARD ${CMAKE_CXX_STANDARD})
|
||||
elseif(NOT HAS_CXX20 LESS 0)
|
||||
set(MDBX_CXX_STANDARD 20)
|
||||
elseif(NOT HAS_CXX17 LESS 0)
|
||||
set(MDBX_CXX_STANDARD 17)
|
||||
elseif(NOT HAS_CXX14 LESS 0)
|
||||
set(MDBX_CXX_STANDARD 14)
|
||||
elseif(NOT HAS_CXX11 LESS 0)
|
||||
set(MDBX_CXX_STANDARD 11)
|
||||
else()
|
||||
set(MDBX_CXX_STANDARD 98)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT HAS_C11 LESS 0)
|
||||
set(MDBX_C_STANDARD 11)
|
||||
else()
|
||||
set(MDBX_C_STANDARD 99)
|
||||
endif()
|
||||
if(MDBX_C_STANDARD)
|
||||
message(STATUS "Use C${MDBX_C_STANDARD} for libmdbx")
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows" AND EXISTS "${MDBX_SOURCE_DIR}/ntdll.def")
|
||||
if(MSVC)
|
||||
@ -392,7 +410,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR IOS)
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
if(MDBX_NTDLL_EXTRA_IMPLIB)
|
||||
add_mdbx_option(MDBX_AVOID_CRT "Avoid dependence from MSVC CRT and use ntdll.dll instead" ${NOT_SUBPROJECT})
|
||||
add_mdbx_option(MDBX_AVOID_CRT "Avoid dependence from MSVC CRT and use ntdll.dll instead" OFF)
|
||||
endif()
|
||||
add_mdbx_option(MDBX_CONFIG_MANUAL_TLS_CALLBACK
|
||||
"Provide mdbx_dll_handler() for manual initialization" OFF)
|
||||
@ -409,8 +427,7 @@ option(MDBX_FORCE_ASSERTIONS "Force enable assertion checking" OFF)
|
||||
|
||||
if(NOT MDBX_AMALGAMATED_SOURCE)
|
||||
add_mdbx_option(MDBX_ALLOY_BUILD "Build MDBX library through single/alloyed object file" ON)
|
||||
option(MDBX_ENABLE_TESTS "Build MDBX tests" ${BUILD_TESTING})
|
||||
endif(NOT MDBX_AMALGAMATED_SOURCE)
|
||||
endif()
|
||||
|
||||
if((MDBX_BUILD_TOOLS OR MDBX_ENABLE_TESTS) AND MDBX_BUILD_SHARED_LIBRARY)
|
||||
add_mdbx_option(MDBX_LINK_TOOLS_NONSTATIC "Link MDBX tools with non-static libmdbx" OFF)
|
||||
@ -418,6 +435,22 @@ else()
|
||||
unset(MDBX_LINK_TOOLS_NONSTATIC CACHE)
|
||||
endif()
|
||||
|
||||
if(MDBX_CXX_STANDARD GREATER_EQUAL 11 AND MDBX_CXX_STANDARD LESS 83)
|
||||
if(NOT MDBX_AMALGAMATED_SOURCE)
|
||||
option(MDBX_ENABLE_TESTS "Build MDBX tests" ${BUILD_TESTING})
|
||||
endif()
|
||||
if(NOT MDBX_AVOID_CRT
|
||||
AND NOT (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5)
|
||||
AND NOT (CMAKE_COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4)
|
||||
AND NOT (MSVC AND MSVC_VERSION LESS 1900))
|
||||
option(MDBX_BUILD_CXX "Build C++ portion" ON)
|
||||
else()
|
||||
set(MDBX_BUILD_CXX FALSE)
|
||||
endif()
|
||||
else()
|
||||
set(MDBX_BUILD_CXX FALSE)
|
||||
endif()
|
||||
|
||||
################################################################################
|
||||
################################################################################
|
||||
|
||||
@ -426,7 +459,7 @@ fetch_version(MDBX "${CMAKE_CURRENT_SOURCE_DIR}" FALSE)
|
||||
message(STATUS "libmdbx version is ${MDBX_VERSION}")
|
||||
|
||||
# sources list
|
||||
set(LIBMDBX_SOURCES mdbx.h "${CMAKE_CURRENT_BINARY_DIR}/config.h")
|
||||
set(LIBMDBX_SOURCES mdbx.h "${CMAKE_CURRENT_BINARY_DIR}/config.h" )
|
||||
if(MDBX_AMALGAMATED_SOURCE)
|
||||
list(APPEND LIBMDBX_SOURCES mdbx.c)
|
||||
else()
|
||||
@ -438,7 +471,7 @@ else()
|
||||
set(MDBX_BUILD_SOURCERY "${MDBX_SOURCERY_DIGEST}_${MDBX_SOURCERY_SUFFIX}")
|
||||
|
||||
if(MDBX_ALLOY_BUILD)
|
||||
list(APPEND LIBMDBX_SOURCES ${MDBX_SOURCE_DIR}/alloy.c)
|
||||
list(APPEND LIBMDBX_SOURCES "${MDBX_SOURCE_DIR}/alloy.c")
|
||||
include_directories("${MDBX_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
else()
|
||||
list(APPEND LIBMDBX_SOURCES
|
||||
@ -450,12 +483,24 @@ else()
|
||||
include_directories("${MDBX_SOURCE_DIR}")
|
||||
endif()
|
||||
endif(MDBX_AMALGAMATED_SOURCE)
|
||||
if(MDBX_BUILD_CXX)
|
||||
message(STATUS "Use C${MDBX_C_STANDARD} and C++${MDBX_CXX_STANDARD} for libmdbx")
|
||||
list(APPEND LIBMDBX_SOURCES "${MDBX_SOURCE_DIR}/mdbx.c++" mdbx.h++)
|
||||
else()
|
||||
message(STATUS "Use C${MDBX_C_STANDARD} for libmdbx but C++ portion is disabled")
|
||||
endif()
|
||||
|
||||
macro(target_setup_options TARGET)
|
||||
if(DEFINED INTERPROCEDURAL_OPTIMIZATION)
|
||||
set_target_properties(${TARGET} PROPERTIES
|
||||
INTERPROCEDURAL_OPTIMIZATION $<BOOL:${INTERPROCEDURAL_OPTIMIZATION}>)
|
||||
endif()
|
||||
set_target_properties(${TARGET} PROPERTIES
|
||||
C_STANDARD ${MDBX_C_STANDARD} C_STANDARD_REQUIRED ON)
|
||||
if(MDBX_BUILD_CXX)
|
||||
set_target_properties(${TARGET} PROPERTIES
|
||||
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
if(CC_HAS_FASTMATH)
|
||||
target_compile_options(${TARGET} PRIVATE "-ffast-math")
|
||||
endif()
|
||||
@ -479,6 +524,9 @@ macro(libmdbx_setup_libs TARGET MODE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
|
||||
target_link_libraries(${TARGET} ${MODE} log)
|
||||
endif()
|
||||
if(LIBCXX_FILESYSTEM AND MDBX_BUILD_CXX)
|
||||
target_link_libraries(${TARGET} ${MODE} ${LIBCXX_FILESYSTEM})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# build static library
|
||||
@ -650,10 +698,16 @@ endif(MDBX_INSTALL_STATIC)
|
||||
# collect options & build info
|
||||
string(TIMESTAMP MDBX_BUILD_TIMESTAMP UTC)
|
||||
set(MDBX_BUILD_FLAGS ${CMAKE_C_FLAGS})
|
||||
if(MDBX_BUILD_CXX)
|
||||
set(MDBX_BUILD_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
endif()
|
||||
|
||||
# append cmake's build-type flags and defines
|
||||
if(NOT CMAKE_CONFIGURATION_TYPES)
|
||||
list(APPEND MDBX_BUILD_FLAGS ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPERCASE}})
|
||||
if(MDBX_BUILD_CXX)
|
||||
list(APPEND MDBX_BUILD_FLAGS ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPERCASE}})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# get definitions
|
||||
|
19
ChangeLog.md
19
ChangeLog.md
@ -1,7 +1,7 @@
|
||||
ChangeLog
|
||||
---------
|
||||
|
||||
## v0.9.0 (in the development):
|
||||
## v0.9.0 (in the development)
|
||||
|
||||
Added features:
|
||||
|
||||
@ -9,10 +9,11 @@ Added features:
|
||||
- Functions to explicit reader threads (de)registration.
|
||||
- Separated enums for environment, sub-databases, transactions, copying and data-update flags.
|
||||
- Support for read transactions preparation (`MDBX_TXN_RDONLY_PREPARE` flag).
|
||||
- Draft: Native bindings for C++.
|
||||
|
||||
TODO:
|
||||
|
||||
- Native bindings for C++.
|
||||
- Finalize: Native bindings for C++.
|
||||
- Packages for AltLinux, Fedora/RHEL, Debian/Ubuntu.
|
||||
|
||||
Deprecated functions and flags:
|
||||
@ -23,7 +24,7 @@ Deprecated functions and flags:
|
||||
Just use `MDBX_SAFE_NOSYNC` or `MDBX_UTTERLY_NOSYNC` instead of it.
|
||||
|
||||
|
||||
## v0.8.2 2020-07-06:
|
||||
## v0.8.2 2020-07-06
|
||||
- Added support multi-opening the same DB in a process with SysV locking (BSD).
|
||||
- Fixed warnings & minors for LCC compiler (E2K).
|
||||
- Enabled to simultaneously open the same database from processes with and without the `MDBX_WRITEMAP` option.
|
||||
@ -38,7 +39,7 @@ Deprecated functions and flags:
|
||||
Now remapping with a change of address is performed automatically if there are no dependent readers in the current process.
|
||||
|
||||
|
||||
## v0.8.1 2020-06-12:
|
||||
## v0.8.1 2020-06-12
|
||||
- Minor change versioning. The last number in the version now means the number of commits since last release/tag.
|
||||
- Provide ChangeLog file.
|
||||
- Fix for using libmdbx as a C-only sub-project with CMake.
|
||||
@ -48,7 +49,7 @@ Deprecated functions and flags:
|
||||
- Force enabling exceptions handling for MSVC (`/EHsc` option).
|
||||
|
||||
|
||||
## v0.8.0 2020-06-05:
|
||||
## v0.8.0 2020-06-05
|
||||
- Support for Android/Bionic.
|
||||
- Support for iOS.
|
||||
- Auto-handling `MDBX_NOSUBDIR` while opening for any existing database.
|
||||
@ -93,7 +94,7 @@ Deprecated functions and flags:
|
||||
- Avoid some GCC-analyzer false-positive warnings.
|
||||
|
||||
|
||||
## v0.7.0 2020-03-18:
|
||||
## v0.7.0 2020-03-18
|
||||
- Workarounds for Wine (Windows compatibility layer for Linux).
|
||||
- `MDBX_MAP_RESIZED` renamed to `MDBX_UNABLE_EXTEND_MAPSIZE`.
|
||||
- Clarify API description, fix typos.
|
||||
@ -105,7 +106,7 @@ Deprecated functions and flags:
|
||||
- Avoids extra error messages "bad txn" from mdbx_chk when DB is corrupted.
|
||||
|
||||
|
||||
## v0.6.0 2020-01-21:
|
||||
## v0.6.0 2020-01-21
|
||||
- Fix `mdbx_load` utility for custom comparators.
|
||||
- Fix checks related to `MDBX_APPEND` flag inside `mdbx_cursor_put()`.
|
||||
- Refine/fix dbi_bind() internals.
|
||||
@ -117,7 +118,7 @@ Deprecated functions and flags:
|
||||
- Clarify API description & comments, fix typos.
|
||||
|
||||
|
||||
## v0.5.0 2019-12-31:
|
||||
## v0.5.0 2019-12-31
|
||||
- Fix returning MDBX_RESULT_TRUE from page_alloc().
|
||||
- Fix false-positive ASAN issue.
|
||||
- Fix assertion for `MDBX_NOTLS` option.
|
||||
@ -132,7 +133,7 @@ Deprecated functions and flags:
|
||||
- Added install section for CMake.
|
||||
|
||||
|
||||
## v0.4.0 2019-12-02:
|
||||
## v0.4.0 2019-12-02
|
||||
- Support for Mac OSX, FreeBSD, NetBSD, OpenBSD, DragonFly BSD, OpenSolaris, OpenIndiana (AIX and HP-UX pending).
|
||||
- Use bootid for decisions of rollback.
|
||||
- Counting retired pages and extended transaction info.
|
||||
|
37
GNUmakefile
37
GNUmakefile
@ -43,7 +43,7 @@ define uname2sosuffix
|
||||
endef
|
||||
SO_SUFFIX := $(shell $(uname2sosuffix))
|
||||
|
||||
HEADERS := mdbx.h
|
||||
HEADERS := mdbx.h mdbx.h++
|
||||
LIBRARIES := libmdbx.a libmdbx.$(SO_SUFFIX)
|
||||
TOOLS := mdbx_stat mdbx_copy mdbx_dump mdbx_load mdbx_chk
|
||||
MANPAGES := mdbx_stat.1 mdbx_copy.1 mdbx_dump.1 mdbx_load.1 mdbx_chk.1
|
||||
@ -64,11 +64,11 @@ clean:
|
||||
*.gcov *.log *.err src/*.o test/*.o mdbx_example dist \
|
||||
config.h src/config.h src/version.c *.tar*
|
||||
|
||||
libmdbx.a: mdbx-static.o
|
||||
libmdbx.a: mdbx-static.o mdbx++-static.o
|
||||
$(AR) rs $@ $?
|
||||
|
||||
libmdbx.$(SO_SUFFIX): mdbx-dylib.o
|
||||
$(CC) $(CFLAGS) $^ -pthread -shared $(LDFLAGS) $(LIBS) -o $@
|
||||
libmdbx.$(SO_SUFFIX): mdbx-dylib.o mdbx++-dylib.o
|
||||
$(CXX) $(CXXFLAGS) $^ -pthread -shared $(LDFLAGS) $(LIBS) -o $@
|
||||
|
||||
#> dist-cutoff-begin
|
||||
ifeq ($(wildcard mdbx.c),mdbx.c)
|
||||
@ -85,12 +85,18 @@ config.h: mdbx.c $(lastword $(MAKEFILE_LIST))
|
||||
&& echo '#define MDBX_BUILD_TARGET "$(shell set -o pipefail; (LC_ALL=C $(CC) -v 2>&1 | grep -i '^Target:' | cut -d ' ' -f 2- || (LC_ALL=C $(CC) --version | grep -qi e2k && echo E2K) || echo 'Please use GCC or CLANG compatible compiler') | head -1)"' \
|
||||
) > $@
|
||||
|
||||
mdbx-dylib.o: config.h mdbx.c $(lastword $(MAKEFILE_LIST))
|
||||
mdbx-dylib.o: config.h mdbx.c mdbx.h $(lastword $(MAKEFILE_LIST))
|
||||
$(CC) $(CFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -DLIBMDBX_EXPORTS=1 -c mdbx.c -o $@
|
||||
|
||||
mdbx-static.o: config.h mdbx.c $(lastword $(MAKEFILE_LIST))
|
||||
mdbx-static.o: config.h mdbx.c mdbx.h $(lastword $(MAKEFILE_LIST))
|
||||
$(CC) $(CFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -ULIBMDBX_EXPORTS -c mdbx.c -o $@
|
||||
|
||||
mdbx++-dylib.o: config.h mdbx.c++ mdbx.h mdbx.h++ $(lastword $(MAKEFILE_LIST))
|
||||
$(CXX) $(CXXFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -DLIBMDBX_EXPORTS=1 -c mdbx.c++ -o $@
|
||||
|
||||
mdbx++-static.o: config.h mdbx.c++ mdbx.h mdbx.h++ $(lastword $(MAKEFILE_LIST))
|
||||
$(CXX) $(CXXFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -ULIBMDBX_EXPORTS -c mdbx.c++ -o $@
|
||||
|
||||
mdbx_%: mdbx_%.c libmdbx.a
|
||||
$(CC) $(CFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' $^ $(EXE_LDFLAGS) $(LIBS) -o $@
|
||||
|
||||
@ -117,7 +123,7 @@ endef
|
||||
|
||||
DIST_EXTRA := LICENSE README.md CMakeLists.txt GNUmakefile Makefile ChangeLog.md VERSION config.h.in ntdll.def \
|
||||
$(addprefix man1/, $(MANPAGES)) cmake/compiler.cmake cmake/profile.cmake cmake/utils.cmake
|
||||
DIST_SRC := mdbx.h mdbx.c $(addsuffix .c, $(TOOLS))
|
||||
DIST_SRC := mdbx.h mdbx.h++ mdbx.c mdbx.c++ $(addsuffix .c, $(TOOLS))
|
||||
|
||||
TEST_DB ?= $(shell [ -d /dev/shm ] && echo /dev/shm || echo /tmp)/mdbx-test.db
|
||||
TEST_LOG ?= $(shell [ -d /dev/shm ] && echo /dev/shm || echo /tmp)/mdbx-test.log.gz
|
||||
@ -270,8 +276,14 @@ docs/intro.md: docs/_preface.md docs/__characteristics.md docs/__improvements.md
|
||||
docs/usage.md: docs/__usage.md docs/_starting.md docs/__bindings.md
|
||||
echo -e "\\page usage Usage\n\\section getting Getting the libmdbx" | cat - $^ | sed 's/^Bindings$$/Bindings {#bindings}/' > $@
|
||||
|
||||
doxygen: docs/Doxyfile docs/overall.md docs/intro.md docs/usage.md mdbx.h src/options.h ChangeLog.md AUTHORS LICENSE
|
||||
rm -rf docs/html && cp mdbx.h src/options.h ChangeLog.md docs/ && (cd docs && doxygen Doxyfile) && cp AUTHORS LICENSE docs/html/
|
||||
doxygen: docs/Doxyfile docs/overall.md docs/intro.md docs/usage.md mdbx.h mdbx.h++ src/options.h ChangeLog.md AUTHORS LICENSE
|
||||
rm -rf docs/html && cp mdbx.h mdbx.h++ src/options.h ChangeLog.md docs/ && (cd docs && doxygen Doxyfile) && cp AUTHORS LICENSE docs/html/
|
||||
|
||||
mdbx++-dylib.o: src/config.h src/mdbx.c++ mdbx.h mdbx.h++ $(lastword $(MAKEFILE_LIST))
|
||||
$(CXX) $(CXXFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -DLIBMDBX_EXPORTS=1 -c src/mdbx.c++ -o $@
|
||||
|
||||
mdbx++-static.o: src/config.h src/mdbx.c++ mdbx.h mdbx.h++ $(lastword $(MAKEFILE_LIST))
|
||||
$(CXX) $(CXXFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -ULIBMDBX_EXPORTS -c src/mdbx.c++ -o $@
|
||||
|
||||
.PHONY: dist release-assets
|
||||
dist: libmdbx-sources-$(MDBX_VERSION_SUFFIX).tar.gz $(lastword $(MAKEFILE_LIST))
|
||||
@ -288,6 +300,9 @@ libmdbx-sources-$(MDBX_VERSION_SUFFIX).zip: $(addprefix dist/, $(DIST_SRC) $(DIS
|
||||
dist/mdbx.h: mdbx.h src/version.c $(lastword $(MAKEFILE_LIST))
|
||||
mkdir -p dist && cp $< $@
|
||||
|
||||
dist/mdbx.h++: mdbx.h++ src/version.c $(lastword $(MAKEFILE_LIST))
|
||||
mkdir -p dist && cp $< $@
|
||||
|
||||
dist/@tmp-shared_internals.inc: src/version.c $(ALLOY_DEPS) $(lastword $(MAKEFILE_LIST))
|
||||
mkdir -p dist && sed \
|
||||
-e 's|#pragma once|#define MDBX_ALLOY 1\n#define MDBX_BUILD_SOURCERY $(MDBX_BUILD_SOURCERY)|' \
|
||||
@ -302,6 +317,10 @@ dist/mdbx.c: dist/@tmp-shared_internals.inc $(lastword $(MAKEFILE_LIST))
|
||||
&& cat src/core.c src/osal.c src/version.c src/lck-windows.c src/lck-posix.c \
|
||||
) | grep -v -e '#include "' -e '#pragma once' | sed 's|@INCLUDE|#include|' > $@
|
||||
|
||||
dist/mdbx.c++: dist/@tmp-shared_internals.inc src/mdbx.c++ $(lastword $(MAKEFILE_LIST))
|
||||
mkdir -p dist && (cat dist/@tmp-shared_internals.inc && cat src/mdbx.c++) \
|
||||
| grep -v -e '#include "' -e '#pragma once' | sed 's|@INCLUDE|#include|;s|"mdbx.h"|"mdbx.h++"|' > $@
|
||||
|
||||
define dist-tool-rule
|
||||
dist/$(1).c: src/$(1).c src/wingetopt.h src/wingetopt.c \
|
||||
dist/@tmp-shared_internals.inc $(lastword $(MAKEFILE_LIST))
|
||||
|
@ -2,6 +2,9 @@ version: 0.9.0.{build}
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015
|
||||
TOOLSET: 140
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
CMAKE_GENERATOR: Visual Studio 16 2019
|
||||
TOOLSET: 142
|
||||
@ -25,9 +28,6 @@ environment:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
CMAKE_GENERATOR: Visual Studio 15 2017
|
||||
TOOLSET: 141
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015
|
||||
TOOLSET: 140
|
||||
|
||||
branches:
|
||||
except:
|
||||
|
@ -606,8 +606,9 @@ macro(setup_compile_flags)
|
||||
if(MSVC_VERSION LESS 1900)
|
||||
message(FATAL_ERROR "At least \"Microsoft C/C++ Compiler\" version 19.0.24234.1 (Visual Studio 2015 Update 3) is required.")
|
||||
endif()
|
||||
add_compile_flags("CXX" "/Zc:__cplusplus")
|
||||
add_compile_flags("C;CXX" "/W4")
|
||||
if(NOT MSVC_VERSION LESS 1910)
|
||||
add_compile_flags("CXX" "/Zc:__cplusplus")
|
||||
endif()
|
||||
add_compile_flags("C;CXX" "/utf-8")
|
||||
else()
|
||||
if(CC_HAS_WALL)
|
||||
|
@ -829,7 +829,7 @@ WARN_LOGFILE =
|
||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = overall.md intro.md usage.md mdbx.h options.h ChangeLog.md
|
||||
INPUT = overall.md intro.md usage.md mdbx.h mdbx.h++ options.h ChangeLog.md
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
|
@ -34,9 +34,11 @@ each of which is divided into several sections.
|
||||
- Cleaning up
|
||||
- \ref bindings
|
||||
|
||||
3. The `C` API manual:
|
||||
3. The `C/C++` API manual:
|
||||
- The \ref c_api reference
|
||||
- The \ref mdbx.h header file reference
|
||||
- The \ref cxx_api reference
|
||||
- The \ref mdbx.h++ header file reference
|
||||
|
||||
Please do not hesitate to point out errors in the documentation,
|
||||
including creating [PR](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/proposing-changes-to-your-work-with-pull-requests) with corrections and improvements.
|
||||
|
132
mdbx.h
132
mdbx.h
@ -107,7 +107,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
#include <windows.h>
|
||||
#include <winnt.h>
|
||||
#ifndef __mode_t_defined
|
||||
typedef unsigned short mode_t;
|
||||
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;
|
||||
@ -121,6 +123,7 @@ typedef DWORD mdbx_tid_t;
|
||||
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
|
||||
@ -347,6 +350,18 @@ typedef pthread_t mdbx_tid_t;
|
||||
#endif
|
||||
#endif /* cxx14_constexpr */
|
||||
|
||||
#ifndef __noreturn
|
||||
#ifdef _Noreturn
|
||||
#define __noreturn _Noreturn
|
||||
#elif defined(__GNUC__) || __has_attribute(__noreturn__)
|
||||
#define __noreturn __attribute__((__noreturn__))
|
||||
#elif defined(_MSC_VER) && !defined(__clang__)
|
||||
#define __noreturn __declspec(noreturn)
|
||||
#else
|
||||
#define __noreturn
|
||||
#endif
|
||||
#endif /* __noreturn */
|
||||
|
||||
#ifndef DEFINE_ENUM_FLAG_OPERATORS
|
||||
#if defined(__cplusplus)
|
||||
/// Define operator overloads to enable bit operations on enum values that are
|
||||
@ -392,6 +407,16 @@ typedef pthread_t mdbx_tid_t;
|
||||
* \addtogroup c_api
|
||||
* @{ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if defined(__clang__) || __has_attribute(type_visibility)
|
||||
#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 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -516,6 +541,7 @@ struct MDBX_cursor;
|
||||
#endif
|
||||
|
||||
/** Generic structure used for passing keys and data in and out of the database.
|
||||
* \anchor MDBX_val \see slice \see buffer
|
||||
*
|
||||
* \details Values returned from the database are valid only until a subsequent
|
||||
* update operation, or the end of the transaction. Do not modify or
|
||||
@ -663,7 +689,8 @@ DEFINE_ENUM_FLAG_OPERATORS(MDBX_debug_flags_t)
|
||||
* \param [in] env An environment handle returned by \ref mdbx_env_create().
|
||||
* \param [in] msg The assertion message, not including newline. */
|
||||
typedef void MDBX_debug_func(MDBX_log_level_t loglevel, const char *function,
|
||||
int line, const char *msg, va_list args);
|
||||
int line, const char *msg,
|
||||
va_list args) cxx17_noexcept;
|
||||
|
||||
/** The "don't change `logger`" value for mdbx_setup_debug() */
|
||||
#define MDBX_LOGGER_DONTCHANGE ((MDBX_debug_func *)(intptr_t)-1)
|
||||
@ -682,7 +709,8 @@ LIBMDBX_API int mdbx_setup_debug(MDBX_log_level_t log_level,
|
||||
* \param [in] env An environment handle returned by mdbx_env_create().
|
||||
* \param [in] msg The assertion message, not including newline. */
|
||||
typedef void MDBX_assert_func(const MDBX_env *env, const char *msg,
|
||||
const char *function, unsigned line);
|
||||
const char *function,
|
||||
unsigned line) cxx17_noexcept;
|
||||
|
||||
/** Set or reset the assert() callback of the environment.
|
||||
*
|
||||
@ -1121,13 +1149,17 @@ enum MDBX_txn_flags_t {
|
||||
* block each other and a write transactions. */
|
||||
MDBX_TXN_RDONLY = MDBX_RDONLY,
|
||||
|
||||
/** Prepare but not start read-only transaction.
|
||||
*
|
||||
* Transaction will not be started immediately, but created transaction handle
|
||||
* will be ready for use with \ref mdbx_txn_renew(). This flag allows to
|
||||
* preallocate memory and assign a reader slot, thus avoiding these operations
|
||||
* at the next start of the transaction. */
|
||||
MDBX_TXN_RDONLY_PREPARE = MDBX_TXN_RDONLY | MDBX_NOMEMINIT,
|
||||
/** Prepare but not start read-only transaction.
|
||||
*
|
||||
* Transaction will not be started immediately, but created transaction handle
|
||||
* will be ready for use with \ref mdbx_txn_renew(). This flag allows to
|
||||
* preallocate memory and assign a reader slot, thus avoiding these operations
|
||||
* at the next start of the transaction. */
|
||||
#if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER < 1910
|
||||
MDBX_TXN_RDONLY_PREPARE = uint32_t(MDBX_RDONLY) | uint32_t(MDBX_NOMEMINIT),
|
||||
#else
|
||||
MDBX_TXN_RDONLY_PREPARE = MDBX_RDONLY | MDBX_NOMEMINIT,
|
||||
#endif
|
||||
|
||||
/** Do not block when starting a write transaction. */
|
||||
MDBX_TXN_TRY = UINT32_C(0x10000000),
|
||||
@ -1297,7 +1329,7 @@ enum MDBX_cursor_op {
|
||||
|
||||
/** \ref MDBX_DUPFIXED -only: Return up to a page of duplicate data items
|
||||
* from next cursor position. Move cursor to prepare
|
||||
* for \ref MDBX_NEXT_MULTIPLE. */
|
||||
* for `MDBX_NEXT_MULTIPLE`. */
|
||||
MDBX_NEXT_MULTIPLE,
|
||||
|
||||
/** Position at first data item of next key */
|
||||
@ -1348,6 +1380,9 @@ enum MDBX_error_t {
|
||||
/** key/data pair already exists */
|
||||
MDBX_KEYEXIST = -30799,
|
||||
|
||||
/** The first LMDB-compatible defined error code */
|
||||
MDBX_FIRST_LMDB_ERRCODE = MDBX_KEYEXIST,
|
||||
|
||||
/** key/data pair not found (EOF) */
|
||||
MDBX_NOTFOUND = -30798,
|
||||
|
||||
@ -1431,6 +1466,9 @@ enum MDBX_error_t {
|
||||
* opening with \ref MDBX_EXCLUSIVE flag */
|
||||
MDBX_BUSY = -30778,
|
||||
|
||||
/** The first of MDBX-added error codes */
|
||||
MDBX_FIRST_ADDED_ERRCODE = MDBX_BUSY,
|
||||
|
||||
/** The specified key has more than one associated value */
|
||||
MDBX_EMULTIVAL = -30421,
|
||||
|
||||
@ -1457,6 +1495,9 @@ enum MDBX_error_t {
|
||||
/** Overlapping read and write transactions for the current thread */
|
||||
MDBX_TXN_OVERLAPPING = -30415,
|
||||
|
||||
/* The last of MDBX-added error codes */
|
||||
MDBX_LAST_ADDED_ERRCODEE = MDBX_TXN_OVERLAPPING,
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
MDBX_ENODATA = ERROR_HANDLE_EOF,
|
||||
MDBX_EINVAL = ERROR_INVALID_PARAMETER,
|
||||
@ -1536,12 +1577,17 @@ LIBMDBX_API const char *mdbx_strerror(int errnum);
|
||||
* restriction if the returned string points to the supplied buffer.
|
||||
* \see mdbx_strerror()
|
||||
*
|
||||
* mdbx_liberr2str() returns string describing only MDBX error numbers but NULL
|
||||
* for non-MDBX error codes. This function is thread-safe since return pointer
|
||||
* to constant non-localized strings.
|
||||
*
|
||||
* \param [in] errnum The error code.
|
||||
* \param [in,out] buf Buffer to store the error message.
|
||||
* \param [in] buflen The size of buffer to store the message.
|
||||
*
|
||||
* \returns "error message" The description of the error. */
|
||||
LIBMDBX_API const char *mdbx_strerror_r(int errnum, char *buf, size_t buflen);
|
||||
__nothrow_pure_function LIBMDBX_API const char *mdbx_liberr2str(int errnum);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
|
||||
/** Bit of Windows' madness. The similar to \ref mdbx_strerror() but returns
|
||||
@ -1645,7 +1691,7 @@ LIBMDBX_API int mdbx_env_create(MDBX_env **penv);
|
||||
* i.e. 32-bit process tries to open >4Gb database.
|
||||
*/
|
||||
LIBMDBX_API int mdbx_env_open(MDBX_env *env, const char *pathname,
|
||||
MDBX_env_flags_t flags, mode_t mode);
|
||||
MDBX_env_flags_t flags, mdbx_mode_t mode);
|
||||
|
||||
/** Copy an MDBX environment to the specified path, with options.
|
||||
* \ingroup c_extra
|
||||
@ -2752,7 +2798,7 @@ LIBMDBX_API int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary);
|
||||
* \ingroup c_crud
|
||||
* \see mdbx_cmp() \see mdbx_get_keycmp()
|
||||
* \see mdbx_get_datacmp \see mdbx_dcmp() */
|
||||
typedef int(MDBX_cmp_func)(const MDBX_val *a, const MDBX_val *b);
|
||||
typedef int(MDBX_cmp_func)(const MDBX_val *a, const MDBX_val *b) cxx17_noexcept;
|
||||
|
||||
/** Open or Create a database in the environment.
|
||||
* \ingroup c_dbi
|
||||
@ -3092,12 +3138,12 @@ LIBMDBX_API int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
||||
LIBMDBX_API int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
MDBX_val *data, size_t *values_count);
|
||||
|
||||
/** Get nearest items from a database.
|
||||
/** Get equal or great item from a database.
|
||||
* \ingroup c_crud
|
||||
*
|
||||
* Briefly this function does the same as \ref mdbx_get() with a few
|
||||
* differences:
|
||||
* 1. Return nearest (i.e. equal or great due comparison function) key-value
|
||||
* 1. Return equal or great (due comparison function) key-value
|
||||
* pair, but not only exactly matching with the key.
|
||||
* 2. On success return \ref MDBX_SUCCESS if key found exactly,
|
||||
* and \ref MDBX_RESULT_TRUE otherwise. Moreover, for databases with
|
||||
@ -3120,8 +3166,8 @@ LIBMDBX_API int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
* by current thread.
|
||||
* \retval MDBX_NOTFOUND The key was not in the database.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_get_nearest(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
MDBX_val *data);
|
||||
LIBMDBX_API int mdbx_get_equal_or_great(MDBX_txn *txn, MDBX_dbi dbi,
|
||||
MDBX_val *key, MDBX_val *data);
|
||||
|
||||
/** Store items into a database.
|
||||
* \ingroup c_crud
|
||||
@ -3215,7 +3261,7 @@ LIBMDBX_API int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
||||
* by \ref mdbx_txn_begin().
|
||||
* \param [in] dbi A database handle returned by \ref mdbx_dbi_open().
|
||||
* \param [in] key The key to store in the database.
|
||||
* \param [in,out] new_data The data to store, if NULL then deletion will
|
||||
* \param [in] new_data The data to store, if NULL then deletion will
|
||||
* be performed.
|
||||
* \param [in,out] old_data The buffer for retrieve previous value as describe
|
||||
* above.
|
||||
@ -3233,6 +3279,14 @@ 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);
|
||||
|
||||
/** Delete items from a database.
|
||||
* \ingroup c_crud
|
||||
*
|
||||
@ -3769,7 +3823,7 @@ 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);
|
||||
size_t bytes_retained) cxx17_noexcept;
|
||||
|
||||
/** Enumarete the entries in the reader lock table.
|
||||
* \ingroup c_statinfo
|
||||
@ -3903,7 +3957,8 @@ LIBMDBX_API int mdbx_thread_unregister(MDBX_env *env);
|
||||
* \see mdbx_env_set_oomfunc() \see mdbx_env_get_oomfunc()
|
||||
*/
|
||||
typedef int(MDBX_oom_func)(MDBX_env *env, mdbx_pid_t pid, mdbx_tid_t tid,
|
||||
uint64_t txn, unsigned gap, size_t space, int retry);
|
||||
uint64_t txn, unsigned gap, size_t space,
|
||||
int retry) cxx17_noexcept;
|
||||
|
||||
/** Set the OOM callback.
|
||||
* \ingroup c_err
|
||||
@ -3960,12 +4015,11 @@ typedef enum MDBX_page_type_t MDBX_page_type_t;
|
||||
#define MDBX_PGWALK_META ((const char *)((ptrdiff_t)-2))
|
||||
|
||||
/** Callback function for traverse the b-tree. \see mdbx_env_pgwalk() */
|
||||
typedef int
|
||||
MDBX_pgvisitor_func(const uint64_t pgno, const unsigned number, void *const ctx,
|
||||
const int deep, const char *const dbi,
|
||||
const size_t page_size, const MDBX_page_type_t type,
|
||||
const size_t nentries, const size_t payload_bytes,
|
||||
const size_t header_bytes, const size_t unused_bytes);
|
||||
typedef int MDBX_pgvisitor_func(
|
||||
const uint64_t pgno, const unsigned number, void *const ctx, const int deep,
|
||||
const char *const dbi, const size_t page_size, const MDBX_page_type_t type,
|
||||
const size_t nentries, const size_t payload_bytes,
|
||||
const size_t header_bytes, const size_t unused_bytes) cxx17_noexcept;
|
||||
|
||||
/** B-tree traversal function. */
|
||||
LIBMDBX_API int mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor,
|
||||
@ -3973,7 +4027,7 @@ LIBMDBX_API int mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor,
|
||||
/** @} B-tree Traversal */
|
||||
|
||||
/**** Attribute support functions for Nexenta
|
||||
* *********************************/
|
||||
* *******************************************/
|
||||
#if defined(MDBX_NEXENTA_ATTRS) || defined(DOXYGEN)
|
||||
/** \defgroup nexenta Attribute support functions for Nexenta
|
||||
* \ingroup c_crud
|
||||
@ -4154,6 +4208,28 @@ LIBMDBX_API int mdbx_e2k_strncmp_bug_workaround(const char *s1, const char *s2,
|
||||
LIBMDBX_API size_t mdbx_e2k_strlen_bug_workaround(const char *s);
|
||||
LIBMDBX_API size_t mdbx_e2k_strnlen_bug_workaround(const char *s,
|
||||
size_t maxlen);
|
||||
#ifdef __cplusplus
|
||||
namespace std {
|
||||
inline int mdbx_e2k_memcmp_bug_workaround(const void *s1, const void *s2,
|
||||
size_t n) {
|
||||
return ::mdbx_e2k_memcmp_bug_workaround(s1, s2, n);
|
||||
}
|
||||
inline int mdbx_e2k_strcmp_bug_workaround(const char *s1, const char *s2) {
|
||||
return ::mdbx_e2k_strcmp_bug_workaround(s1, s2);
|
||||
}
|
||||
inline int mdbx_e2k_strncmp_bug_workaround(const char *s1, const char *s2,
|
||||
size_t n) {
|
||||
return ::mdbx_e2k_strncmp_bug_workaround(s1, s2, n);
|
||||
}
|
||||
inline size_t mdbx_e2k_strlen_bug_workaround(const char *s) {
|
||||
return ::mdbx_e2k_strlen_bug_workaround(s);
|
||||
}
|
||||
inline size_t mdbx_e2k_strnlen_bug_workaround(const char *s, size_t maxlen) {
|
||||
return ::mdbx_e2k_strnlen_bug_workaround(s, maxlen);
|
||||
}
|
||||
} // namespace std
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#undef memcmp
|
||||
@ -4171,7 +4247,7 @@ LIBMDBX_API size_t mdbx_e2k_strnlen_bug_workaround(const char *s,
|
||||
#endif /* MDBX_E2K_MLHCPB_WORKAROUND */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LIBMDBX_H */
|
||||
|
123
src/core.c
123
src/core.c
@ -3045,11 +3045,9 @@ static __always_inline void mdbx_dpl_clear(MDBX_DPL dl) {
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef MDBX_ALLOY
|
||||
uint8_t mdbx_runtime_flags = MDBX_RUNTIME_FLAGS_INIT;
|
||||
uint8_t mdbx_loglevel = MDBX_DEBUG;
|
||||
MDBX_debug_func *mdbx_debug_logger;
|
||||
#endif /* MDBX_ALLOY */
|
||||
|
||||
static bool mdbx_refund(MDBX_txn *txn);
|
||||
static __must_check_result int mdbx_page_retire(MDBX_cursor *mc, MDBX_page *mp);
|
||||
@ -3199,7 +3197,7 @@ static MDBX_cmp_func cmp_lexical, cmp_reverse, cmp_int_align4, cmp_int_align2,
|
||||
static __inline MDBX_cmp_func *get_default_keycmp(unsigned flags);
|
||||
static __inline MDBX_cmp_func *get_default_datacmp(unsigned flags);
|
||||
|
||||
static const char *__mdbx_strerr(int errnum) {
|
||||
__cold const char *mdbx_liberr2str(int errnum) {
|
||||
/* Table of descriptions for MDBX errors */
|
||||
static const char *const tbl[] = {
|
||||
"MDBX_KEYEXIST: Key/data pair already exists",
|
||||
@ -3272,14 +3270,14 @@ static const char *__mdbx_strerr(int errnum) {
|
||||
}
|
||||
|
||||
const char *__cold mdbx_strerror_r(int errnum, char *buf, size_t buflen) {
|
||||
const char *msg = __mdbx_strerr(errnum);
|
||||
const char *msg = mdbx_liberr2str(errnum);
|
||||
if (!msg && buflen > 0 && buflen < INT_MAX) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
const DWORD size = FormatMessageA(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
|
||||
errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (DWORD)buflen,
|
||||
NULL);
|
||||
return size ? buf : NULL;
|
||||
return size ? buf : "FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM) failed";
|
||||
#elif defined(_GNU_SOURCE) && defined(__GLIBC__)
|
||||
/* GNU-specific */
|
||||
if (errnum > 0)
|
||||
@ -3311,7 +3309,7 @@ const char *__cold mdbx_strerror(int errnum) {
|
||||
static char buf[1024];
|
||||
return mdbx_strerror_r(errnum, buf, sizeof(buf));
|
||||
#else
|
||||
const char *msg = __mdbx_strerr(errnum);
|
||||
const char *msg = mdbx_liberr2str(errnum);
|
||||
if (!msg) {
|
||||
if (errnum > 0)
|
||||
msg = strerror(errnum);
|
||||
@ -3327,13 +3325,17 @@ const char *__cold mdbx_strerror(int errnum) {
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) /* Bit of madness for Windows */
|
||||
const char *mdbx_strerror_r_ANSI2OEM(int errnum, char *buf, size_t buflen) {
|
||||
const char *msg = __mdbx_strerr(errnum);
|
||||
const char *msg = mdbx_liberr2str(errnum);
|
||||
if (!msg && buflen > 0 && buflen < INT_MAX) {
|
||||
const DWORD size = FormatMessageA(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
|
||||
errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (DWORD)buflen,
|
||||
NULL);
|
||||
if (size && CharToOemBuffA(buf, buf, size))
|
||||
if (!size)
|
||||
msg = "FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM) failed";
|
||||
else if (!CharToOemBuffA(buf, buf, size))
|
||||
msg = "CharToOemBuffA() failed";
|
||||
else
|
||||
msg = buf;
|
||||
}
|
||||
return msg;
|
||||
@ -9802,7 +9804,7 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) {
|
||||
|
||||
/* Open and/or initialize the lock region for the environment. */
|
||||
static int __cold mdbx_setup_lck(MDBX_env *env, char *lck_pathname,
|
||||
mode_t mode) {
|
||||
mdbx_mode_t mode) {
|
||||
mdbx_assert(env, env->me_lazy_fd != INVALID_HANDLE_VALUE);
|
||||
mdbx_assert(env, env->me_lfd == INVALID_HANDLE_VALUE);
|
||||
|
||||
@ -10137,7 +10139,7 @@ static uint32_t merge_sync_flags(const uint32_t a, const uint32_t b) {
|
||||
}
|
||||
|
||||
int __cold mdbx_env_open(MDBX_env *env, const char *pathname,
|
||||
MDBX_env_flags_t flags, mode_t mode) {
|
||||
MDBX_env_flags_t flags, mdbx_mode_t mode) {
|
||||
int rc = check_env(env);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
@ -10198,7 +10200,7 @@ int __cold mdbx_env_open(MDBX_env *env, const char *pathname,
|
||||
return rc;
|
||||
|
||||
/* auto-create directory if requested */
|
||||
const mode_t dir_mode =
|
||||
const mdbx_mode_t dir_mode =
|
||||
(/* inherit read/write permissions for group and others */ mode &
|
||||
(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) |
|
||||
/* always add read/write/search for owner */ S_IRWXU |
|
||||
@ -11183,7 +11185,7 @@ int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data) {
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
MDBX_cursor_couple cx;
|
||||
rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
@ -11194,8 +11196,8 @@ int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data) {
|
||||
return mdbx_cursor_set(&cx.outer, (MDBX_val *)key, data, MDBX_SET, &exact);
|
||||
}
|
||||
|
||||
int mdbx_get_nearest(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
MDBX_val *data) {
|
||||
int mdbx_get_equal_or_great(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
MDBX_val *data) {
|
||||
DKBUF;
|
||||
mdbx_debug("===> get db %u key [%s]", dbi, DKEY(key));
|
||||
|
||||
@ -11207,7 +11209,7 @@ int mdbx_get_nearest(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
|
||||
return MDBX_BAD_TXN;
|
||||
@ -11247,7 +11249,7 @@ int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
MDBX_cursor_couple cx;
|
||||
rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
@ -13415,7 +13417,7 @@ int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
|
||||
return rc;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_VALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
if (unlikely(dbi == FREE_DBI && !F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY)))
|
||||
return MDBX_EACCESS;
|
||||
@ -13457,7 +13459,7 @@ int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) {
|
||||
return rc;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, mc->mc_dbi, DBI_VALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
if (unlikely(mc->mc_backup))
|
||||
return MDBX_EINVAL;
|
||||
@ -14933,7 +14935,7 @@ int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
if (unlikely(txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
|
||||
return (txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
|
||||
@ -15475,7 +15477,7 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data,
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
if (unlikely(flags & ~(MDBX_NOOVERWRITE | MDBX_NODUPDATA | MDBX_RESERVE |
|
||||
MDBX_APPEND | MDBX_APPENDDUP | MDBX_CURRENT)))
|
||||
@ -16125,7 +16127,7 @@ int __cold mdbx_env_copy(MDBX_env *env, const char *dest_path,
|
||||
mdbx_filehandle_t newfd;
|
||||
rc = mdbx_openfile(MDBX_OPEN_COPY, env, dest_path, &newfd,
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
(mode_t)-1
|
||||
(mdbx_mode_t)-1
|
||||
#else
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
|
||||
#endif
|
||||
@ -16307,7 +16309,7 @@ int __cold mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi,
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_VALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
MDBX_cursor_couple cx;
|
||||
rc = mdbx_cursor_init(&cx.outer, txn, dbi);
|
||||
@ -16780,7 +16782,7 @@ int __cold mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest,
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_VALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
const size_t size_before_modtxnid = offsetof(MDBX_stat, ms_mod_txnid);
|
||||
if (unlikely(bytes != sizeof(MDBX_stat)) && bytes != size_before_modtxnid)
|
||||
@ -16822,7 +16824,7 @@ int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi) {
|
||||
return rc;
|
||||
|
||||
if (unlikely(dbi < CORE_DBS || dbi >= env->me_maxdbs))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
rc = mdbx_fastmutex_acquire(&env->me_dbi_lock);
|
||||
if (likely(rc == MDBX_SUCCESS)) {
|
||||
@ -16842,7 +16844,7 @@ int mdbx_dbi_flags_ex(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags,
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_VALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
*flags = txn->mt_dbs[dbi].md_flags & DB_PERSISTENT_FLAGS;
|
||||
*state =
|
||||
@ -16954,7 +16956,7 @@ int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, bool del) {
|
||||
return rc;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
if (unlikely(TXN_DBI_CHANGED(txn, dbi)))
|
||||
return MDBX_BAD_DBI;
|
||||
@ -16965,7 +16967,7 @@ int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, bool del) {
|
||||
return rc;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID))) {
|
||||
rc = MDBX_EINVAL;
|
||||
rc = MDBX_BAD_DBI;
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
@ -17023,7 +17025,7 @@ int mdbx_set_compare(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
|
||||
return rc;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
txn->mt_dbxs[dbi].md_cmp = cmp;
|
||||
return MDBX_SUCCESS;
|
||||
@ -17035,7 +17037,7 @@ int mdbx_set_dupsort(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
|
||||
return rc;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
txn->mt_dbxs[dbi].md_dcmp = cmp;
|
||||
return MDBX_SUCCESS;
|
||||
@ -18095,7 +18097,7 @@ int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
MDBX_cursor_couple begin;
|
||||
/* LY: first, initialize cursor to refresh a DB in case it have DB_STALE */
|
||||
@ -18252,24 +18254,27 @@ int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
|
||||
* - внешняя аллокация курсоров, в том числе на стеке (без malloc).
|
||||
* - получения статуса страницы по адресу (знать о P_DIRTY).
|
||||
*/
|
||||
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) {
|
||||
|
||||
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) {
|
||||
int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (unlikely(!key || !old_data || old_data == new_data))
|
||||
if (unlikely(!key || !old_data || old_data == new_data || !preserver))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(old_data->iov_base == NULL && old_data->iov_len))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(new_data == NULL && !(flags & MDBX_CURRENT)))
|
||||
if (unlikely(new_data == NULL &&
|
||||
(flags & (MDBX_CURRENT | MDBX_RESERVE)) != MDBX_CURRENT))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
if (unlikely(flags & ~(MDBX_NOOVERWRITE | MDBX_NODUPDATA | MDBX_RESERVE |
|
||||
MDBX_APPEND | MDBX_APPENDDUP | MDBX_CURRENT)))
|
||||
@ -18359,14 +18364,11 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
||||
}
|
||||
|
||||
if (IS_DIRTY(page)) {
|
||||
if (unlikely(old_data->iov_len < present_data.iov_len)) {
|
||||
old_data->iov_base = NULL;
|
||||
old_data->iov_len = present_data.iov_len;
|
||||
rc = MDBX_RESULT_TRUE;
|
||||
rc = preserver ? preserver(preserver_context, old_data,
|
||||
present_data.iov_base, present_data.iov_len)
|
||||
: MDBX_SUCCESS;
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
goto bailout;
|
||||
}
|
||||
memcpy(old_data->iov_base, present_data.iov_base, present_data.iov_len);
|
||||
old_data->iov_len = present_data.iov_len;
|
||||
} else {
|
||||
*old_data = present_data;
|
||||
}
|
||||
@ -18383,6 +18385,25 @@ bailout:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int default_value_preserver(void *context, MDBX_val *target,
|
||||
const void *src, size_t bytes) {
|
||||
(void)context;
|
||||
if (unlikely(target->iov_len < bytes)) {
|
||||
target->iov_base = nullptr;
|
||||
target->iov_len = bytes;
|
||||
return MDBX_RESULT_TRUE;
|
||||
}
|
||||
memcpy(target->iov_base, src, target->iov_len = bytes);
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
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) {
|
||||
return mdbx_replace_ex(txn, dbi, key, new_data, old_data, flags,
|
||||
default_value_preserver, nullptr);
|
||||
}
|
||||
|
||||
/* Функция сообщает находится ли указанный адрес в "грязной" странице у
|
||||
* заданной пишущей транзакции. В конечном счете это позволяет избавиться от
|
||||
* лишнего копирования данных из НЕ-грязных страниц.
|
||||
@ -18410,21 +18431,21 @@ int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) {
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (txn->mt_flags & MDBX_TXN_RDONLY)
|
||||
return MDBX_RESULT_FALSE;
|
||||
|
||||
const MDBX_env *env = txn->mt_env;
|
||||
const ptrdiff_t offset = (uint8_t *)ptr - env->me_map;
|
||||
if (offset >= 0) {
|
||||
const pgno_t pgno = bytes2pgno(env, offset);
|
||||
if (likely(pgno < txn->mt_next_pgno)) {
|
||||
if (txn->mt_flags & MDBX_TXN_RDONLY)
|
||||
return MDBX_RESULT_FALSE;
|
||||
|
||||
const MDBX_page *page = pgno2page(env, pgno);
|
||||
if (unlikely(page->mp_pgno != pgno)) {
|
||||
/* The ptr pointed into middle of a large page,
|
||||
* not to the beginning of a data. */
|
||||
return MDBX_EINVAL;
|
||||
}
|
||||
if (unlikely(page->mp_flags & (P_DIRTY | P_LOOSE | P_KEEP)))
|
||||
if (unlikely(page->mp_flags & (P_DIRTY | P_LOOSE | P_KEEP | P_META)))
|
||||
return MDBX_RESULT_TRUE;
|
||||
if (likely(txn->tw.spill_pages == nullptr))
|
||||
return MDBX_RESULT_FALSE;
|
||||
@ -18434,7 +18455,7 @@ int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) {
|
||||
if ((size_t)offset < env->me_dxb_mmap.limit) {
|
||||
/* Указатель адресует что-то в пределах mmap, но за границей
|
||||
* распределенных страниц. Такое может случится если mdbx_is_dirty()
|
||||
* вызывает после операции, в ходе которой гразная страница попала
|
||||
* вызывается после операции, в ходе которой грязная страница попала
|
||||
* в loose и затем была возвращена в нераспределенное пространство. */
|
||||
return MDBX_RESULT_TRUE;
|
||||
}
|
||||
@ -18444,7 +18465,7 @@ int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) {
|
||||
* передан некорректный адрес, либо адрес в теневой странице, которая была
|
||||
* выделена посредством malloc().
|
||||
*
|
||||
* Для WRITE_MAP режима такая страница однозначно "не грязная",
|
||||
* Для режима WRITE_MAP режима страница однозначно "не грязная",
|
||||
* а для режимов без WRITE_MAP следует просматривать списки dirty
|
||||
* и spilled страниц у каких-либо транзакций (в том числе дочерних).
|
||||
*
|
||||
@ -18465,7 +18486,7 @@ int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result,
|
||||
return rc;
|
||||
|
||||
if (unlikely(!mdbx_txn_dbi_exists(txn, dbi, DBI_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
if (unlikely(TXN_DBI_CHANGED(txn, dbi)))
|
||||
return MDBX_BAD_DBI;
|
||||
@ -18855,7 +18876,7 @@ int mdbx_set_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return MDBX_EINVAL;
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
if (unlikely(txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
|
||||
return (txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN;
|
||||
|
@ -116,7 +116,8 @@
|
||||
#endif /* __noop */
|
||||
|
||||
#ifndef __fallthrough
|
||||
# if defined(__cplusplus) && __has_cpp_attribute(fallthrough)
|
||||
# if defined(__cplusplus) && (__has_cpp_attribute(fallthrough) && \
|
||||
(!defined(__clang__) || __clang__ > 4)) || __cplusplus >= 201703L
|
||||
# define __fallthrough [[fallthrough]]
|
||||
# elif __GNUC_PREREQ(8, 0) && defined(__cplusplus) && __cplusplus >= 201103L
|
||||
# define __fallthrough [[fallthrough]]
|
||||
@ -151,7 +152,9 @@
|
||||
#endif /* __prefetch */
|
||||
|
||||
#ifndef __noreturn
|
||||
# if defined(__GNUC__) || __has_attribute(__noreturn__)
|
||||
# ifdef _Noreturn
|
||||
# define __noreturn _Noreturn
|
||||
# elif defined(__GNUC__) || __has_attribute(__noreturn__)
|
||||
# define __noreturn __attribute__((__noreturn__))
|
||||
# elif defined(_MSC_VER)
|
||||
# define __noreturn __declspec(noreturn)
|
||||
|
@ -48,7 +48,7 @@
|
||||
#endif
|
||||
#if MDBX_DISABLE_GNU_SOURCE
|
||||
#undef _GNU_SOURCE
|
||||
#elif defined(__linux__) || defined(__gnu_linux__)
|
||||
#elif (defined(__linux__) || defined(__gnu_linux__)) && !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
@ -89,6 +89,7 @@
|
||||
#pragma warning(disable : 4366) /* the result of the unary '&' operator may be unaligned */
|
||||
#pragma warning(disable : 4200) /* nonstandard extension used: zero-sized array in struct/union */
|
||||
#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) */
|
||||
|
||||
#if defined(MDBX_TOOLS)
|
||||
@ -127,6 +128,16 @@
|
||||
# warning "libmdbx don't compatible with ThreadSanitizer, you will get a lot of false-positive issues."
|
||||
#endif /* __SANITIZE_THREAD__ */
|
||||
|
||||
#if __has_warning("-Wnested-anon-types")
|
||||
# if defined(__clang__)
|
||||
# pragma clang diagnostic ignored "-Wnested-anon-types"
|
||||
# elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic ignored "-Wnested-anon-types"
|
||||
# else
|
||||
# pragma warning disable "nested-anon-types"
|
||||
# endif
|
||||
#endif /* -Wnested-anon-types */
|
||||
|
||||
#if __has_warning("-Wconstant-logical-operand")
|
||||
# if defined(__clang__)
|
||||
# pragma clang diagnostic ignored "-Wconstant-logical-operand"
|
||||
@ -155,6 +166,10 @@
|
||||
/* *INDENT-ON* */
|
||||
/* clang-format on */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "osal.h"
|
||||
|
||||
#define mdbx_sourcery_anchor XCONCAT(mdbx_sourcery_, MDBX_BUILD_SOURCERY)
|
||||
@ -216,6 +231,7 @@ typedef uint64_t txnid_t;
|
||||
#define PRIaTXN PRIi64
|
||||
#define MIN_TXNID UINT64_C(1)
|
||||
#define MAX_TXNID (SAFE64_INVALID_THRESHOLD - 1)
|
||||
#define INITIAL_TXNID (MIN_TXNID + NUM_METAS - 1)
|
||||
#define INVALID_TXNID UINT64_MAX
|
||||
/* LY: for testing non-atomic 64-bit txnid on 32-bit arches.
|
||||
* #define MDBX_TXNID_STEP (UINT32_MAX / 3) */
|
||||
@ -1019,14 +1035,9 @@ struct MDBX_env {
|
||||
#define MDBX_RUNTIME_FLAGS_INIT \
|
||||
((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT
|
||||
|
||||
#ifdef MDBX_ALLOY
|
||||
static uint8_t mdbx_runtime_flags = MDBX_RUNTIME_FLAGS_INIT;
|
||||
static uint8_t mdbx_loglevel = MDBX_DEBUG;
|
||||
#else
|
||||
extern uint8_t mdbx_runtime_flags;
|
||||
extern uint8_t mdbx_loglevel;
|
||||
#endif /* MDBX_ALLOY */
|
||||
MDBX_INTERNAL_VAR MDBX_debug_func *mdbx_debug_logger;
|
||||
extern MDBX_debug_func *mdbx_debug_logger;
|
||||
|
||||
MDBX_INTERNAL_FUNC void mdbx_debug_log(int type, const char *function, int line,
|
||||
const char *fmt, ...)
|
||||
@ -1067,15 +1078,15 @@ MDBX_INTERNAL_FUNC void mdbx_debug_log(int type, const char *function, int line,
|
||||
#define mdbx_panic(fmt, ...) \
|
||||
__android_log_assert("panic", "mdbx", fmt, __VA_ARGS__)
|
||||
#else
|
||||
MDBX_INTERNAL_FUNC void mdbx_panic(const char *fmt, ...) __printf_args(1, 2);
|
||||
void mdbx_panic(const char *fmt, ...) __printf_args(1, 2);
|
||||
#endif
|
||||
|
||||
#if !MDBX_DEBUG && defined(__ANDROID_API__)
|
||||
#define mdbx_assert_fail(env, msg, func, line) \
|
||||
__android_log_assert(msg, "mdbx", "%s:%u", func, line)
|
||||
#else
|
||||
MDBX_INTERNAL_FUNC void mdbx_assert_fail(const MDBX_env *env, const char *msg,
|
||||
const char *func, int line);
|
||||
void mdbx_assert_fail(const MDBX_env *env, const char *msg, const char *func,
|
||||
int line);
|
||||
#endif
|
||||
|
||||
#define mdbx_debug_extra(fmt, ...) \
|
||||
@ -1318,7 +1329,7 @@ typedef struct MDBX_node {
|
||||
MDBX_INTEGERDUP | MDBX_REVERSEDUP)
|
||||
|
||||
/* mdbx_dbi_open() flags */
|
||||
#define DB_USABLE_FLAGS (DB_PERSISTENT_FLAGS | MDBX_CREATE | MDBX_ACCEDE)
|
||||
#define DB_USABLE_FLAGS (DB_PERSISTENT_FLAGS | MDBX_CREATE | MDBX_DB_ACCEDE)
|
||||
|
||||
#define DB_VALID 0x8000 /* DB handle is valid, for me_dbflags */
|
||||
#define DB_INTERNAL_FLAGS DB_VALID
|
||||
@ -1402,13 +1413,19 @@ ceil_powerof2(size_t value, size_t granularity) {
|
||||
MDBX_LIFORECLAIM | MDBX_EXCLUSIVE)
|
||||
#define ENV_USABLE_FLAGS (ENV_CHANGEABLE_FLAGS | ENV_CHANGELESS_FLAGS)
|
||||
|
||||
#if !(defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER == 1900)
|
||||
static __maybe_unused void static_checks(void) {
|
||||
STATIC_ASSERT_MSG(INT16_MAX - CORE_DBS == MDBX_MAX_DBI,
|
||||
"Oops, MDBX_MAX_DBI or CORE_DBS?");
|
||||
STATIC_ASSERT_MSG((MDBX_ACCEDE | MDBX_CREATE) ==
|
||||
STATIC_ASSERT_MSG((unsigned)(MDBX_DB_ACCEDE | MDBX_CREATE) ==
|
||||
((DB_USABLE_FLAGS | DB_INTERNAL_FLAGS) &
|
||||
(ENV_USABLE_FLAGS | ENV_INTERNAL_FLAGS)),
|
||||
"Oops, some flags overlapped or wrong");
|
||||
STATIC_ASSERT_MSG((ENV_INTERNAL_FLAGS & ENV_USABLE_FLAGS) == 0,
|
||||
"Oops, some flags overlapped or wrong");
|
||||
}
|
||||
#endif /* Disabled for MSVC 19.0 (VisualStudio 2015) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
1065
src/mdbx.c++
Normal file
1065
src/mdbx.c++
Normal file
File diff suppressed because it is too large
Load Diff
@ -199,9 +199,8 @@ __extern_C void __assert(const char *function, const char *file, int line,
|
||||
|
||||
#if !defined(__ANDROID_API__) || MDBX_DEBUG
|
||||
|
||||
MDBX_INTERNAL_FUNC void __cold mdbx_assert_fail(const MDBX_env *env,
|
||||
const char *msg,
|
||||
const char *func, int line) {
|
||||
void __cold mdbx_assert_fail(const MDBX_env *env, const char *msg,
|
||||
const char *func, int line) {
|
||||
#if MDBX_DEBUG
|
||||
if (env && env->me_assert_func) {
|
||||
env->me_assert_func(env, msg, func, line);
|
||||
@ -241,7 +240,7 @@ MDBX_INTERNAL_FUNC void __cold mdbx_assert_fail(const MDBX_env *env,
|
||||
|
||||
#if !defined(__ANDROID_API__)
|
||||
|
||||
MDBX_INTERNAL_FUNC __cold void mdbx_panic(const char *fmt, ...) {
|
||||
__cold void mdbx_panic(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
@ -514,7 +513,7 @@ MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname) {
|
||||
MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
|
||||
const MDBX_env *env, const char *pathname,
|
||||
mdbx_filehandle_t *fd,
|
||||
mode_t unix_mode_bits) {
|
||||
mdbx_mode_t unix_mode_bits) {
|
||||
*fd = INVALID_HANDLE_VALUE;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
@ -596,7 +596,7 @@ enum mdbx_openfile_purpose {
|
||||
MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
|
||||
const MDBX_env *env, const char *pathname,
|
||||
mdbx_filehandle_t *fd,
|
||||
mode_t unix_mode_bits);
|
||||
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_is_pipe(mdbx_filehandle_t fd);
|
||||
|
@ -27,30 +27,6 @@ add_executable(mdbx_test
|
||||
nested.cc
|
||||
)
|
||||
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_20 HAS_CXX20)
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_17 HAS_CXX17)
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_14 HAS_CXX14)
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_11 HAS_CXX11)
|
||||
if(NOT DEFINED MDBX_CXX_STANDARD)
|
||||
if(DEFINED CMAKE_CXX_STANDARD)
|
||||
set(MDBX_CXX_STANDARD ${CMAKE_CXX_STANDARD})
|
||||
elseif(NOT HAS_CXX20 LESS 0)
|
||||
set(MDBX_CXX_STANDARD 20)
|
||||
elseif(NOT HAS_CXX17 LESS 0)
|
||||
set(MDBX_CXX_STANDARD 17)
|
||||
elseif(NOT HAS_CXX14 LESS 0)
|
||||
set(MDBX_CXX_STANDARD 14)
|
||||
elseif(NOT HAS_CXX11 LESS 0)
|
||||
set(MDBX_CXX_STANDARD 11)
|
||||
endif()
|
||||
endif()
|
||||
if(MDBX_CXX_STANDARD)
|
||||
message(STATUS "Use C++${MDBX_CXX_STANDARD} for libmdbx")
|
||||
if(NOT SUBPROJECT OR NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD ${MDBX_CXX_STANDARD})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MDBX_CXX_STANDARD)
|
||||
set_target_properties(mdbx_test PROPERTIES
|
||||
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
||||
|
@ -31,14 +31,15 @@ const char *test_strerror(int errnum) {
|
||||
return mdbx_strerror_r(errnum, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
void __noreturn failure_perror(const char *what, int errnum) {
|
||||
__noreturn void failure_perror(const char *what, int errnum) {
|
||||
failure("%s failed: %s (%d)\n", what, test_strerror(errnum), errnum);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void mdbx_logger(MDBX_log_level_t priority, const char *function,
|
||||
int line, const char *msg, va_list args) {
|
||||
int line, const char *msg,
|
||||
va_list args) cxx17_noexcept {
|
||||
if (!function)
|
||||
function = "unknown";
|
||||
|
||||
|
@ -17,9 +17,9 @@
|
||||
#include "base.h"
|
||||
#include "chrono.h"
|
||||
|
||||
void __noreturn usage(void);
|
||||
void __noreturn __printf_args(1, 2) failure(const char *fmt, ...);
|
||||
void __noreturn failure_perror(const char *what, int errnum);
|
||||
__noreturn void usage(void);
|
||||
__noreturn void __printf_args(1, 2) failure(const char *fmt, ...);
|
||||
__noreturn void failure_perror(const char *what, int errnum);
|
||||
const char *test_strerror(int errnum);
|
||||
|
||||
namespace logging {
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include <sys/time.h>
|
||||
#endif /* !Windows */
|
||||
|
||||
void __noreturn usage(void) {
|
||||
__noreturn void usage(void) {
|
||||
puts(
|
||||
"usage:\n"
|
||||
" --help or -h Show this text\n"
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#if !(defined(_WIN32) || defined(_WIN64))
|
||||
|
||||
#include <atomic>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
@ -309,7 +310,7 @@ bool actor_config::osal_deserialize(const char *str, const char *end,
|
||||
|
||||
static pid_t overlord_pid;
|
||||
|
||||
static std::atomic<int> sigusr1_head, sigusr2_head;
|
||||
static std::atomic_int sigusr1_head, sigusr2_head;
|
||||
static void handler_SIGUSR(int signum) {
|
||||
switch (signum) {
|
||||
case SIGUSR1:
|
||||
@ -337,7 +338,7 @@ bool osal_progress_push(bool active) {
|
||||
|
||||
static std::unordered_map<pid_t, actor_status> childs;
|
||||
|
||||
static std::atomic<int> sigalarm_head;
|
||||
static std::atomic_int sigalarm_head;
|
||||
static void handler_SIGCHLD(int signum) {
|
||||
if (signum == SIGALRM)
|
||||
++sigalarm_head;
|
||||
|
@ -80,7 +80,7 @@ const char *keygencase2str(const keygen_case keycase) {
|
||||
|
||||
int testcase::oom_callback(MDBX_env *env, mdbx_pid_t pid, mdbx_tid_t tid,
|
||||
uint64_t txn, unsigned gap, size_t space,
|
||||
int retry) {
|
||||
int retry) cxx17_noexcept {
|
||||
|
||||
testcase *self = (testcase *)mdbx_env_get_userctx(env);
|
||||
|
||||
@ -530,7 +530,8 @@ void testcase::db_table_close(MDBX_dbi handle) {
|
||||
void testcase::checkdata(const char *step, MDBX_dbi handle, MDBX_val key2check,
|
||||
MDBX_val expected_valued) {
|
||||
MDBX_val actual_value = expected_valued;
|
||||
int rc = mdbx_get_nearest(txn_guard.get(), handle, &key2check, &actual_value);
|
||||
int rc = mdbx_get_equal_or_great(txn_guard.get(), handle, &key2check,
|
||||
&actual_value);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
failure_perror(step, rc);
|
||||
if (!is_samedata(&actual_value, &expected_valued))
|
||||
|
@ -167,7 +167,8 @@ protected:
|
||||
int remove(const keygen::buffer &akey, const keygen::buffer &adata);
|
||||
|
||||
static int oom_callback(MDBX_env *env, mdbx_pid_t pid, mdbx_tid_t tid,
|
||||
uint64_t txn, unsigned gap, size_t space, int retry);
|
||||
uint64_t txn, unsigned gap, size_t space,
|
||||
int retry) cxx17_noexcept;
|
||||
|
||||
MDBX_env_flags_t actual_env_mode{MDBX_ENV_DEFAULTS};
|
||||
bool is_nested_txn_available() const {
|
||||
|
Loading…
x
Reference in New Issue
Block a user