From d3daa23c632f15d20db3ee4b87e16734958813bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 13 Jan 2025 13:13:26 +0300 Subject: [PATCH 001/181] =?UTF-8?q?mdbx:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20ChangeLog=20(=D0=BF=D0=BE?= =?UTF-8?q?=D0=B4=D0=B3=D0=BE=D1=82=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=BF=D1=83=D1=81=D0=BA=D0=B0=200.13.4).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 1a57e791..bc7ef66c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -5,6 +5,16 @@ English version [by liar Google](https://libmdbx-dqdkfa-ru.translate.goog/md__ch and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx.dqdkfa.ru/md__change_log.html). +## v0.13.4 в процессе накопления изменений + +Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов. + +Предполагаемая дата выпуска между 2025-02-11 и 2025-03-13. + + +-------------------------------------------------------------------------------- + + ## v0.13.3 "Королёв" от 2025-01-12 Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов From 88d782e5eb5f61ccf1684e934388c1e61f85334f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 14 Jan 2025 13:00:53 +0300 Subject: [PATCH 002/181] =?UTF-8?q?mdbx:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=B0=D1=82=D1=87=D0=B0?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D1=81=D1=82=D0=B0=D1=80=D1=8B=D1=85=20?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D0=B9=20buildroot=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...libmdbx-new-package-library-database.patch | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch b/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch index 98ffaa79..9c7afff4 100644 --- a/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch +++ b/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch @@ -1,8 +1,8 @@ -From 40efe497b511c322470aa9c084fe4c1759788c57 Mon Sep 17 00:00:00 2001 +From 0ba6ba5e6d6311213a21f033729e18826729230a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= -Date: Sun, 27 Oct 2024 22:34:19 +0300 -Subject: [PATCH 1/1] package/libmdbx: new package (library/database). +Date: Tue, 14 Jan 2025 12:57:03 +0300 +Subject: [PATCH] package/libmdbx: new package (library/database). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -15,9 +15,9 @@ This patch adds libmdbx: in terms of reliability, features and performance. - more information at https://gitflic.ru/project/erthink/libmdbx -The 0.12.12 "Dollezhal" is stable release of _libmdbx_ branch in memory -of the Soviet energy scientist Nikolai Antonovich Dollezhal on the 125th -anniversary of his birth. +The 0.13.13 "Korolev" is stable release of _libmdbx_ branch with new superior features +on the birthday and in memory of Sergei Korolev who was the lead Soviet rocket +engineer and spacecraft designer. The complete ChangeLog: https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md @@ -112,18 +112,18 @@ index 0000000000..a9a4ac45c5 + !BR2_TOOLCHAIN_GCC_AT_LEAST_4_4 diff --git a/package/libmdbx/libmdbx.hash b/package/libmdbx/libmdbx.hash new file mode 100644 -index 0000000000..222e7caf5c +index 0000000000..1c91aa2f90 --- /dev/null +++ b/package/libmdbx/libmdbx.hash @@ -0,0 +1,5 @@ +# Hashes from: https://libmdbx.dqdkfa.ru/release/SHA256SUMS -+sha256 19c0eb33e1ed43ca2a94dceb06dd31946432d16f30a9751d3701c67efa22eb1a libmdbx-amalgamated-0.12.12.tar.xz ++sha256 2e42505f1ceb57945569db3c1a5db9b5216d8f72da7c75c240ff81196f8e9a0b libmdbx-amalgamated-0.13.3.tar.xz + +# Locally calculated -+sha256 310fe25c858a9515fc8c8d7d1f24a67c9496f84a91e0a0e41ea9975b1371e569 LICENSE ++sha256 0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594 LICENSE diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk new file mode 100644 -index 0000000000..da4a53913f +index 0000000000..b42ab629fe --- /dev/null +++ b/package/libmdbx/libmdbx.mk @@ -0,0 +1,42 @@ @@ -133,7 +133,7 @@ index 0000000000..da4a53913f +# +################################################################################ + -+LIBMDBX_VERSION = 0.12.12 ++LIBMDBX_VERSION = 0.13.3 +LIBMDBX_SOURCE = libmdbx-amalgamated-$(LIBMDBX_VERSION).tar.xz +LIBMDBX_SITE = https://libmdbx.dqdkfa.ru/release +LIBMDBX_SUPPORTS_IN_SOURCE_BUILD = NO @@ -170,5 +170,5 @@ index 0000000000..da4a53913f + +$(eval $(cmake-package)) -- -2.47.0 +2.48.0 From 36abcc57f0501835a92747c3710caacfb33f1598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Wed, 15 Jan 2025 19:30:00 +0300 Subject: [PATCH 003/181] =?UTF-8?q?mdbx:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B3=D0=BE=D0=B4=D0=B0=20?= =?UTF-8?q?=D0=B2=20=C2=A9=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 +- COPYRIGHT | 2 +- NOTICE | 2 +- cmake/compiler.cmake | 2 +- cmake/profile.cmake | 2 +- cmake/utils.cmake | 2 +- example/example-mdbx.c | 2 +- example/sample-bdb.txt | 2 +- mdbx.h | 2 +- mdbx.h++ | 2 +- src/alloy.c | 2 +- src/api-cold.c | 2 +- src/api-copy.c | 2 +- src/api-cursor.c | 2 +- src/api-dbi.c | 2 +- src/api-env.c | 2 +- src/api-extra.c | 2 +- src/api-key-transform.c | 2 +- src/api-misc.c | 2 +- src/api-opts.c | 2 +- src/api-range-estimate.c | 2 +- src/api-txn-data.c | 2 +- src/api-txn.c | 2 +- src/atomics-ops.h | 2 +- src/atomics-types.h | 2 +- src/audit.c | 2 +- src/chk.c | 2 +- src/cogs.c | 2 +- src/cogs.h | 2 +- src/coherency.c | 2 +- src/cursor.c | 2 +- src/cursor.h | 2 +- src/dbi.c | 2 +- src/dbi.h | 2 +- src/dpl.c | 2 +- src/dpl.h | 2 +- src/dxb.c | 2 +- src/env.c | 2 +- src/essentials.h | 2 +- src/gc-get.c | 2 +- src/gc-put.c | 2 +- src/gc.h | 2 +- src/global.c | 2 +- src/internals.h | 2 +- src/layout-dxb.h | 2 +- src/layout-lck.h | 2 +- src/lck-posix.c | 2 +- src/lck-windows.c | 2 +- src/lck.c | 2 +- src/lck.h | 2 +- src/logging_and_debug.c | 2 +- src/logging_and_debug.h | 2 +- src/man1/mdbx_chk.1 | 2 +- src/man1/mdbx_copy.1 | 2 +- src/man1/mdbx_drop.1 | 2 +- src/man1/mdbx_dump.1 | 2 +- src/man1/mdbx_load.1 | 2 +- src/man1/mdbx_stat.1 | 2 +- src/mdbx.c++ | 2 +- src/meta.c | 2 +- src/meta.h | 2 +- src/mvcc-readers.c | 2 +- src/node.c | 2 +- src/node.h | 2 +- src/options.h | 2 +- src/osal.c | 2 +- src/osal.h | 2 +- src/page-get.c | 2 +- src/page-iov.c | 2 +- src/page-iov.h | 2 +- src/page-ops.c | 2 +- src/page-ops.h | 2 +- src/pnl.c | 2 +- src/pnl.h | 2 +- src/preface.h | 2 +- src/proto.h | 2 +- src/refund.c | 2 +- src/sort.h | 2 +- src/spill.c | 2 +- src/spill.h | 2 +- src/table.c | 2 +- src/tls.c | 2 +- src/tls.h | 2 +- src/tools/chk.c | 2 +- src/tools/copy.c | 2 +- src/tools/drop.c | 2 +- src/tools/dump.c | 2 +- src/tools/load.c | 2 +- src/tools/stat.c | 2 +- src/tree-ops.c | 2 +- src/tree-search.c | 2 +- src/txl.c | 2 +- src/txl.h | 2 +- src/txn.c | 2 +- src/unaligned.h | 2 +- src/utils.c | 2 +- src/utils.h | 2 +- src/walk.c | 2 +- src/walk.h | 2 +- src/windows-import.c | 2 +- src/windows-import.h | 2 +- test/CMakeLists.txt | 2 +- test/append.c++ | 2 +- test/base.h++ | 2 +- test/cases.c++ | 2 +- test/chrono.c++ | 2 +- test/chrono.h++ | 2 +- test/config.c++ | 2 +- test/config.h++ | 2 +- test/copy.c++ | 2 +- test/dead.c++ | 2 +- test/extra/doubtless_positioning.c++ | 2 +- test/extra/dupfix_multiple.c++ | 2 +- test/extra/hex_base64_base58.c++ | 2 +- test/extra/maindb_ordinal.c++ | 2 +- test/extra/pcrf/pcrf_test.c | 2 +- test/fork.c++ | 2 +- test/hill.c++ | 2 +- test/jitter.c++ | 2 +- test/keygen.c++ | 2 +- test/keygen.h++ | 2 +- test/log.c++ | 2 +- test/log.h++ | 2 +- test/main.c++ | 2 +- test/nested.c++ | 2 +- test/osal-unix.c++ | 2 +- test/osal-windows.c++ | 2 +- test/osal.h++ | 2 +- test/test.c++ | 2 +- test/test.h++ | 2 +- test/try.c++ | 2 +- test/ttl.c++ | 2 +- test/utils.c++ | 2 +- test/utils.h++ | 2 +- 134 files changed, 134 insertions(+), 134 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f8d1b02..0996291b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2024 Леонид Юрьев aka Leonid Yuriev ############################################### +# Copyright (c) 2020-2025 Леонид Юрьев aka Leonid Yuriev ############################################### # SPDX-License-Identifier: Apache-2.0 # # Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`. Всё будет хорошо! diff --git a/COPYRIGHT b/COPYRIGHT index 81fadf1b..fb29a937 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,4 +1,4 @@ -Copyright (c) 2015-2024 Леонид Юрьев aka Leonid Yuriev +Copyright (c) 2015-2025 Леонид Юрьев aka Leonid Yuriev Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/NOTICE b/NOTICE index 639c628c..4df84dba 100644 --- a/NOTICE +++ b/NOTICE @@ -11,7 +11,7 @@ to the Telegram' group https://t.me/libmdbx. Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`. Всё будет хорошо! -Copyright 2015-2024 Леонид Юрьев aka Leonid Yuriev +Copyright 2015-2025 Леонид Юрьев aka Leonid Yuriev SPDX-License-Identifier: Apache-2.0 For notes about the license change, credits and acknowledgments, please refer to the COPYRIGHT file within original libmdbx source code diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake index 05c067f9..5fefdbae 100644 --- a/cmake/compiler.cmake +++ b/cmake/compiler.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2024 Леонид Юрьев aka Leonid Yuriev ############################################### +# Copyright (c) 2010-2025 Леонид Юрьев aka Leonid Yuriev ############################################### # SPDX-License-Identifier: Apache-2.0 if(CMAKE_VERSION VERSION_LESS 3.8.2) diff --git a/cmake/profile.cmake b/cmake/profile.cmake index dc930f3a..6a8a466e 100644 --- a/cmake/profile.cmake +++ b/cmake/profile.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2012-2024 Леонид Юрьев aka Leonid Yuriev ############################################### +# Copyright (c) 2012-2025 Леонид Юрьев aka Leonid Yuriev ############################################### # SPDX-License-Identifier: Apache-2.0 if(CMAKE_VERSION VERSION_LESS 3.8.2) diff --git a/cmake/utils.cmake b/cmake/utils.cmake index adb8004d..abb4cd30 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2012-2024 Леонид Юрьев aka Leonid Yuriev ############################################### +# Copyright (c) 2012-2025 Леонид Юрьев aka Leonid Yuriev ############################################### # SPDX-License-Identifier: Apache-2.0 if(CMAKE_VERSION VERSION_LESS 3.8.2) diff --git a/example/example-mdbx.c b/example/example-mdbx.c index beae17f5..a0eeb121 100644 --- a/example/example-mdbx.c +++ b/example/example-mdbx.c @@ -4,7 +4,7 @@ */ /* - * Copyright 2015-2023 Leonid Yuriev . + * Copyright 2015-2025 Leonid Yuriev . * Copyright 2017 Ilya Shipitsin . * Copyright 2012-2015 Howard Chu, Symas Corp. * All rights reserved. diff --git a/example/sample-bdb.txt b/example/sample-bdb.txt index d3478a16..5dc9a78c 100644 --- a/example/sample-bdb.txt +++ b/example/sample-bdb.txt @@ -4,7 +4,7 @@ */ /* - * Copyright 2015-2023 Leonid Yuriev . + * Copyright 2015-2025 Leonid Yuriev . * Copyright 2012-2015 Howard Chu, Symas Corp. * Copyright 2015,2016 Peter-Service R&D LLC. * All rights reserved. diff --git a/mdbx.h b/mdbx.h index af01e309..a0886799 100644 --- a/mdbx.h +++ b/mdbx.h @@ -31,7 +31,7 @@ developers. For the same reason ~~Github~~ is blacklisted forever. \copyright SPDX-License-Identifier: Apache-2.0 \note Please refer to the COPYRIGHT file for explanations license change, credits and acknowledgments. -\author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +\author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 *******************************************************************************/ diff --git a/mdbx.h++ b/mdbx.h++ index e96c2012..62315f61 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2020-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2020-2025 /// /// Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`. /// Всё будет хорошо! diff --git a/src/alloy.c b/src/alloy.c index 076d39da..ef96cf94 100644 --- a/src/alloy.c +++ b/src/alloy.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #define xMDBX_ALLOY 1 /* alloyed build */ #include "internals.h" /* must be included first */ diff --git a/src/api-cold.c b/src/api-cold.c index 7498d8ab..1d124852 100644 --- a/src/api-cold.c +++ b/src/api-cold.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/api-copy.c b/src/api-copy.c index 3c7a4f2c..08c01192 100644 --- a/src/api-copy.c +++ b/src/api-copy.c @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/api-cursor.c b/src/api-cursor.c index e52f5817..a10e09ef 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/api-dbi.c b/src/api-dbi.c index 93bbdf21..e7f6f27d 100644 --- a/src/api-dbi.c +++ b/src/api-dbi.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/api-env.c b/src/api-env.c index dfd7ca6f..9a6be7b3 100644 --- a/src/api-env.c +++ b/src/api-env.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/api-extra.c b/src/api-extra.c index dd394f7b..61b0fac9 100644 --- a/src/api-extra.c +++ b/src/api-extra.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/api-key-transform.c b/src/api-key-transform.c index 6143a62e..6c42260d 100644 --- a/src/api-key-transform.c +++ b/src/api-key-transform.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/api-misc.c b/src/api-misc.c index c34c9df7..7e54c51d 100644 --- a/src/api-misc.c +++ b/src/api-misc.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/api-opts.c b/src/api-opts.c index d470bf25..2465864a 100644 --- a/src/api-opts.c +++ b/src/api-opts.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/api-range-estimate.c b/src/api-range-estimate.c index de3e1d12..5356d4da 100644 --- a/src/api-range-estimate.c +++ b/src/api-range-estimate.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/api-txn-data.c b/src/api-txn-data.c index b3cee3c3..76bdf32a 100644 --- a/src/api-txn-data.c +++ b/src/api-txn-data.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/api-txn.c b/src/api-txn.c index 6831fd5d..61b994bd 100644 --- a/src/api-txn.c +++ b/src/api-txn.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/atomics-ops.h b/src/atomics-ops.h index c61c055d..7dae2f34 100644 --- a/src/atomics-ops.h +++ b/src/atomics-ops.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/atomics-types.h b/src/atomics-types.h index fe977b94..0dbf747d 100644 --- a/src/atomics-types.h +++ b/src/atomics-types.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/audit.c b/src/audit.c index 91e18873..094722ff 100644 --- a/src/audit.c +++ b/src/audit.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/chk.c b/src/chk.c index 4197b29c..d848b014 100644 --- a/src/chk.c +++ b/src/chk.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/cogs.c b/src/cogs.c index 2e7d18c6..7fc924ca 100644 --- a/src/cogs.c +++ b/src/cogs.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/cogs.h b/src/cogs.h index 5b8f20c7..11d7fe1d 100644 --- a/src/cogs.h +++ b/src/cogs.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/coherency.c b/src/coherency.c index 6b9df51d..af1cc6fd 100644 --- a/src/coherency.c +++ b/src/coherency.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/cursor.c b/src/cursor.c index 8e92297e..43cf8e48 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/cursor.h b/src/cursor.h index 0ea13903..c2de019b 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/dbi.c b/src/dbi.c index 7716e6d2..13d5a3eb 100644 --- a/src/dbi.c +++ b/src/dbi.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/dbi.h b/src/dbi.h index c654a0fa..e9b16efe 100644 --- a/src/dbi.h +++ b/src/dbi.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/dpl.c b/src/dpl.c index 1d2bef79..d1a1ef52 100644 --- a/src/dpl.c +++ b/src/dpl.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/dpl.h b/src/dpl.h index 0059dc58..ea66d214 100644 --- a/src/dpl.h +++ b/src/dpl.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/dxb.c b/src/dxb.c index b85258bb..aa222025 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/env.c b/src/env.c index 58ee0346..525ed8ec 100644 --- a/src/env.c +++ b/src/env.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/essentials.h b/src/essentials.h index 3331e524..f46aec2e 100644 --- a/src/essentials.h +++ b/src/essentials.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/gc-get.c b/src/gc-get.c index c6d2c62b..bb1c9680 100644 --- a/src/gc-get.c +++ b/src/gc-get.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/gc-put.c b/src/gc-put.c index 4c6fd070..b5231773 100644 --- a/src/gc-put.c +++ b/src/gc-put.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/gc.h b/src/gc.h index b3ec23cf..171037f4 100644 --- a/src/gc.h +++ b/src/gc.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/global.c b/src/global.c index e8d13cf4..e3435f72 100644 --- a/src/global.c +++ b/src/global.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/internals.h b/src/internals.h index bb7fabfa..57b91f8b 100644 --- a/src/internals.h +++ b/src/internals.h @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/layout-dxb.h b/src/layout-dxb.h index 3d9514c8..001bc59d 100644 --- a/src/layout-dxb.h +++ b/src/layout-dxb.h @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/layout-lck.h b/src/layout-lck.h index b635c595..accf79a9 100644 --- a/src/layout-lck.h +++ b/src/layout-lck.h @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/lck-posix.c b/src/lck-posix.c index 41f49f48..99a01f91 100644 --- a/src/lck-posix.c +++ b/src/lck-posix.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #if !(defined(_WIN32) || defined(_WIN64)) /*----------------------------------------------------------------------------* diff --git a/src/lck-windows.c b/src/lck-windows.c index 10c362a6..296679d1 100644 --- a/src/lck-windows.c +++ b/src/lck-windows.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #if defined(_WIN32) || defined(_WIN64) diff --git a/src/lck.c b/src/lck.c index 097aeb69..0bb3205c 100644 --- a/src/lck.c +++ b/src/lck.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/lck.h b/src/lck.h index eee38e15..ba1ebc88 100644 --- a/src/lck.h +++ b/src/lck.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/logging_and_debug.c b/src/logging_and_debug.c index f796db35..e8538934 100644 --- a/src/logging_and_debug.c +++ b/src/logging_and_debug.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/logging_and_debug.h b/src/logging_and_debug.h index e99ccea5..3141f3cd 100644 --- a/src/logging_and_debug.h +++ b/src/logging_and_debug.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/man1/mdbx_chk.1 b/src/man1/mdbx_chk.1 index b53422c7..bc6de4b7 100644 --- a/src/man1/mdbx_chk.1 +++ b/src/man1/mdbx_chk.1 @@ -1,4 +1,4 @@ -.\" Copyright 2015-2024 Leonid Yuriev . +.\" Copyright 2015-2025 Leonid Yuriev . .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .TH MDBX_CHK 1 "2024-08-29" "MDBX 0.13" .SH NAME diff --git a/src/man1/mdbx_copy.1 b/src/man1/mdbx_copy.1 index 16c0fced..83ec8553 100644 --- a/src/man1/mdbx_copy.1 +++ b/src/man1/mdbx_copy.1 @@ -1,4 +1,4 @@ -.\" Copyright 2015-2024 Leonid Yuriev . +.\" Copyright 2015-2025 Leonid Yuriev . .\" Copyright 2015,2016 Peter-Service R&D LLC . .\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. diff --git a/src/man1/mdbx_drop.1 b/src/man1/mdbx_drop.1 index 3bf5683b..a6abbe41 100644 --- a/src/man1/mdbx_drop.1 +++ b/src/man1/mdbx_drop.1 @@ -1,4 +1,4 @@ -.\" Copyright 2021-2024 Leonid Yuriev . +.\" Copyright 2021-2025 Leonid Yuriev . .\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .TH MDBX_DROP 1 "2024-08-29" "MDBX 0.13" diff --git a/src/man1/mdbx_dump.1 b/src/man1/mdbx_dump.1 index 96342054..030617c3 100644 --- a/src/man1/mdbx_dump.1 +++ b/src/man1/mdbx_dump.1 @@ -1,4 +1,4 @@ -.\" Copyright 2015-2024 Leonid Yuriev . +.\" Copyright 2015-2025 Leonid Yuriev . .\" Copyright 2015,2016 Peter-Service R&D LLC . .\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. diff --git a/src/man1/mdbx_load.1 b/src/man1/mdbx_load.1 index 5e790876..27b533e3 100644 --- a/src/man1/mdbx_load.1 +++ b/src/man1/mdbx_load.1 @@ -1,4 +1,4 @@ -.\" Copyright 2015-2024 Leonid Yuriev . +.\" Copyright 2015-2025 Leonid Yuriev . .\" Copyright 2015,2016 Peter-Service R&D LLC . .\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. diff --git a/src/man1/mdbx_stat.1 b/src/man1/mdbx_stat.1 index 935a541f..68a698c1 100644 --- a/src/man1/mdbx_stat.1 +++ b/src/man1/mdbx_stat.1 @@ -1,4 +1,4 @@ -.\" Copyright 2015-2024 Leonid Yuriev . +.\" Copyright 2015-2025 Leonid Yuriev . .\" Copyright 2015,2016 Peter-Service R&D LLC . .\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. diff --git a/src/mdbx.c++ b/src/mdbx.c++ index 17ca4718..d891b654 100644 --- a/src/mdbx.c++ +++ b/src/mdbx.c++ @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2020-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2020-2025 /// /// \brief Non-inline part of the libmdbx C++ API /// diff --git a/src/meta.c b/src/meta.c index cbdea2d0..562c81db 100644 --- a/src/meta.c +++ b/src/meta.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/meta.h b/src/meta.h index 899f1d5a..64ef59cb 100644 --- a/src/meta.h +++ b/src/meta.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/mvcc-readers.c b/src/mvcc-readers.c index be0220a9..e97eaaa5 100644 --- a/src/mvcc-readers.c +++ b/src/mvcc-readers.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/node.c b/src/node.c index 934bad65..f4b264fc 100644 --- a/src/node.c +++ b/src/node.c @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/node.h b/src/node.h index 50de16e1..03069021 100644 --- a/src/node.h +++ b/src/node.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/options.h b/src/options.h index 1a80cd20..9449fed9 100644 --- a/src/options.h +++ b/src/options.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /******************************************************************************* ******************************************************************************* diff --git a/src/osal.c b/src/osal.c index dd1c7b4b..d4f4b03a 100644 --- a/src/osal.c +++ b/src/osal.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// /// https://en.wikipedia.org/wiki/Operating_system_abstraction_layer diff --git a/src/osal.h b/src/osal.h index c82f8af1..8f0d020c 100644 --- a/src/osal.h +++ b/src/osal.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// /// https://en.wikipedia.org/wiki/Operating_system_abstraction_layer diff --git a/src/page-get.c b/src/page-get.c index a07768a7..9ce3ecac 100644 --- a/src/page-get.c +++ b/src/page-get.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/page-iov.c b/src/page-iov.c index b6686017..0ec83807 100644 --- a/src/page-iov.c +++ b/src/page-iov.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/page-iov.h b/src/page-iov.h index bf367fef..1b298588 100644 --- a/src/page-iov.h +++ b/src/page-iov.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/page-ops.c b/src/page-ops.c index 6cecd119..43e6a79a 100644 --- a/src/page-ops.c +++ b/src/page-ops.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/page-ops.h b/src/page-ops.h index bb4ebd16..6874be60 100644 --- a/src/page-ops.h +++ b/src/page-ops.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/pnl.c b/src/pnl.c index 6a7f18ad..88f14c7f 100644 --- a/src/pnl.c +++ b/src/pnl.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/pnl.h b/src/pnl.h index ba033775..c0b7d542 100644 --- a/src/pnl.h +++ b/src/pnl.h @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/preface.h b/src/preface.h index 962c7ae7..5f43b67e 100644 --- a/src/preface.h +++ b/src/preface.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/proto.h b/src/proto.h index 857a6794..842cbf62 100644 --- a/src/proto.h +++ b/src/proto.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/refund.c b/src/refund.c index 3d2fc368..68710614 100644 --- a/src/refund.c +++ b/src/refund.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/sort.h b/src/sort.h index 824c6bf5..bc676271 100644 --- a/src/sort.h +++ b/src/sort.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// /// \file sort.h /// \brief Маркосы реализующие сортировку и двоичный поиск diff --git a/src/spill.c b/src/spill.c index 261adb78..bded62c7 100644 --- a/src/spill.c +++ b/src/spill.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/spill.h b/src/spill.h index 32a8c9b2..5e7b7dad 100644 --- a/src/spill.h +++ b/src/spill.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/table.c b/src/table.c index c9a1e980..690ab9ff 100644 --- a/src/table.c +++ b/src/table.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/tls.c b/src/tls.c index 79f228f2..9d8fab2f 100644 --- a/src/tls.c +++ b/src/tls.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/tls.h b/src/tls.h index 5bcbfa23..5f3fd2b8 100644 --- a/src/tls.h +++ b/src/tls.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/tools/chk.c b/src/tools/chk.c index a22fd57b..6399ea60 100644 --- a/src/tools/chk.c +++ b/src/tools/chk.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// /// diff --git a/src/tools/copy.c b/src/tools/copy.c index 6b781025..2a55339b 100644 --- a/src/tools/copy.c +++ b/src/tools/copy.c @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// /// mdbx_copy.c - memory-mapped database backup tool /// diff --git a/src/tools/drop.c b/src/tools/drop.c index 3c6e0f10..e74dcfe4 100644 --- a/src/tools/drop.c +++ b/src/tools/drop.c @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2021-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2021-2025 /// /// mdbx_drop.c - memory-mapped database delete tool /// diff --git a/src/tools/dump.c b/src/tools/dump.c index 12e1f88f..c09b2b17 100644 --- a/src/tools/dump.c +++ b/src/tools/dump.c @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// /// mdbx_dump.c - memory-mapped database dump tool /// diff --git a/src/tools/load.c b/src/tools/load.c index 7bb8c822..0220ce22 100644 --- a/src/tools/load.c +++ b/src/tools/load.c @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// /// mdbx_load.c - memory-mapped database load tool /// diff --git a/src/tools/stat.c b/src/tools/stat.c index b3dd6811..c65d892a 100644 --- a/src/tools/stat.c +++ b/src/tools/stat.c @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// /// mdbx_stat.c - memory-mapped database status tool /// diff --git a/src/tree-ops.c b/src/tree-ops.c index 3c51a65c..d0456792 100644 --- a/src/tree-ops.c +++ b/src/tree-ops.c @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/tree-search.c b/src/tree-search.c index c19a9274..9cc68d7d 100644 --- a/src/tree-search.c +++ b/src/tree-search.c @@ -1,7 +1,7 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 /// \note Please refer to the COPYRIGHT file for explanations license change, /// credits and acknowledgments. -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/txl.c b/src/txl.c index c9830f81..d369f3bd 100644 --- a/src/txl.c +++ b/src/txl.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/txl.h b/src/txl.h index d8d67e05..79cb5524 100644 --- a/src/txl.h +++ b/src/txl.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/txn.c b/src/txn.c index 478f4d07..eb198965 100644 --- a/src/txn.c +++ b/src/txn.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/unaligned.h b/src/unaligned.h index 4085b51d..b119004f 100644 --- a/src/unaligned.h +++ b/src/unaligned.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/utils.c b/src/utils.c index 05b7a21e..ead1e4d3 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/utils.h b/src/utils.h index 85563b09..9043a760 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/walk.c b/src/walk.c index 585c350d..4a8c6e8c 100644 --- a/src/walk.c +++ b/src/walk.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #include "internals.h" diff --git a/src/walk.h b/src/walk.h index be6dc507..c87b8479 100644 --- a/src/walk.h +++ b/src/walk.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/src/windows-import.c b/src/windows-import.c index ee0ea9c8..d11cee29 100644 --- a/src/windows-import.c +++ b/src/windows-import.c @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #if defined(_WIN32) || defined(_WIN64) diff --git a/src/windows-import.h b/src/windows-import.h index 0362e9b6..d35fccdf 100644 --- a/src/windows-import.h +++ b/src/windows-import.h @@ -1,5 +1,5 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 #pragma once diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 28c4e74e..f8a72d68 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2024 Леонид Юрьев aka Leonid Yuriev ############################################### +# Copyright (c) 2020-2025 Леонид Юрьев aka Leonid Yuriev ############################################### # SPDX-License-Identifier: Apache-2.0 enable_language(CXX) diff --git a/test/append.c++ b/test/append.c++ index 59f6d1ca..91bbf33f 100644 --- a/test/append.c++ +++ b/test/append.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/base.h++ b/test/base.h++ index 21af13a2..c3394f31 100644 --- a/test/base.h++ +++ b/test/base.h++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #pragma once diff --git a/test/cases.c++ b/test/cases.c++ index fdb99485..41461051 100644 --- a/test/cases.c++ +++ b/test/cases.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/chrono.c++ b/test/chrono.c++ index daf285b1..04353037 100644 --- a/test/chrono.c++ +++ b/test/chrono.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/chrono.h++ b/test/chrono.h++ index 0749db8a..12868b5e 100644 --- a/test/chrono.h++ +++ b/test/chrono.h++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #pragma once diff --git a/test/config.c++ b/test/config.c++ index 514f9ae4..4188e3c0 100644 --- a/test/config.c++ +++ b/test/config.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/config.h++ b/test/config.h++ index 71ff5c97..7c5d0ee6 100644 --- a/test/config.h++ +++ b/test/config.h++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #pragma once diff --git a/test/copy.c++ b/test/copy.c++ index b5d068d8..777ad4d9 100644 --- a/test/copy.c++ +++ b/test/copy.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/dead.c++ b/test/dead.c++ index c34443eb..2cfe818f 100644 --- a/test/dead.c++ +++ b/test/dead.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/extra/doubtless_positioning.c++ b/test/extra/doubtless_positioning.c++ index 28c37492..ecc24daa 100644 --- a/test/extra/doubtless_positioning.c++ +++ b/test/extra/doubtless_positioning.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "mdbx.h++" diff --git a/test/extra/dupfix_multiple.c++ b/test/extra/dupfix_multiple.c++ index a8897314..a212984b 100644 --- a/test/extra/dupfix_multiple.c++ +++ b/test/extra/dupfix_multiple.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "mdbx.h++" diff --git a/test/extra/hex_base64_base58.c++ b/test/extra/hex_base64_base58.c++ index 7ae1fac4..972673e9 100644 --- a/test/extra/hex_base64_base58.c++ +++ b/test/extra/hex_base64_base58.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "mdbx.h++" diff --git a/test/extra/maindb_ordinal.c++ b/test/extra/maindb_ordinal.c++ index c766049f..9e6bd7ef 100644 --- a/test/extra/maindb_ordinal.c++ +++ b/test/extra/maindb_ordinal.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "mdbx.h++" diff --git a/test/extra/pcrf/pcrf_test.c b/test/extra/pcrf/pcrf_test.c index 1d023fcf..1a9d59e2 100644 --- a/test/extra/pcrf/pcrf_test.c +++ b/test/extra/pcrf/pcrf_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 Leonid Yuriev . + * Copyright 2016-2025 Leonid Yuriev . * Copyright 2015 Vladimir Romanov * , Yota Lab. * diff --git a/test/fork.c++ b/test/fork.c++ index d546cf89..c8d4558f 100644 --- a/test/fork.c++ +++ b/test/fork.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/hill.c++ b/test/hill.c++ index ac6254e9..24ac25ce 100644 --- a/test/hill.c++ +++ b/test/hill.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/jitter.c++ b/test/jitter.c++ index 3bf75100..fa190132 100644 --- a/test/jitter.c++ +++ b/test/jitter.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/keygen.c++ b/test/keygen.c++ index 8ac4987d..f73ae55d 100644 --- a/test/keygen.c++ +++ b/test/keygen.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/keygen.h++ b/test/keygen.h++ index 389cab4d..80739fb5 100644 --- a/test/keygen.h++ +++ b/test/keygen.h++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #pragma once diff --git a/test/log.c++ b/test/log.c++ index 9b952785..a1144d5c 100644 --- a/test/log.c++ +++ b/test/log.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/log.h++ b/test/log.h++ index bb92783e..147d2869 100644 --- a/test/log.h++ +++ b/test/log.h++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #pragma once diff --git a/test/main.c++ b/test/main.c++ index 59c58729..bc2bee70 100644 --- a/test/main.c++ +++ b/test/main.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/nested.c++ b/test/nested.c++ index dda73f92..e44b5413 100644 --- a/test/nested.c++ +++ b/test/nested.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/osal-unix.c++ b/test/osal-unix.c++ index 3a6bf215..f440aeca 100644 --- a/test/osal-unix.c++ +++ b/test/osal-unix.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/osal-windows.c++ b/test/osal-windows.c++ index 94f52b4a..b03d73ea 100644 --- a/test/osal-windows.c++ +++ b/test/osal-windows.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/osal.h++ b/test/osal.h++ index 058f7078..85c5f0f3 100644 --- a/test/osal.h++ +++ b/test/osal.h++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #pragma once diff --git a/test/test.c++ b/test/test.c++ index 1d8db898..cf178f95 100644 --- a/test/test.c++ +++ b/test/test.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/test.h++ b/test/test.h++ index 861429ff..3b0afa20 100644 --- a/test/test.h++ +++ b/test/test.h++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #pragma once diff --git a/test/try.c++ b/test/try.c++ index 4333a996..395e641e 100644 --- a/test/try.c++ +++ b/test/try.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/ttl.c++ b/test/ttl.c++ index a4482e1f..9d23c0c6 100644 --- a/test/ttl.c++ +++ b/test/ttl.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/utils.c++ b/test/utils.c++ index 442e4a21..e6da160b 100644 --- a/test/utils.c++ +++ b/test/utils.c++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #include "test.h++" diff --git a/test/utils.h++ b/test/utils.h++ index caa34049..131c75de 100644 --- a/test/utils.h++ +++ b/test/utils.h++ @@ -1,4 +1,4 @@ -/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 +/// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2025 /// \copyright SPDX-License-Identifier: Apache-2.0 #pragma once From 4a0a32a54bbe06016c4e118afde3b2b5f6f97046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 17 Jan 2025 22:41:26 +0300 Subject: [PATCH 004/181] =?UTF-8?q?mdbx-doc:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=20README=20=D1=81?= =?UTF-8?q?=D1=81=D1=8B=D0=BB=D0=BA=D0=B8=20=D0=BD=D0=B0=20=D0=B0=D1=80?= =?UTF-8?q?=D1=85=D0=B8=D0=B2=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B9=20=D1=82=D0=B5=D0=BB=D0=B5=D0=B3=D1=80=D0=B0=D0=BC?= =?UTF-8?q?=D0=BC-=D0=B3=D1=80=D1=83=D0=BF=D0=BF=D1=8B=202020-2024=20?= =?UTF-8?q?=D0=B3=D0=BE=D0=B4=D0=BE=D0=B2=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index df7e67c8..22ea871c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ > with [`C` API description](https://libmdbx.dqdkfa.ru/group__c__api.html) > and pay attention to the [`C++` API](https://gitflic.ru/project/erthink/libmdbx/blob?file=mdbx.h%2B%2B#line-num-1). -> Questions, feedback and suggestions are welcome to the [Telegram' group](https://t.me/libmdbx). +> Questions, feedback and suggestions are welcome to the [Telegram' group](https://t.me/libmdbx) (archive [1](https://libmdbx.dqdkfa.ru/tg-archive/messages1.html), +> [2](https://libmdbx.dqdkfa.ru/tg-archive/messages2.html), [3](https://libmdbx.dqdkfa.ru/tg-archive/messages3.html), [4](https://libmdbx.dqdkfa.ru/tg-archive/messages4.html), +> [5](https://libmdbx.dqdkfa.ru/tg-archive/messages5.html), [6](https://libmdbx.dqdkfa.ru/tg-archive/messages6.html), [7](https://libmdbx.dqdkfa.ru/tg-archive/messages7.html)). > See the [ChangeLog](https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md) for `NEWS` and latest updates. > Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`. From 03685aba5a45896864b1720007dacac70988dc6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 18 Jan 2025 19:03:14 +0300 Subject: [PATCH 005/181] =?UTF-8?q?mdbx-doc:=20=D1=80=D0=B0=D0=B7=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B0=D0=BA=D1=82=D1=83?= =?UTF-8?q?=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D1=85=20=D0=B8=20=D1=83=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D1=80=D0=B5=D0=B2=D1=88=D0=B8=D1=85/=D0=BD=D0=B5?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=B8=D0=B2=D0=B0?= =?UTF-8?q?=D0=B5=D0=BC=D1=8B=D1=85=20=D0=BF=D1=80=D0=B8=D0=B2=D1=8F=D0=B7?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=B2=20README=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 22ea871c..ef65d7e4 100644 --- a/README.md +++ b/README.md @@ -641,19 +641,24 @@ Bindings | Runtime | Repo | Author | | ------- | ------ | ------ | +| Rust | [libmdbx-rs](https://github.com/vorot93/libmdbx-rs) | [Artem Vorotnikov](https://github.com/vorot93) | +| Python | [PyPi/libmdbx](https://pypi.org/project/libmdbx/) | [Lazymio](https://github.com/wtdcode) | +| Java | [mdbxjni](https://github.com/castortech/mdbxjni) | [Castor Technologies](https://castortech.com/) | +| Go | [mdbx-go](https://github.com/torquem-ch/mdbx-go) | [Alex Sharov](https://github.com/AskAlexSharov) | +| Ruby | [ruby-mdbx](https://rubygems.org/gems/mdbx/) | [Mahlon E. Smith](https://github.com/mahlonsmith) | + +##### Obsolete/Outdated/Unsupported: + +| Runtime | Repo | Author | +| ------- | ------ | ------ | +| .NET | [mdbx.NET](https://github.com/wangjia184/mdbx.NET) | [Jerry Wang](https://github.com/wangjia184) | | Scala | [mdbx4s](https://github.com/david-bouyssie/mdbx4s) | [David Bouyssié](https://github.com/david-bouyssie) | +| Rust | [mdbx](https://crates.io/crates/mdbx) | [gcxfd](https://github.com/gcxfd) | | Haskell | [libmdbx-hs](https://hackage.haskell.org/package/libmdbx) | [Francisco Vallarino](https://github.com/fjvallarino) | +| Lua | [lua-libmdbx](https://github.com/mah0x211/lua-libmdbx) | [Masatoshi Fukunaga](https://github.com/mah0x211) | | NodeJS, [Deno](https://deno.land/) | [lmdbx-js](https://github.com/kriszyp/lmdbx-js) | [Kris Zyp](https://github.com/kriszyp/) | NodeJS | [node-mdbx](https://www.npmjs.com/package/node-mdbx/) | [Сергей Федотов](mailto:sergey.fedotov@corp.mail.ru) | -| Ruby | [ruby-mdbx](https://rubygems.org/gems/mdbx/) | [Mahlon E. Smith](https://github.com/mahlonsmith) | -| Go | [mdbx-go](https://github.com/torquem-ch/mdbx-go) | [Alex Sharov](https://github.com/AskAlexSharov) | -| [Nim](https://en.wikipedia.org/wiki/Nim_(programming_language)) | [NimDBX](https://github.com/snej/nimdbx) | [Jens Alfke](https://github.com/snej) -| Lua | [lua-libmdbx](https://github.com/mah0x211/lua-libmdbx) | [Masatoshi Fukunaga](https://github.com/mah0x211) | -| Rust | [libmdbx-rs](https://github.com/vorot93/libmdbx-rs) | [Artem Vorotnikov](https://github.com/vorot93) | -| Rust | [mdbx](https://crates.io/crates/mdbx) | [gcxfd](https://github.com/gcxfd) | -| Java | [mdbxjni](https://github.com/castortech/mdbxjni) | [Castor Technologies](https://castortech.com/) | -| Python | [PyPi/libmdbx](https://pypi.org/project/libmdbx/) | [Lazymio](https://github.com/wtdcode) | -| .NET (obsolete) | [mdbx.NET](https://github.com/wangjia184/mdbx.NET) | [Jerry Wang](https://github.com/wangjia184) | +| Nim | [NimDBX](https://github.com/snej/nimdbx) | [Jens Alfke](https://github.com/snej) From c615e4d0a6b7ae3f333dbd1694086861666fcf3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 19 Jan 2025 02:14:19 +0300 Subject: [PATCH 006/181] =?UTF-8?q?mdbx-doc:=20=D0=B4=D0=BE=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=BA=D0=B0/=D0=B0=D0=BA=D1=82=D1=83=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D1=80=D0=B0=D0=B7?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B0=20"Restrictions=20&=20Caveats"=20(back?= =?UTF-8?q?port).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/_restrictions.md | 79 +++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/docs/_restrictions.md b/docs/_restrictions.md index 7e905b5e..eb488a43 100644 --- a/docs/_restrictions.md +++ b/docs/_restrictions.md @@ -42,18 +42,33 @@ long-lived read transactions, and using the \ref MDBX_LIFORECLAIM mode which addresses subsequent performance degradation. The "next" version of libmdbx (aka \ref MithrilDB) will completely solve this. -- Avoid suspending a process with active transactions. These would then be - "long-lived" as above. +Nonetheless, situations that encourage lengthy read transactions while +intensively updating data should be avoided. For example, you should +avoid suspending/blocking processes/threads performing read +transactions, including during debugging, and use transaction parking if +necessary. -- Avoid aborting a process with an active read-only transaction in scenarios - with high rate of write transactions. The transaction becomes "long-lived" - as above until a check for stale readers is performed or the LCK-file is - reset, since the process may not remove it from the lockfile. This does - not apply to write transactions if the system clears stale writers, see - above. +You should also beware of aborting processes that perform reading +transactions. Despite the fact that libmdbx automatically checks and +cleans readers, as an a process aborting (especially with core dump) can +take a long time, and checking readers cannot be performed too often due +to performance degradation. + +This issue will be addressed in MithrlDB and one of libmdbx releases, +presumably in 2025. To do this, nonlinear GC recycling will be +implemented, without stopping garbage recycling on the old MVCC snapshot +used by a long read transaction. + +After the planned implementation, any long-term reading transaction will +still keep the used MVCC-snapshot (all the database pages forming it) +from being recycled, but it will allow all unused MVCC snapshots to be +recycled, both before and after the readable one. This will eliminate +one of the main architectural flaws inherited from LMDB and caused the +growth of a database in proportion to a volume of data changes made +concurrently with a long-running read transaction. -## Large data items and huge transactions +## Large data items MDBX allows you to store values up to 1 gigabyte in size, but this is not the main functionality for a key-value storage, but an additional @@ -71,6 +86,18 @@ and in the absence of a sufficient sequence of free pages, increase the DB file. Thus, for long values, MDBX provides maximum read performance at the expense of write performance. +Some aspects related to GC have been refined and improved in 2022 within +the first releases of the 0.12.x series. In particular the search for +free consecutive/adjacent pages through GC has been significantly +speeded, including acceleration using NOEN/SSE2/AVX2/AVX512 +instructions. + +This issue will be addressed in MithrlDB and refined within one of +0.15.x libmdbx releases, presumably at end of 2025. + + +### Huge transactions + A similar situation can be with huge transactions, in which a lot of database pages are retired. The retired pages should be put into GC as a list of page numbers for future reuse. But in huge transactions, such a @@ -80,20 +107,15 @@ you delete large amounts of information from the database in a single transaction, MDBX may need to increase the database file to save the list of pages to be retired. -Both of these issues will be addressed in MithrilDB. +This issue was fixed in 2022 within the first releases of the 0.12.x +series by `Big Foot` feature, which now is enabled by default. +See \ref MDBX_ENABLE_BIGFOOT build-time option. -#### Since v0.12.1 and later -Some aspects related to GC have been refined and improved, in particular: - - - The search for free consecutive/adjacent pages through GC has been - significantly speeded, including acceleration using - NOEN/SSE2/AVX2/AVX512 instructions. - - - The `Big Foot` feature which significantly reduces GC overhead for - processing large lists of retired pages from huge transactions. Now - libmdbx avoid creating large chunks of PNLs (page number lists) which - required a long sequences of free pages, aka large/overflow pages. Thus - avoiding searching, allocating and storing such sequences inside GC. +The `Big Foot` feature which significantly reduces GC overhead for +processing large lists of retired pages from huge transactions. Now +libmdbx avoid creating large chunks of PNLs (page number lists) which +required a long sequences of free pages, aka large/overflow pages. Thus +avoiding searching, allocating and storing such sequences inside GC. ## Space reservation @@ -135,9 +157,11 @@ On the other hand, MDBX allow calling \ref mdbx_env_close() in such cases to release resources, but no more and in general this is a wrong way. #### Since v0.13.1 and later -Начиная с версии 0.13.1 в API доступна функция \ref mdbx_env_resurrect_after_fork(), -которая позволяет пере-использовать в дочерних процессах уже открытую среду БД, -но строго без наследования транзакций от родительского процесса. + +Starting from the v0.13.1 release, the \ref mdbx_env_resurrect_after_work() +is available, which allows you to reuse an already open database +environment in child processes, but strictly without inheriting any +transactions from a parent process. ## Read-only mode @@ -149,9 +173,6 @@ to without-LCK mode on appropriate errors (`EROFS`, `EACCESS`, `EPERM`) if the read-only mode was requested by the \ref MDBX_RDONLY flag which is described below. -The "next" version of libmdbx (\ref MithrilDB) will solve this issue for the "many -readers without writer" case. - ## Troubleshooting the LCK-file 1. A broken LCK-file can cause sync issues, including appearance of @@ -166,8 +187,6 @@ readers without writer" case. multiple processes in a lock-free manner and any locking is unwise due to a large overhead. - The "next" version of libmdbx (\ref MithrilDB) will solve this issue. - \note Workaround: Just make all programs using the database close it; the LCK-file is always reset on first open. From 27a2166be7a202b53b061f4e7af38879b7e17df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 21 Jan 2025 15:38:42 +0300 Subject: [PATCH 007/181] =?UTF-8?q?mdbx-doc:=20=D0=B8=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=80=D1=84?= =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B0=D1=84=D0=B8=D0=B8/=D0=BE=D0=BF=D0=B5?= =?UTF-8?q?=D1=87=D0=B0=D1=82=D0=BA=D0=B8=20=D0=B2=20ChangeLog=20(backport?= =?UTF-8?q?).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index bc7ef66c..7b46fddc 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -2459,7 +2459,7 @@ Deprecated functions and flags: - Rework `MADV_DONTNEED` threshold. - Fix `mdbx_chk` utility for don't checking some numbers if walking on the B-tree was disabled. - Use page's mp_txnid for basic integrity checking. - - Add `MDBX_FORCE_ASSERTIONS` built-time option. + - Add `MDBX_FORCE_ASSERTIONS` build-time option. - Rework `MDBX_DBG_DUMP` to avoid performance degradation. - Rename `MDBX_NOSYNC` to `MDBX_SAFE_NOSYNC` for clarity. - Interpret `ERROR_ACCESS_DENIED` from `OpenProcess()` as 'process exists'. From a59c5f9316d1df8b344766b552ef607ada930d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 25 Jan 2025 19:18:18 +0300 Subject: [PATCH 008/181] =?UTF-8?q?mdbx:=20=D1=83=D0=BF=D1=80=D0=BE=D1=89?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20`gcu=5Floose()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gc-put.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/gc-put.c b/src/gc-put.c index b5231773..12bd22da 100644 --- a/src/gc-put.c +++ b/src/gc-put.c @@ -146,20 +146,12 @@ static inline void zeroize_reserved(const MDBX_env *env, MDBX_val pnl) { static int gcu_loose(MDBX_txn *txn, gcu_t *ctx) { tASSERT(txn, txn->tw.loose_count > 0); - /* Return loose page numbers to tw.repnl, - * though usually none are left at this point. + /* Return loose page numbers to tw.repnl, though usually none are left at this point. * The pages themselves remain in dirtylist. */ if (unlikely(!txn->tw.gc.retxl && txn->tw.gc.last_reclaimed < 1)) { - TRACE("%s: try allocate gc-slot for %zu loose-pages", dbg_prefix(ctx), txn->tw.loose_count); - int err = gc_alloc_ex(&ctx->cursor, 0, ALLOC_RESERVE).err; - if (err == MDBX_SUCCESS) { - TRACE("%s: retry since gc-slot for %zu loose-pages available", dbg_prefix(ctx), txn->tw.loose_count); - return MDBX_RESULT_TRUE; - } - - /* Put loose page numbers in tw.retired_pages, - * since unable to return ones to tw.repnl. */ - err = pnl_need(&txn->tw.retired_pages, txn->tw.loose_count); + /* Put loose page numbers in tw.retired_pages, since unable to return ones to tw.repnl. */ + TRACE("%s: merge %zu loose-pages into %s-pages", dbg_prefix(ctx), txn->tw.loose_count, "retired"); + int err = pnl_need(&txn->tw.retired_pages, txn->tw.loose_count); if (unlikely(err != MDBX_SUCCESS)) return err; for (page_t *lp = txn->tw.loose_pages; lp; lp = page_next(lp)) { @@ -167,9 +159,9 @@ static int gcu_loose(MDBX_txn *txn, gcu_t *ctx) { MDBX_ASAN_UNPOISON_MEMORY_REGION(&page_next(lp), sizeof(page_t *)); VALGRIND_MAKE_MEM_DEFINED(&page_next(lp), sizeof(page_t *)); } - TRACE("%s: append %zu loose-pages to retired-pages", dbg_prefix(ctx), txn->tw.loose_count); } else { /* Room for loose pages + temp PNL with same */ + TRACE("%s: merge %zu loose-pages into %s-pages", dbg_prefix(ctx), txn->tw.loose_count, "reclaimed"); int err = pnl_need(&txn->tw.repnl, 2 * txn->tw.loose_count + 2); if (unlikely(err != MDBX_SUCCESS)) return err; @@ -185,7 +177,6 @@ static int gcu_loose(MDBX_txn *txn, gcu_t *ctx) { MDBX_PNL_SETSIZE(loose, count); pnl_sort(loose, txn->geo.first_unallocated); pnl_merge(txn->tw.repnl, loose); - TRACE("%s: append %zu loose-pages to reclaimed-pages", dbg_prefix(ctx), txn->tw.loose_count); } /* filter-out list of dirty-pages from loose-pages */ From 11e1346f9df6f91b302cd8c34ac2e71f2c7bc594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 26 Jan 2025 12:41:19 +0300 Subject: [PATCH 009/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=B5=D1=87?= =?UTF-8?q?=D0=B0=D1=82=D0=BA=D0=B8=20=D0=B2=20`cursor=5Ftouch()`=20(backp?= =?UTF-8?q?ort).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit При переделке курсоров было пропущено отрицание в условии, при оценке кол-ва страниц, которые могут потребоваться для выполнения операции. В текущем понимании ошибка не приводила к каким-либо проблемам, ибо оценка делает по верхней границе с существенным запасом, а в худшем случае это могло приводить к прерыванию транзакции из-за достижения ограничения на кол-во грязных страниц. --- src/cursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cursor.c b/src/cursor.c index 43cf8e48..36ef13cf 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -145,7 +145,7 @@ __hot int cursor_touch(MDBX_cursor *const mc, const MDBX_val *key, const MDBX_va if (!cursor_is_gc(mc)) { need += txn->dbs[FREE_DBI].height + (size_t)3; /* 3) Named DBs also dirty the main DB */ - if (cursor_is_main(mc)) + if (!cursor_is_main(mc)) need += txn->dbs[MAIN_DBI].height + (size_t)3; } #if xMDBX_DEBUG_SPILLING != 2 From b59937adb8a76a65f0a373c50808ad3738d699dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 26 Jan 2025 17:36:40 +0300 Subject: [PATCH 010/181] =?UTF-8?q?mdbx-doc:=20=D0=B8=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=B5?= =?UTF-8?q?=D1=87=D0=B0=D1=82=D0=BA=D0=B8=20=D0=B2=20=D1=83=D0=BF=D0=BE?= =?UTF-8?q?=D0=BC=D0=B8=D0=BD=D0=B0=D0=BD=D0=B8=D0=B8=20`mdbx=5Fenv=5Fresu?= =?UTF-8?q?rrect=5Fafter=5Ffork()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/_restrictions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_restrictions.md b/docs/_restrictions.md index eb488a43..631f625f 100644 --- a/docs/_restrictions.md +++ b/docs/_restrictions.md @@ -158,7 +158,7 @@ release resources, but no more and in general this is a wrong way. #### Since v0.13.1 and later -Starting from the v0.13.1 release, the \ref mdbx_env_resurrect_after_work() +Starting from the v0.13.1 release, the \ref mdbx_env_resurrect_after_fork() is available, which allows you to reuse an already open database environment in child processes, but strictly without inheriting any transactions from a parent process. From 6d346d8630d1cbbcdaf07ea39d80af1c891b17d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 26 Jan 2025 16:18:08 +0300 Subject: [PATCH 011/181] =?UTF-8?q?mdbx-cmake:=20=D0=BF=D0=BE=D0=B4=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B6=D0=BA=D0=B0=20MacOS=20universal=20binaries?= =?UTF-8?q?=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thank Alain Picard (Castor Technologies) so much for this patch and supporting the Java bindings! --- CMakeLists.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0996291b..7d0e3f43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,6 +213,20 @@ if(DEFINED PROJECT_NAME AND NOT MDBX_FORCE_BUILD_AS_MAIN_PROJECT) else() set(SUBPROJECT OFF) set(NOT_SUBPROJECT ON) + + # Setup Apple stuff which should be set prior to the first project() or enable_language() + if(APPLE) + # Enable universal binaries for macOS (target arm64 and x86_64) + if(NOT DEFINED CMAKE_OSX_ARCHITECTURES) + set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") + endif() + + # Set the minimum macOS deployment target if not already defined + if(NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET) + set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0") + endif() + endif() + project(libmdbx C) if(NOT MDBX_AMALGAMATED_SOURCE AND NOT DEFINED BUILD_TESTING) set(BUILD_TESTING ON) From 21630ea115690a5cb39cfa921f9d199271a08102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 27 Jan 2025 11:04:51 +0300 Subject: [PATCH 012/181] =?UTF-8?q?mdbx:=20=D1=83=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B5=D0=B3=D1=80=D0=B5?= =?UTF-8?q?=D1=81=D1=81=D0=B0=20=D0=B2=D0=B5=D1=80=D0=BE=D1=8F=D1=82=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B8=20SIGSEGV=20=D0=BF=D1=80=D0=B8=20?= =?UTF-8?q?=D0=B2=D1=8B=D1=82=D0=B5=D1=81=D0=BD=D0=B5=D0=BD=D0=B8=D0=B8/sp?= =?UTF-8?q?illing=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=20(backport?= =?UTF-8?q?).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ошибка внесена коммитом `a6f7d74a32a3cbcc310916a624a31302dbebfa07` от 2024-03-07 и присутствует в выпусках v0.13.1, v0.13.2, v0.13.3. Проблема оставалась незамеченной из-за специфических условий и низкой вероятности проявления. Суть ошибки: - функция cursor_touch() подготавливает стек страниц курсора к внесению изменений, при этом все страницы в стеке (от корневой до листовой в текущей позиции курсора) должны стать доступными для модификации. - микрооптимизация добавленная коммитом пропускала обход стека, если корневая страница уже доступна для модификации, но это допустимо/корректно только при отсутствии в стеке вытесненных/spilled страниц. - если же складывалась ситуация когда в стека была вытесненная некорневая страница, то она так и оставалась недоступной для записи и при попытке её изменения возникал SIGSEGV. --- src/cursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cursor.c b/src/cursor.c index 36ef13cf..f24677f2 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -168,7 +168,7 @@ __hot int cursor_touch(MDBX_cursor *const mc, const MDBX_val *key, const MDBX_va return err; } - if (likely(mc->top >= 0) && !is_modifable(mc->txn, mc->pg[mc->top])) { + if (likely(is_pointed(mc)) && ((mc->txn->flags & MDBX_TXN_SPILLS) || !is_modifable(mc->txn, mc->pg[mc->top]))) { const int8_t top = mc->top; mc->top = 0; do { From b46d2def80e0fc8924b280c7d1e1fe00de25b391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 27 Jan 2025 12:12:38 +0300 Subject: [PATCH 013/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 7b46fddc..8b436622 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -5,11 +5,34 @@ English version [by liar Google](https://libmdbx-dqdkfa-ru.translate.goog/md__ch and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx.dqdkfa.ru/md__change_log.html). -## v0.13.4 в процессе накопления изменений +## v0.13.4 "Sigma Boy" запланирован на 2025-02-14 Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов. -Предполагаемая дата выпуска между 2025-02-11 и 2025-03-13. +Благодарности: + + - [Алексею Костюку (aka Keller)](https://t.me/keller18306) за сообщения об ошибках и недочетах. + - [Erigon](https://docs.erigon.tech/) за спонсорство. + - [Alain Picard](https://github.com/castortech) for support [Java bindings](https://github.com/castortech/mdbxjni) and MacOS universal binaries patch for CMake build scenario. + - [Alex Sharov](https://github.com/AskAlexSharov) за сообщение об ошибках и тестирование. + +Новое: + + - Поддержка MacOS universal binaries при сборке посредством CMake. + +Исправления: + + - Устранён регресс допускающий SIGSEGV в операциях обновления после вытеснения/spilling страниц в больших транзакциях. + Ошибка присутствует в выпусках v0.13.1, v0.13.2, v0.13.3 и оставалась незамеченной из-за специфических условий и низкой вероятности проявления. + Более подробная информация в описании коммита `a060057e480aa5196c7d5c00ea441c962e3b952d`. + + - Исправлена опечатка в документации в упоминании `mdbx_env_resurrect_after_fork()`. + + - Исправлена опечатка в условном операторе внутри `cursor_touch()`. + При переделке курсоров было пропущено отрицание в условии, при оценке кол-ва страниц, которые могут потребоваться для выполнения операции. + В текущем понимании ошибка не приводила к каким-либо проблемам, ибо оценка делает по верхней границе с существенным запасом, а в худшем + случае это могло приводить к прерыванию транзакции из-за достижения ограничения на кол-во грязных страниц. + -------------------------------------------------------------------------------- From 401454dadf0a025b653e0255d1ab29a45e94b69a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 3 Feb 2025 18:46:01 +0300 Subject: [PATCH 014/181] =?UTF-8?q?mdbx-conan:=20=D0=B8=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=B5?= =?UTF-8?q?=D1=87=D0=B0=D1=82=D0=BA=D0=B8=20=D0=B2=20=D0=B8=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9=20`version=5Fjson=5Fpathname`=20=D0=B2=20verbose-?= =?UTF-8?q?=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=D0=B5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Спасибо Виктору Логунову (https://t.me/vl_username) за сообщение о проблеме. --- ChangeLog.md | 1 + conanfile.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 27d3d853..95e2ad76 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -13,6 +13,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - [Erigon](https://docs.erigon.tech/) за спонсорство. - [Alain Picard](https://github.com/castortech) for support [Java bindings](https://github.com/castortech/mdbxjni) and MacOS universal binaries patch for CMake build scenario. - [Alex Sharov](https://github.com/AskAlexSharov) за сообщение об ошибках и тестирование. + - [Виктору Логунову](https://t.me/vl_username) за сообщение об опечатки в имени переменной в Conan-рецепте. Новое: diff --git a/conanfile.py b/conanfile.py index 79241260..b36e7b44 100644 --- a/conanfile.py +++ b/conanfile.py @@ -228,7 +228,7 @@ class libmdbx(ConanFile): if os.path.exists(version_json_pathname): self.version = json.load( open(version_json_pathname, encoding='utf-8'))['semver'] - version_from = "'" + version_jsonpath_name + "'" + version_from = "'" + version_json_pathname + "'" else: self.version = self.fetch_versioninfo_from_git()['semver'] version_from = 'Git' From 24f2b9b0992b4273989438f5841c147b1030e547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 3 Feb 2025 18:46:01 +0300 Subject: [PATCH 015/181] =?UTF-8?q?mdbx-conan:=20=D0=B8=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=B5?= =?UTF-8?q?=D1=87=D0=B0=D1=82=D0=BA=D0=B8=20=D0=B2=20=D0=B8=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9=20`version=5Fjson=5Fpathname`=20=D0=B2=20verbose-?= =?UTF-8?q?=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=D0=B5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Спасибо Виктору Логунову (https://t.me/vl_username) за сообщение о проблеме. --- ChangeLog.md | 1 + conanfile.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 8b436622..6b23a9df 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -15,6 +15,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - [Erigon](https://docs.erigon.tech/) за спонсорство. - [Alain Picard](https://github.com/castortech) for support [Java bindings](https://github.com/castortech/mdbxjni) and MacOS universal binaries patch for CMake build scenario. - [Alex Sharov](https://github.com/AskAlexSharov) за сообщение об ошибках и тестирование. + - [Виктору Логунову](https://t.me/vl_username) за сообщение об опечатки в имени переменной в Conan-рецепте. Новое: diff --git a/conanfile.py b/conanfile.py index 79241260..b36e7b44 100644 --- a/conanfile.py +++ b/conanfile.py @@ -228,7 +228,7 @@ class libmdbx(ConanFile): if os.path.exists(version_json_pathname): self.version = json.load( open(version_json_pathname, encoding='utf-8'))['semver'] - version_from = "'" + version_jsonpath_name + "'" + version_from = "'" + version_json_pathname + "'" else: self.version = self.fetch_versioninfo_from_git()['semver'] version_from = 'Git' From 4730abe3e55c95e53e05d2ffbd83ed6a7cb21fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 11 Feb 2025 14:01:10 +0300 Subject: [PATCH 016/181] =?UTF-8?q?mdbx:=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D0=B5=20=D1=81=D1=82=D1=80=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D1=83=D1=81=D0=BB=D0=BE=D0=B2=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=B2=20assert-=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA?= =?UTF-8?q?=D0=B5=20=D0=B2=D0=BD=D1=83=D1=82=D1=80=D0=B8=20`recalculate=5F?= =?UTF-8?q?subpage=5Fthresholds()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/page-ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/page-ops.c b/src/page-ops.c index e046bc05..599f12c9 100644 --- a/src/page-ops.c +++ b/src/page-ops.c @@ -726,7 +726,7 @@ void recalculate_subpage_thresholds(MDBX_env *env) { env->subpage_reserve_prereq = page_space(env); else if (env->subpage_reserve_prereq < env->subpage_room_threshold + env->subpage_reserve_limit) env->subpage_reserve_prereq = env->subpage_room_threshold + env->subpage_reserve_limit; - eASSERT(env, env->subpage_reserve_prereq > env->subpage_room_threshold + env->subpage_reserve_limit); + eASSERT(env, env->subpage_reserve_prereq >= env->subpage_room_threshold + env->subpage_reserve_limit); } size_t page_subleaf2_reserve(const MDBX_env *env, size_t host_page_room, size_t subpage_len, size_t item_len) { From 79572b485064c5ec7528b15ffd44773c21796f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 11 Feb 2025 14:03:13 +0300 Subject: [PATCH 017/181] =?UTF-8?q?mdbx:=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D0=B5=20=D1=81=D1=82=D1=80=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D1=83=D1=81=D0=BB=D0=BE=D0=B2=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=B2=20assert-=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA?= =?UTF-8?q?=D0=B5=20=D0=B2=D0=BD=D1=83=D1=82=D1=80=D0=B8=20`recalculate=5F?= =?UTF-8?q?subpage=5Fthresholds()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/page-ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/page-ops.c b/src/page-ops.c index 43e6a79a..11916749 100644 --- a/src/page-ops.c +++ b/src/page-ops.c @@ -726,7 +726,7 @@ void recalculate_subpage_thresholds(MDBX_env *env) { env->subpage_reserve_prereq = page_space(env); else if (env->subpage_reserve_prereq < env->subpage_room_threshold + env->subpage_reserve_limit) env->subpage_reserve_prereq = env->subpage_room_threshold + env->subpage_reserve_limit; - eASSERT(env, env->subpage_reserve_prereq > env->subpage_room_threshold + env->subpage_reserve_limit); + eASSERT(env, env->subpage_reserve_prereq >= env->subpage_room_threshold + env->subpage_reserve_limit); } size_t page_subleaf2_reserve(const MDBX_env *env, size_t host_page_room, size_t subpage_len, size_t item_len) { From 75122b311d3672409823d2477564689ec0be082c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 14 Feb 2025 12:56:12 +0300 Subject: [PATCH 018/181] =?UTF-8?q?mdbx:=20=D0=B2=D1=8B=D0=BF=D1=83=D1=81?= =?UTF-8?q?=D0=BA=200.13.4=20"Sigma=20Boy".?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов. За перечнем доработок и изменений обращайтесь к [ChangeLog](https://libmdbx.dqdkfa.ru/md__change_log.html). git diff' stat: 139 files changed, 391 insertions(+), 208 deletions(-) Signed-off-by: Леонид Юрьев (Leonid Yuriev) --- ChangeLog.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 6b23a9df..f1e01426 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -5,7 +5,7 @@ English version [by liar Google](https://libmdbx-dqdkfa-ru.translate.goog/md__ch and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx.dqdkfa.ru/md__change_log.html). -## v0.13.4 "Sigma Boy" запланирован на 2025-02-14 +## v0.13.4 "Sigma Boy" от 2025-02-14 Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов. @@ -30,10 +30,15 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - Исправлена опечатка в документации в упоминании `mdbx_env_resurrect_after_fork()`. - Исправлена опечатка в условном операторе внутри `cursor_touch()`. - При переделке курсоров было пропущено отрицание в условии, при оценке кол-ва страниц, которые могут потребоваться для выполнения операции. + При переделке курсоров было пропущено отрицание в условии, при оценке количества страниц, которые могут потребоваться для выполнения операции. В текущем понимании ошибка не приводила к каким-либо проблемам, ибо оценка делает по верхней границе с существенным запасом, а в худшем случае это могло приводить к прерыванию транзакции из-за достижения ограничения на кол-во грязных страниц. + - Корректировка излишне строгого условия в assert-проверке внутри `recalculate_subpage_thresholds()`. + Ошибка могла проявляться только в отладочных сборках при выставлении определенной комбинации предельных значений опций `MDBX_opt_subpage_limit`, + `MDBX_opt_subpage_room_threshold`, `MDBX_opt_subpage_reserve_prereq`, `MDBX_opt_subpage_reserve_limit`. + + - Исправление опечатки в Conan-рецепте в коде протокольно-отладочного вывода в имени переменной `version_json_pathname`. -------------------------------------------------------------------------------- From fcdd2e2db3cf2a511547abd200118e5099d1f660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 14 Feb 2025 15:23:28 +0300 Subject: [PATCH 019/181] =?UTF-8?q?mdbx:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index f1e01426..f9df0108 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -4,6 +4,17 @@ ChangeLog English version [by liar Google](https://libmdbx-dqdkfa-ru.translate.goog/md__change_log.html?_x_tr_sl=ru&_x_tr_tl=en) and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx.dqdkfa.ru/md__change_log.html). +## v0.13.5 в процессе накопления изменений + +Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов. + +Благодарности: + + - [Erigon](https://docs.erigon.tech/) за спонсорство. + + +-------------------------------------------------------------------------------- + ## v0.13.4 "Sigma Boy" от 2025-02-14 @@ -11,8 +22,8 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx Благодарности: - - [Алексею Костюку (aka Keller)](https://t.me/keller18306) за сообщения об ошибках и недочетах. - [Erigon](https://docs.erigon.tech/) за спонсорство. + - [Алексею Костюку (aka Keller)](https://t.me/keller18306) за сообщения об ошибках и недочетах. - [Alain Picard](https://github.com/castortech) for support [Java bindings](https://github.com/castortech/mdbxjni) and MacOS universal binaries patch for CMake build scenario. - [Alex Sharov](https://github.com/AskAlexSharov) за сообщение об ошибках и тестирование. - [Виктору Логунову](https://t.me/vl_username) за сообщение об опечатки в имени переменной в Conan-рецепте. @@ -25,7 +36,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - Устранён регресс допускающий SIGSEGV в операциях обновления после вытеснения/spilling страниц в больших транзакциях. Ошибка присутствует в выпусках v0.13.1, v0.13.2, v0.13.3 и оставалась незамеченной из-за специфических условий и низкой вероятности проявления. - Более подробная информация в описании коммита `a060057e480aa5196c7d5c00ea441c962e3b952d`. + Более подробная информация в описании коммита `21630ea115690a5cb39cfa921f9d199271a08102`. - Исправлена опечатка в документации в упоминании `mdbx_env_resurrect_after_fork()`. From aa2ff20fafd8318762d98c9997e4a11b5f2f1ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 14 Feb 2025 21:36:38 +0300 Subject: [PATCH 020/181] =?UTF-8?q?mdbx:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=B0=D1=82=D1=87=D0=B0?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D1=81=D1=82=D0=B0=D1=80=D1=8B=D1=85=20?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D0=B9=20buildroot=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...libmdbx-new-package-library-database.patch | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch b/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch index 9c7afff4..2ccb2846 100644 --- a/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch +++ b/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch @@ -1,7 +1,7 @@ -From 0ba6ba5e6d6311213a21f033729e18826729230a Mon Sep 17 00:00:00 2001 +From 49256dcd050fd0ee67860b7bc544dabe088d08e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= -Date: Tue, 14 Jan 2025 12:57:03 +0300 +Date: Fri, 14 Feb 2025 21:34:25 +0300 Subject: [PATCH] package/libmdbx: new package (library/database). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -13,11 +13,9 @@ This patch adds libmdbx: focused on creating unique lightweight solutions. - libmdbx surpasses the legendary LMDB (Lightning Memory-Mapped Database) in terms of reliability, features and performance. - - more information at https://gitflic.ru/project/erthink/libmdbx + - more information at https://libmdbx.dqdkfa.ru -The 0.13.13 "Korolev" is stable release of _libmdbx_ branch with new superior features -on the birthday and in memory of Sergei Korolev who was the lead Soviet rocket -engineer and spacecraft designer. +The 0.13.4 "Sigma Boy" is stable release of _libmdbx_ branch with new superior features. The complete ChangeLog: https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md @@ -26,9 +24,9 @@ Signed-off-by: Леонид Юрьев (Leonid Yuriev) DEVELOPERS | 3 +++ package/Config.in | 1 + package/libmdbx/Config.in | 45 ++++++++++++++++++++++++++++++++++++ - package/libmdbx/libmdbx.hash | 5 ++++ + package/libmdbx/libmdbx.hash | 6 +++++ package/libmdbx/libmdbx.mk | 42 +++++++++++++++++++++++++++++++++ - 5 files changed, 96 insertions(+) + 5 files changed, 97 insertions(+) create mode 100644 package/libmdbx/Config.in create mode 100644 package/libmdbx/libmdbx.hash create mode 100644 package/libmdbx/libmdbx.mk @@ -112,18 +110,19 @@ index 0000000000..a9a4ac45c5 + !BR2_TOOLCHAIN_GCC_AT_LEAST_4_4 diff --git a/package/libmdbx/libmdbx.hash b/package/libmdbx/libmdbx.hash new file mode 100644 -index 0000000000..1c91aa2f90 +index 0000000000..202937e7be --- /dev/null +++ b/package/libmdbx/libmdbx.hash -@@ -0,0 +1,5 @@ +@@ -0,0 +1,6 @@ +# Hashes from: https://libmdbx.dqdkfa.ru/release/SHA256SUMS -+sha256 2e42505f1ceb57945569db3c1a5db9b5216d8f72da7c75c240ff81196f8e9a0b libmdbx-amalgamated-0.13.3.tar.xz ++sha256 86df30ca2231c9b3ad71424bb829dca9041947f5539d4295030c653d4982c1be libmdbx-amalgamated-0.13.4.tar.xz + +# Locally calculated +sha256 0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594 LICENSE ++sha256 699a62986b6c8d31124646dffd4b15872c7d3bc5eecea5994edb1f5195df49d1 NOTICE diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk new file mode 100644 -index 0000000000..b42ab629fe +index 0000000000..a8a6f3dbdf --- /dev/null +++ b/package/libmdbx/libmdbx.mk @@ -0,0 +1,42 @@ @@ -133,12 +132,12 @@ index 0000000000..b42ab629fe +# +################################################################################ + -+LIBMDBX_VERSION = 0.13.3 ++LIBMDBX_VERSION = 0.13.4 +LIBMDBX_SOURCE = libmdbx-amalgamated-$(LIBMDBX_VERSION).tar.xz +LIBMDBX_SITE = https://libmdbx.dqdkfa.ru/release +LIBMDBX_SUPPORTS_IN_SOURCE_BUILD = NO -+LIBMDBX_LICENSE = OLDAP-2.8 -+LIBMDBX_LICENSE_FILES = LICENSE ++LIBMDBX_LICENSE = Apache-2.0 ++LIBMDBX_LICENSE_FILES = LICENSE NOTICE +LIBMDBX_REDISTRIBUTE = YES +LIBMDBX_STRIP_COMPONENTS = 0 +LIBMDBX_INSTALL_STAGING = YES @@ -170,5 +169,5 @@ index 0000000000..b42ab629fe + +$(eval $(cmake-package)) -- -2.48.0 +2.48.1 From b63ca3c12e65087f22e1d9b1859e9cc300da8007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 14 Feb 2025 21:39:27 +0300 Subject: [PATCH 021/181] =?UTF-8?q?mdbx:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=B0=D1=82=D1=87=D0=B0?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D1=81=D1=82=D0=B0=D1=80=D1=8B=D1=85=20?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D0=B9=20buildroot.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...libmdbx-new-package-library-database.patch | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch b/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch index 9c7afff4..2ccb2846 100644 --- a/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch +++ b/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch @@ -1,7 +1,7 @@ -From 0ba6ba5e6d6311213a21f033729e18826729230a Mon Sep 17 00:00:00 2001 +From 49256dcd050fd0ee67860b7bc544dabe088d08e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= -Date: Tue, 14 Jan 2025 12:57:03 +0300 +Date: Fri, 14 Feb 2025 21:34:25 +0300 Subject: [PATCH] package/libmdbx: new package (library/database). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -13,11 +13,9 @@ This patch adds libmdbx: focused on creating unique lightweight solutions. - libmdbx surpasses the legendary LMDB (Lightning Memory-Mapped Database) in terms of reliability, features and performance. - - more information at https://gitflic.ru/project/erthink/libmdbx + - more information at https://libmdbx.dqdkfa.ru -The 0.13.13 "Korolev" is stable release of _libmdbx_ branch with new superior features -on the birthday and in memory of Sergei Korolev who was the lead Soviet rocket -engineer and spacecraft designer. +The 0.13.4 "Sigma Boy" is stable release of _libmdbx_ branch with new superior features. The complete ChangeLog: https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md @@ -26,9 +24,9 @@ Signed-off-by: Леонид Юрьев (Leonid Yuriev) DEVELOPERS | 3 +++ package/Config.in | 1 + package/libmdbx/Config.in | 45 ++++++++++++++++++++++++++++++++++++ - package/libmdbx/libmdbx.hash | 5 ++++ + package/libmdbx/libmdbx.hash | 6 +++++ package/libmdbx/libmdbx.mk | 42 +++++++++++++++++++++++++++++++++ - 5 files changed, 96 insertions(+) + 5 files changed, 97 insertions(+) create mode 100644 package/libmdbx/Config.in create mode 100644 package/libmdbx/libmdbx.hash create mode 100644 package/libmdbx/libmdbx.mk @@ -112,18 +110,19 @@ index 0000000000..a9a4ac45c5 + !BR2_TOOLCHAIN_GCC_AT_LEAST_4_4 diff --git a/package/libmdbx/libmdbx.hash b/package/libmdbx/libmdbx.hash new file mode 100644 -index 0000000000..1c91aa2f90 +index 0000000000..202937e7be --- /dev/null +++ b/package/libmdbx/libmdbx.hash -@@ -0,0 +1,5 @@ +@@ -0,0 +1,6 @@ +# Hashes from: https://libmdbx.dqdkfa.ru/release/SHA256SUMS -+sha256 2e42505f1ceb57945569db3c1a5db9b5216d8f72da7c75c240ff81196f8e9a0b libmdbx-amalgamated-0.13.3.tar.xz ++sha256 86df30ca2231c9b3ad71424bb829dca9041947f5539d4295030c653d4982c1be libmdbx-amalgamated-0.13.4.tar.xz + +# Locally calculated +sha256 0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594 LICENSE ++sha256 699a62986b6c8d31124646dffd4b15872c7d3bc5eecea5994edb1f5195df49d1 NOTICE diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk new file mode 100644 -index 0000000000..b42ab629fe +index 0000000000..a8a6f3dbdf --- /dev/null +++ b/package/libmdbx/libmdbx.mk @@ -0,0 +1,42 @@ @@ -133,12 +132,12 @@ index 0000000000..b42ab629fe +# +################################################################################ + -+LIBMDBX_VERSION = 0.13.3 ++LIBMDBX_VERSION = 0.13.4 +LIBMDBX_SOURCE = libmdbx-amalgamated-$(LIBMDBX_VERSION).tar.xz +LIBMDBX_SITE = https://libmdbx.dqdkfa.ru/release +LIBMDBX_SUPPORTS_IN_SOURCE_BUILD = NO -+LIBMDBX_LICENSE = OLDAP-2.8 -+LIBMDBX_LICENSE_FILES = LICENSE ++LIBMDBX_LICENSE = Apache-2.0 ++LIBMDBX_LICENSE_FILES = LICENSE NOTICE +LIBMDBX_REDISTRIBUTE = YES +LIBMDBX_STRIP_COMPONENTS = 0 +LIBMDBX_INSTALL_STAGING = YES @@ -170,5 +169,5 @@ index 0000000000..b42ab629fe + +$(eval $(cmake-package)) -- -2.48.0 +2.48.1 From 822213f75d8ce977f4c0ca6bae69786fb22c4d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 15 Feb 2025 15:46:44 +0300 Subject: [PATCH 022/181] =?UTF-8?q?mdbx:=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80?= =?UTF-8?q?=D0=BC=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BE=20=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D1=82=D1=83=D1=81=D0=B5=20Github=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ef65d7e4..f37d56f9 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,51 @@ Historically, _libmdbx_ is a deeply revised and extended descendant of the amazi [Lightning Memory-Mapped Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database). _libmdbx_ inherits all benefits from _LMDB_, but resolves some issues and adds [a set of improvements](#improvements-beyond-lmdb). -### MithrilDB and Future +## Github + +### на Русском (мой родной язык) + +Весной 2022, без каких-либо предупреждений или пояснений, администрация +Github удалила мой аккаунт и все проекты. Через несколько месяцев, без +какого-либо моего участия или уведомления, проекты были +восстановлены/открыты в статусе "public read-only archive" из какой-то +неполноценной резервной копии. Эти действия Github я расцениваю как +злонамеренный саботаж, а сам сервис Github считаю навсегда утратившим +какое-либо доверие. + +Вследствие произошедшего, никогда и ни при каких условиях, я не буду +размещать на Github первоисточники (aka origins) моих проектов, либо +как-либо полагаться на инфраструктуру Github. + +Тем не менее, понимая что пользователям моих проектов удобнее получать к +ним доступ именно на Github, я не хочу ограничивать их свободу или +создавать неудобство, и поэтому размещаю на Github зеркала (aka mirrors) +репозиториев моих проектов. При этом ещё раз акцентирую внимание, что +это только зеркала, которые могут быть заморожены, заблокированы или +удалены в любой момент, как это уже было в 2022. + +### in English + +In the spring of 2022, without any warnings or explanations, the Github +administration deleted my account and all projects. A few months later, +without any involvement or notification from me, the projects were +restored/opened in the "public read-only archive" status from some kind +of incomplete backup. I regard these actions of Github as malicious +sabotage, and I consider the Github service itself to have lost any +trust forever. + +As a result of what has happened, I will never, under any circumstances, +post the primary sources (aka origins) of my projects on Github, or rely +in any way on the Github infrastructure. + +Nevertheless, realizing that it is more convenient for users of my +projects to access them on Github, I do not want to restrict their +freedom or create inconvenience, and therefore I place mirrors of my +project repositories on Github. At the same time, I would like to +emphasize once again that these are only mirrors that can be frozen, +blocked or deleted at any time, as was the case in 2022. + +## MithrilDB and Future From d2864029da83a6038d1ce8d5834c587ddf758c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 15 Feb 2025 15:47:33 +0300 Subject: [PATCH 023/181] =?UTF-8?q?mdbx:=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80?= =?UTF-8?q?=D0=BC=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BE=20=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D1=82=D1=83=D1=81=D0=B5=20Github.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ef65d7e4..f37d56f9 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,51 @@ Historically, _libmdbx_ is a deeply revised and extended descendant of the amazi [Lightning Memory-Mapped Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database). _libmdbx_ inherits all benefits from _LMDB_, but resolves some issues and adds [a set of improvements](#improvements-beyond-lmdb). -### MithrilDB and Future +## Github + +### на Русском (мой родной язык) + +Весной 2022, без каких-либо предупреждений или пояснений, администрация +Github удалила мой аккаунт и все проекты. Через несколько месяцев, без +какого-либо моего участия или уведомления, проекты были +восстановлены/открыты в статусе "public read-only archive" из какой-то +неполноценной резервной копии. Эти действия Github я расцениваю как +злонамеренный саботаж, а сам сервис Github считаю навсегда утратившим +какое-либо доверие. + +Вследствие произошедшего, никогда и ни при каких условиях, я не буду +размещать на Github первоисточники (aka origins) моих проектов, либо +как-либо полагаться на инфраструктуру Github. + +Тем не менее, понимая что пользователям моих проектов удобнее получать к +ним доступ именно на Github, я не хочу ограничивать их свободу или +создавать неудобство, и поэтому размещаю на Github зеркала (aka mirrors) +репозиториев моих проектов. При этом ещё раз акцентирую внимание, что +это только зеркала, которые могут быть заморожены, заблокированы или +удалены в любой момент, как это уже было в 2022. + +### in English + +In the spring of 2022, without any warnings or explanations, the Github +administration deleted my account and all projects. A few months later, +without any involvement or notification from me, the projects were +restored/opened in the "public read-only archive" status from some kind +of incomplete backup. I regard these actions of Github as malicious +sabotage, and I consider the Github service itself to have lost any +trust forever. + +As a result of what has happened, I will never, under any circumstances, +post the primary sources (aka origins) of my projects on Github, or rely +in any way on the Github infrastructure. + +Nevertheless, realizing that it is more convenient for users of my +projects to access them on Github, I do not want to restrict their +freedom or create inconvenience, and therefore I place mirrors of my +project repositories on Github. At the same time, I would like to +emphasize once again that these are only mirrors that can be frozen, +blocked or deleted at any time, as was the case in 2022. + +## MithrilDB and Future From 5388d2273b00297c13cba0c8158e9492f7c08a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 16 Feb 2025 16:52:53 +0300 Subject: [PATCH 024/181] =?UTF-8?q?mdbx-doc:=20=D0=BE=D0=BF=D0=B5=D1=87?= =?UTF-8?q?=D0=B0=D1=82=D0=BA=D0=B8=20=D0=B2=20README.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f37d56f9..1bad0676 100644 --- a/README.md +++ b/README.md @@ -279,7 +279,7 @@ which is also (mostly) applicable to _libmdbx_ with minor clarification: - a database could shared by multiple processes, i.e. no multi-process issues; - no issues with moving a cursor(s) after the deletion; - _libmdbx_ provides zero-overhead database compactification, so a database file could be shrinked/truncated in particular cases; - - excluding dist I/O time _libmdbx_ could be -3 times faster than BoltDB and up to 10-100K times faster than both BoltDB and LMDB in particular extreme cases; + - excluding disk I/O time _libmdbx_ could be ≈3 times faster than BoltDB and up to 10-100K times faster than both BoltDB and LMDB in particular extreme cases; - _libmdbx_ provides more features compared to BoltDB and/or LMDB. From 80de77b1eec98ec92ccaef2ed6d3cb059b751f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 16 Feb 2025 16:52:53 +0300 Subject: [PATCH 025/181] =?UTF-8?q?mdbx-doc:=20=D0=BE=D0=BF=D0=B5=D1=87?= =?UTF-8?q?=D0=B0=D1=82=D0=BA=D0=B8=20=D0=B2=20README=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f37d56f9..1bad0676 100644 --- a/README.md +++ b/README.md @@ -279,7 +279,7 @@ which is also (mostly) applicable to _libmdbx_ with minor clarification: - a database could shared by multiple processes, i.e. no multi-process issues; - no issues with moving a cursor(s) after the deletion; - _libmdbx_ provides zero-overhead database compactification, so a database file could be shrinked/truncated in particular cases; - - excluding dist I/O time _libmdbx_ could be -3 times faster than BoltDB and up to 10-100K times faster than both BoltDB and LMDB in particular extreme cases; + - excluding disk I/O time _libmdbx_ could be ≈3 times faster than BoltDB and up to 10-100K times faster than both BoltDB and LMDB in particular extreme cases; - _libmdbx_ provides more features compared to BoltDB and/or LMDB. From 287bab36a155adc47338af60bd21731fff73f369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 17 Feb 2025 14:43:20 +0300 Subject: [PATCH 026/181] =?UTF-8?q?mdbx-doc:=20=D0=BE=D0=B1=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BD=D1=84?= =?UTF-8?q?=D0=B8=D0=B3=D1=83=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20doxygen.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Doxyfile.in | 734 ++++++++++++++++++++++++++++++----------------- 1 file changed, 470 insertions(+), 264 deletions(-) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 198f2e05..329d9d4c 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -1,7 +1,7 @@ -# Doxyfile 1.9.6 +# Doxyfile 1.13.2 # This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. +# Doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. @@ -15,10 +15,10 @@ # # Note: # -# Use doxygen to compare the used configuration file with the template +# Use Doxygen to compare the used configuration file with the template # configuration file: # doxygen -x [configFile] -# Use doxygen to compare the used configuration file with the template +# Use Doxygen to compare the used configuration file with the template # configuration file without replacing the environment variables or CMake type # replacement variables: # doxygen -x_noenv [configFile] @@ -51,7 +51,7 @@ PROJECT_NAME = libmdbx PROJECT_NUMBER = "${MDBX_VERSION_MAJOR}.${MDBX_VERSION_MINOR}.${MDBX_VERSION_PATCH}.${MDBX_VERSION_TWEAK} (@MDBX_GIT_TIMESTAMP@)" # Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer a +# for a project that appears at the top of each page and should give viewers a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "One of the fastest compact embeddable key-value ACID storage engine without WAL." @@ -63,18 +63,24 @@ PROJECT_BRIEF = "One of the fastest compact embeddable key-value ACID s PROJECT_LOGO = +# With the PROJECT_ICON tag one can specify an icon that is included in the tabs +# when the HTML document is shown. Doxygen will copy the logo to the output +# directory. + +PROJECT_ICON = + # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is -# entered, it will be relative to the location where doxygen was started. If +# entered, it will be relative to the location where Doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = . -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# If the CREATE_SUBDIRS tag is set to YES then Doxygen will create up to 4096 # sub-directories (in 2 levels) under the output directory of each output format # and will distribute the generated files over these directories. Enabling this -# option can be useful when feeding doxygen a huge amount of source files, where -# putting all generated files in the same directory would otherwise causes +# option can be useful when feeding Doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise cause # performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to # control the number of sub-directories. # The default value is: NO. @@ -92,7 +98,7 @@ CREATE_SUBDIRS = NO CREATE_SUBDIRS_LEVEL = 8 -# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# If the ALLOW_UNICODE_NAMES tag is set to YES, Doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. @@ -101,7 +107,7 @@ CREATE_SUBDIRS_LEVEL = 8 ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this +# documentation generated by Doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, # Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English @@ -115,14 +121,14 @@ ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# If the BRIEF_MEMBER_DESC tag is set to YES, Doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# If the REPEAT_BRIEF tag is set to YES, Doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the @@ -153,13 +159,13 @@ ABBREVIATE_BRIEF = "The $name class" \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# doxygen will generate a detailed section even if there is only a brief +# Doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# If the INLINE_INHERITED_MEMB tag is set to YES, Doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. @@ -167,7 +173,7 @@ ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# If the FULL_PATH_NAMES tag is set to YES, Doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. @@ -177,11 +183,11 @@ FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the path to +# If left blank the directory from which Doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which -# will be relative from the directory where doxygen is started. +# will be relative from the directory where Doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = @@ -195,41 +201,42 @@ STRIP_FROM_PATH = STRIP_FROM_INC_PATH = -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but -# less readable) file names. This can be useful is your file systems doesn't +# If the SHORT_NAMES tag is set to YES, Doxygen will generate much shorter (but +# less readable) file names. This can be useful if your file system doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO -# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the -# first line (until the first dot) of a Javadoc-style comment as the brief -# description. If set to NO, the Javadoc-style will behave just like regular Qt- -# style comments (thus requiring an explicit @brief command for a brief -# description.) +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen will interpret the +# first line (until the first dot, question mark or exclamation mark) of a +# Javadoc-style comment as the brief description. If set to NO, the Javadoc- +# style will behave just like regular Qt-style comments (thus requiring an +# explicit @brief command for a brief description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO -# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# If the JAVADOC_BANNER tag is set to YES then Doxygen will interpret a line # such as # /*************** # as being the beginning of a Javadoc-style comment "banner". If set to NO, the # Javadoc-style will behave just like regular comments and it will not be -# interpreted by doxygen. +# interpreted by Doxygen. # The default value is: NO. JAVADOC_BANNER = NO -# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first -# line (until the first dot) of a Qt-style comment as the brief description. If -# set to NO, the Qt-style will behave just like regular Qt-style comments (thus -# requiring an explicit \brief command for a brief description.) +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will interpret the first +# line (until the first dot, question mark or exclamation mark) of a Qt-style +# comment as the brief description. If set to NO, the Qt-style will behave just +# like regular Qt-style comments (thus requiring an explicit \brief command for +# a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this @@ -241,10 +248,10 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO -# By default Python docstrings are displayed as preformatted text and doxygen's +# By default Python docstrings are displayed as preformatted text and Doxygen's # special commands cannot be used. By setting PYTHON_DOCSTRING to NO the -# doxygen's special commands can be used and the contents of the docstring -# documentation blocks is shown as doxygen documentation. +# Doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as Doxygen documentation. # The default value is: YES. PYTHON_DOCSTRING = YES @@ -255,7 +262,7 @@ PYTHON_DOCSTRING = YES INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# If the SEPARATE_MEMBER_PAGES tag is set to YES then Doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. @@ -325,30 +332,30 @@ OPTIMIZE_OUTPUT_SLICE = NO # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# language is one of the parsers supported by Doxygen: IDL, Java, JavaScript, # Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, # VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the -# default for Fortran type files). For instance to make doxygen treat .inc files +# default for Fortran type files). For instance to make Doxygen treat .inc files # as Fortran files (default is PHP), and .f files as C (default is Fortran), # use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. When specifying no_extension you should add +# the files are not read by Doxygen. When specifying no_extension you should add # * to the FILE_PATTERNS. # # Note see also the list of default file extension mappings. EXTENSION_MAPPING = -# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# If the MARKDOWN_SUPPORT tag is enabled then Doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See https://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you can -# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# The output of markdown processing is further processed by Doxygen, so you can +# mix Doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. @@ -358,25 +365,45 @@ MARKDOWN_SUPPORT = YES # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 5. +# Minimum value: 0, maximum value: 99, default value: 6. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 5 -# When enabled doxygen tries to link words that correspond to documented +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + +# When enabled Doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or -# globally by setting AUTOLINK_SUPPORT to NO. +# globally by setting AUTOLINK_SUPPORT to NO. Words listed in the +# AUTOLINK_IGNORE_WORDS tag are excluded from automatic linking. # The default value is: YES. AUTOLINK_SUPPORT = YES +# This tag specifies a list of words that, when matching the start of a word in +# the documentation, will suppress auto links generation, if it is enabled via +# AUTOLINK_SUPPORT. This list does not affect affect links explicitly created +# using \# or the \link or commands. +# This tag requires that the tag AUTOLINK_SUPPORT is set to YES. + +AUTOLINK_IGNORE_WORDS = + # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and +# tag to YES in order to let Doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. +# versus func(std::string) {}). This also makes the inheritance and +# collaboration diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = YES @@ -388,16 +415,16 @@ BUILTIN_STL_SUPPORT = YES CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. +# https://www.riverbankcomputing.com/software) sources only. Doxygen will parse +# them like normal C++ but will assume all classes use public instead of private +# inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. +# Doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. @@ -406,7 +433,7 @@ SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES then doxygen will reuse the documentation of the first +# tag is set to YES then Doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. @@ -464,18 +491,18 @@ TYPEDEF_HIDES_STRUCT = YES # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the -# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small -# doxygen will become slower. If the cache is too large, memory is wasted. The +# code, Doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# Doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 -# symbols. At the end of a run doxygen will report the cache usage and suggest +# symbols. At the end of a run Doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 -# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use -# during processing. When set to 0 doxygen will based this on the number of +# The NUM_PROC_THREADS specifies the number of threads Doxygen is allowed to use +# during processing. When set to 0 Doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing # speed. At this moment only the input processing can be done using multiple @@ -487,11 +514,19 @@ LOOKUP_CACHE_SIZE = 0 NUM_PROC_THREADS = 1 +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = NO + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# If the EXTRACT_ALL tag is set to YES, Doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. @@ -557,7 +592,7 @@ EXTRACT_ANON_NSPACES = NO RESOLVE_UNNAMED_PARAMS = YES -# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. @@ -565,7 +600,7 @@ RESOLVE_UNNAMED_PARAMS = YES HIDE_UNDOC_MEMBERS = NO -# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # will also hide undocumented C++ concepts if enabled. This option has no effect @@ -574,14 +609,22 @@ HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# If the HIDE_UNDOC_NAMESPACES tag is set to YES, Doxygen will hide all +# undocumented namespaces that are normally visible in the namespace hierarchy. +# If set to NO, these namespaces will be included in the various overviews. This +# option has no effect if EXTRACT_ALL is enabled. +# The default value is: YES. + +HIDE_UNDOC_NAMESPACES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all friend # declarations. If set to NO, these declarations will be included in the # documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO -# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. @@ -595,7 +638,7 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO -# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# With the correct setting of option CASE_SENSE_NAMES Doxygen will better be # able to match the capabilities of the underlying filesystem. In case the # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly @@ -604,7 +647,7 @@ INTERNAL_DOCS = NO # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On -# Windows (including Cygwin) and MacOS, users should typically set this option +# Windows (including Cygwin) and macOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. # Possible values are: SYSTEM, NO and YES. @@ -612,14 +655,14 @@ INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO -# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# If the HIDE_SCOPE_NAMES tag is set to NO then Doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO -# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then Doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. @@ -632,7 +675,7 @@ HIDE_COMPOUND_REFERENCE= NO SHOW_HEADERFILE = YES -# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# If the SHOW_INCLUDE_FILES tag is set to YES then Doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -645,7 +688,7 @@ SHOW_INCLUDE_FILES = YES SHOW_GROUPED_MEMB_INC = NO -# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. @@ -657,14 +700,14 @@ FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES -# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# If the SORT_MEMBER_DOCS tag is set to YES then Doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# If the SORT_BRIEF_DOCS tag is set to YES then Doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. @@ -672,7 +715,7 @@ SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then Doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. @@ -684,7 +727,7 @@ SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = YES -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# If the SORT_GROUP_NAMES tag is set to YES then Doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. @@ -701,11 +744,11 @@ SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# If the STRICT_PROTO_MATCHING option is enabled and Doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a -# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# simple string match. By disabling STRICT_PROTO_MATCHING Doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. @@ -775,25 +818,25 @@ SHOW_FILES = YES SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from +# Doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided -# by doxygen. Whatever the program writes to standard output is used as the file +# by Doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated +# by Doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can +# that represents Doxygen's defaults, run Doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. See also section "Changing the # layout of pages" for information. # -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# Note that if you run Doxygen from a directory containing a file called +# DoxygenLayout.xml, Doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = @@ -808,19 +851,35 @@ LAYOUT_FILE = CITE_BIB_FILES = +# The EXTERNAL_TOOL_PATH tag can be used to extend the search path (PATH +# environment variable) so that external tools such as latex and gs can be +# found. +# Note: Directories specified with EXTERNAL_TOOL_PATH are added in front of the +# path already specified by the PATH variable, and are added in the order +# specified. +# Note: This option is particularly useful for macOS version 14 (Sonoma) and +# higher, when running Doxygen from Doxywizard, because in this case any user- +# defined changes to the PATH are ignored. A typical example on macOS is to set +# EXTERNAL_TOOL_PATH = /Library/TeX/texbin /usr/local/bin +# together with the standard path, the full search path used by doxygen when +# launching external tools will then become +# PATH=/Library/TeX/texbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin + +EXTERNAL_TOOL_PATH = + #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the +# standard output by Doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# generated to standard error (stderr) by Doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. @@ -828,14 +887,14 @@ QUIET = NO WARNINGS = YES -# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# If the WARN_IF_UNDOCUMENTED tag is set to YES then Doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES -# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# If the WARN_IF_DOC_ERROR tag is set to YES, Doxygen will generate warnings for # potential errors in the documentation, such as documenting some parameters in # a documented function twice, or documenting parameters that don't exist or # using markup commands wrongly. @@ -843,8 +902,8 @@ WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES -# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete -# function parameter documentation. If set to NO, doxygen will accept that some +# If WARN_IF_INCOMPLETE_DOC is set to YES, Doxygen will warn about incomplete +# function parameter documentation. If set to NO, Doxygen will accept that some # parameters have no documentation without warning. # The default value is: YES. @@ -852,7 +911,7 @@ WARN_IF_INCOMPLETE_DOC = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong parameter +# value. If set to NO, Doxygen will only warn about wrong parameter # documentation, but not about the absence of documentation. If EXTRACT_ALL is # set to YES then this flag will automatically be disabled. See also # WARN_IF_INCOMPLETE_DOC @@ -860,24 +919,39 @@ WARN_IF_INCOMPLETE_DOC = YES WARN_NO_PARAMDOC = NO -# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about -# undocumented enumeration values. If set to NO, doxygen will accept +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, Doxygen will warn about +# undocumented enumeration values. If set to NO, Doxygen will accept # undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: NO. WARN_IF_UNDOC_ENUM_VAL = NO -# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# If WARN_LAYOUT_FILE option is set to YES, Doxygen will warn about issues found +# while parsing the user defined layout file, such as missing or wrong elements. +# See also LAYOUT_FILE for details. If set to NO, problems with the layout file +# will be suppressed. +# The default value is: YES. + +WARN_LAYOUT_FILE = YES + +# If the WARN_AS_ERROR tag is set to YES then Doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS -# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but -# at the end of the doxygen process doxygen will return with a non-zero status. -# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# then Doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the Doxygen process Doxygen will return with a non-zero status. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then Doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined Doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. WARN_AS_ERROR = NO -# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# The WARN_FORMAT tag determines the format of the warning messages that Doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will @@ -890,7 +964,7 @@ WARN_FORMAT = "$file:$line: $text" # In the $text part of the WARN_FORMAT command it is possible that a reference # to a more specific place is given. To make it easier to jump to this place -# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# (outside of Doxygen) the user can define a custom "cut" / "paste" string. # Example: # WARN_LINE_FORMAT = "'vi $file +$line'" # See also: WARN_FORMAT @@ -926,7 +1000,7 @@ INPUT = overall.md \ 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 +# that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. @@ -936,12 +1010,12 @@ INPUT = overall.md \ INPUT_ENCODING = UTF-8 # This tag can be used to specify the character encoding of the source files -# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# that Doxygen parses. The INPUT_FILE_ENCODING tag can be used to specify # character encoding on a per file pattern basis. Doxygen will compare the file # name with each pattern and apply the encoding instead of the default -# INPUT_ENCODING) if there is a match. The character encodings are a list of the -# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding -# "INPUT_ENCODING" for further information on supported encodings. +# INPUT_ENCODING if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). +# See also: INPUT_ENCODING for further information on supported encodings. INPUT_FILE_ENCODING = @@ -951,17 +1025,17 @@ INPUT_FILE_ENCODING = # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not -# read by doxygen. +# read by Doxygen. # # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, -# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C -# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, -# *.vhdl, *.ucf, *.qsf and *.ice. +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, +# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, +# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to +# be provided as Doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.h @@ -975,7 +1049,7 @@ RECURSIVE = NO # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # -# Note that relative paths are relative to the directory from which doxygen is +# Note that relative paths are relative to the directory from which Doxygen is # run. EXCLUDE = @@ -1001,9 +1075,6 @@ EXCLUDE_PATTERNS = # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # ANamespace::AClass, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = NOMINMAX \ __ORDER_BIG_ENDIAN__ \ @@ -1062,7 +1133,7 @@ EXAMPLE_RECURSIVE = NO IMAGE_PATH = -# The INPUT_FILTER tag can be used to specify a program that doxygen should +# The INPUT_FILTER tag can be used to specify a program that Doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # @@ -1077,14 +1148,14 @@ IMAGE_PATH = # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # -# Note that doxygen will use the data processed and written to standard output +# Note that Doxygen will use the data processed and written to standard output # for further processing, therefore nothing else, like debug statements or used # commands (so in case of a Windows batch file always use @echo OFF), should be # written to standard output. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not -# properly processed by doxygen. +# properly processed by Doxygen. INPUT_FILTER = @@ -1097,7 +1168,7 @@ INPUT_FILTER = # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not -# properly processed by doxygen. +# properly processed by Doxygen. FILTER_PATTERNS = @@ -1119,10 +1190,19 @@ FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub -# and want to reuse the introduction page also for the doxygen output. +# and want to reuse the introduction page also for the Doxygen output. USE_MDFILE_AS_MAINPAGE = +# If the IMPLICIT_DIR_DOCS tag is set to YES, any README.md file found in sub- +# directories of the project's root, is used as the documentation for that sub- +# directory, except when the README.md starts with a \dir, \page or \mainpage +# command. If set to NO, the README.md file needs to start with an explicit \dir +# command in order to be used as directory documentation. +# The default value is: YES. + +IMPLICIT_DIR_DOCS = YES + # The Fortran standard specifies that for fixed formatted Fortran code all # characters from position 72 are to be considered as comment. A common # extension is to allow longer lines before the automatic comment starts. The @@ -1146,12 +1226,13 @@ FORTRAN_COMMENT_AFTER = 72 SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. +# multi-line macros, enums or list initialized variables directly into the +# documentation. # The default value is: NO. INLINE_SOURCES = NO -# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct Doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. @@ -1189,7 +1270,7 @@ REFERENCES_LINK_SOURCE = YES SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will -# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# point to the HTML generated by the htags(1) tool instead of Doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. @@ -1203,14 +1284,14 @@ SOURCE_TOOLTIPS = YES # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # -# The result: instead of the source browser generated by doxygen, the links to +# The result: instead of the source browser generated by Doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# If the VERBATIM_HEADERS tag is set the YES then Doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. @@ -1242,7 +1323,7 @@ IGNORE_PREFIX = # Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# If the GENERATE_HTML tag is set to YES, Doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES @@ -1263,40 +1344,40 @@ HTML_OUTPUT = html HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for -# each generated HTML page. If the tag is left blank doxygen will generate a +# each generated HTML page. If the tag is left blank Doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. +# that Doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally +# for information on how to generate the default header that Doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description +# default header when upgrading to a newer version of Doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = header.html # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard +# generated HTML page. If the tag is left blank Doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. +# that Doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of -# the HTML output. If left blank doxygen will generate a default style sheet. +# the HTML output. If left blank Doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style -# sheet that doxygen normally uses. +# sheet that Doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. @@ -1306,7 +1387,7 @@ HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets -# created by doxygen. Using this option one can overrule certain style aspects. +# created by Doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. @@ -1334,11 +1415,11 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE tag can be used to specify if the generated HTML output # should be rendered with a dark or light theme. -# Possible values are: LIGHT always generate light mode output, DARK always -# generate dark mode output, AUTO_LIGHT automatically set the mode according to -# the user preference, use light mode if no preference is set (the default), -# AUTO_DARK automatically set the mode according to the user preference, use -# dark mode if no preference is set and TOGGLE allow to user to switch between +# Possible values are: LIGHT always generates light mode output, DARK always +# generates dark mode output, AUTO_LIGHT automatically sets the mode according +# to the user preference, uses light mode if no preference is set (the default), +# AUTO_DARK automatically sets the mode according to the user preference, uses +# dark mode if no preference is set and TOGGLE allows a user to switch between # light and dark mode via a button. # The default value is: AUTO_LIGHT. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1394,6 +1475,33 @@ HTML_DYNAMIC_MENUS = YES HTML_DYNAMIC_SECTIONS = NO +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + +# If the HTML_COPY_CLIPBOARD tag is set to YES then Doxygen will show an icon in +# the top right corner of code and text fragments that allows the user to copy +# its content to the clipboard. Note this only works if supported by the browser +# and the web page is served via a secure context (see: +# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file: +# protocol. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COPY_CLIPBOARD = YES + +# Doxygen stores a couple of settings persistently in the browser (via e.g. +# cookies). By default these settings apply to all HTML pages generated by +# Doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# the settings under a project specific key, such that the user preferences will +# be stored separately. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_PROJECT_COOKIE = + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1411,7 +1519,7 @@ HTML_INDEX_NUM_ENTRIES = 100 # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: # https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To -# create a documentation set, doxygen will generate a Makefile in the HTML +# create a documentation set, Doxygen will generate a Makefile in the HTML # output directory. Running make will produce the docset in that directory and # running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at @@ -1459,18 +1567,18 @@ DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher -# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# If the GENERATE_HTMLHELP tag is set to YES then Doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # on Windows. In the beginning of 2021 Microsoft took the original page, with -# a.o. the download links, offline the HTML help workshop was already many years -# in maintenance mode). You can download the HTML help workshop from the web -# archives at Installation executable (see: +# a.o. the download links, offline (the HTML help workshop was already many +# years in maintenance mode). You can download the HTML help workshop from the +# web archives at Installation executable (see: # http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo # ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output -# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# generated by Doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for @@ -1490,7 +1598,7 @@ CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, -# doxygen will try to run the HTML help compiler on the generated index.hhp. +# Doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1524,6 +1632,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = https://libmdbx.dqdkfa.ru/sitemap.xml + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -1582,7 +1700,7 @@ QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location (absolute path -# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# including file name) of Qt's qhelpgenerator. If non-empty Doxygen will try to # run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1614,7 +1732,7 @@ ECLIPSE_DOC_ID = org.doxygen.Project # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. -# The default value is: NO. +# The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = YES @@ -1627,11 +1745,11 @@ DISABLE_INDEX = YES # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine tune the look of the index (see "Fine-tuning the output"). As an -# example, the default style sheet generated by doxygen has an example that +# example, the default style sheet generated by Doxygen has an example that # shows how to put an image at the root of the tree instead of the PROJECT_NAME. # Since the tree basically has the same information as the tab index, you could # consider setting DISABLE_INDEX to YES when enabling this option. -# The default value is: NO. +# The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = YES @@ -1649,7 +1767,7 @@ GENERATE_TREEVIEW = YES FULL_SIDEBAR = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that -# doxygen will group on one line in the generated HTML documentation. +# Doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. @@ -1658,6 +1776,12 @@ FULL_SIDEBAR = NO ENUM_VALUES_PER_LINE = 4 +# When the SHOW_ENUM_VALUES tag is set doxygen will show the specified +# enumeration values besides the enumeration mnemonics. +# The default value is: NO. + +SHOW_ENUM_VALUES = NO + # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. @@ -1665,21 +1789,21 @@ ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 -# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# If the EXT_LINKS_IN_WINDOW option is set to YES, Doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO -# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# If the OBFUSCATE_EMAILS tag is set to YES, Doxygen will obfuscate email # addresses. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. OBFUSCATE_EMAILS = YES -# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# If the HTML_FORMULA_FORMAT option is set to svg, Doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for # the HTML output. These images will generally look nicer at scaled resolutions. @@ -1692,7 +1816,7 @@ HTML_FORMULA_FORMAT = png # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful -# doxygen run you need to manually remove any form_*.png images from the HTML +# Doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1736,7 +1860,7 @@ MATHJAX_VERSION = MathJax_2 # Possible values are: HTML-CSS (which is slower, but has the best # compatibility. This is the name for Mathjax version 2, for MathJax version 3 # this will be translated into chtml), NativeMML (i.e. MathML. Only supported -# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# for MathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This # is the name for Mathjax version 3, for MathJax version 2 this will be # translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. @@ -1770,7 +1894,7 @@ MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ MATHJAX_EXTENSIONS = -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# The MATHJAX_CODEFILE tag can be used to specify a file with JavaScript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: # http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an @@ -1779,12 +1903,12 @@ MATHJAX_EXTENSIONS = MATHJAX_CODEFILE = -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and +# When the SEARCHENGINE tag is enabled Doxygen will generate a search box for +# the HTML output. The underlying search engine uses JavaScript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then +# For large projects the JavaScript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically @@ -1803,7 +1927,7 @@ SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using JavaScript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH -# setting. When disabled, doxygen will generate a PHP script for searching and +# setting. When disabled, Doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing # and searching needs to be provided by external tools. See the section # "External Indexing and Searching" for details. @@ -1812,7 +1936,7 @@ SEARCHENGINE = YES SERVER_BASED_SEARCH = NO -# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# When EXTERNAL_SEARCH tag is enabled Doxygen will no longer generate the PHP # script for searching. Instead the search results are written to an XML file # which needs to be processed by an external indexer. Doxygen will invoke an # external search engine pointed to by the SEARCHENGINE_URL option to obtain the @@ -1857,7 +1981,7 @@ SEARCHDATA_FILE = searchdata.xml EXTERNAL_SEARCH_ID = -# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through Doxygen # projects other than the one defined by this configuration file, but that are # all added to the same external search index. Each project needs to have a # unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of @@ -1871,7 +1995,7 @@ EXTRA_SEARCH_MAPPINGS = # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# If the GENERATE_LATEX tag is set to YES, Doxygen will generate LaTeX output. # The default value is: YES. GENERATE_LATEX = NO @@ -1916,7 +2040,7 @@ MAKEINDEX_CMD_NAME = makeindex LATEX_MAKEINDEX_CMD = makeindex -# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# If the COMPACT_LATEX tag is set to YES, Doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1947,15 +2071,15 @@ EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for # the generated LaTeX document. The header should contain everything until the -# first chapter. If it is left blank doxygen will generate a standard header. It +# first chapter. If it is left blank Doxygen will generate a standard header. It # is highly recommended to start with a default header using # doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty # and then modify the file new_header.tex. See also section "Doxygen usage" for -# information on how to generate the default header that doxygen normally uses. +# information on how to generate the default header that Doxygen normally uses. # # Note: Only use a user-defined header if you know what you are doing! # Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. The following +# default header when upgrading to a newer version of Doxygen. The following # commands have a special meaning inside the header (and footer): For a # description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1964,10 +2088,10 @@ LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for # the generated LaTeX document. The footer should contain everything after the -# last chapter. If it is left blank doxygen will generate a standard footer. See +# last chapter. If it is left blank Doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what # special commands can be used inside the footer. See also section "Doxygen -# usage" for information on how to generate the default footer that doxygen +# usage" for information on how to generate the default footer that Doxygen # normally uses. Note: Only use a user-defined footer if you know what you are # doing! # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1976,7 +2100,7 @@ LATEX_FOOTER = # The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined # LaTeX style sheets that are included after the standard style sheets created -# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# by Doxygen. Using this option one can overrule certain style aspects. Doxygen # will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the @@ -2002,7 +2126,7 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# If the USE_PDFLATEX tag is set to YES, Doxygen will use the engine as # specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX # files. Set this option to YES, to get a higher quality PDF documentation. # @@ -2012,15 +2136,22 @@ PDF_HYPERLINKS = YES USE_PDFLATEX = YES -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. +# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BATCHMODE = NO -# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# If the LATEX_HIDE_INDICES tag is set to YES then Doxygen will not include the # index chapters (such as File Index, Compound Index, etc.) in the output. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -2030,7 +2161,7 @@ LATEX_HIDE_INDICES = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See # https://en.wikipedia.org/wiki/BibTeX and \cite for more info. -# The default value is: plain. +# The default value is: plainnat. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BIB_STYLE = plain @@ -2047,7 +2178,7 @@ LATEX_EMOJI_DIRECTORY = # Configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# If the GENERATE_RTF tag is set to YES, Doxygen will generate RTF output. The # RTF output is optimized for Word 97 and may not look too pretty with other RTF # readers/editors. # The default value is: NO. @@ -2062,7 +2193,7 @@ GENERATE_RTF = NO RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# If the COMPACT_RTF tag is set to YES, Doxygen generates more compact RTF # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -2082,28 +2213,36 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's +# Load stylesheet definitions from file. Syntax is similar to Doxygen's # configuration file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the -# default style sheet that doxygen normally uses. +# default style sheet that Doxygen normally uses. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is -# similar to doxygen's configuration file. A template extensions file can be +# similar to Doxygen's configuration file. A template extensions file can be # generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = +# The RTF_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the RTF_OUTPUT output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTRA_FILES = + #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# If the GENERATE_MAN tag is set to YES, Doxygen will generate man pages for # classes and files. # The default value is: NO. @@ -2134,7 +2273,7 @@ MAN_EXTENSION = .3 MAN_SUBDIR = -# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, then it # will generate one additional man file for each entity documented in the real # man page(s). These additional files only source the real man page, but without # them the man command would be unable to find the correct page. @@ -2147,7 +2286,7 @@ MAN_LINKS = NO # Configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# If the GENERATE_XML tag is set to YES, Doxygen will generate an XML file that # captures the structure of the code including all documentation. # The default value is: NO. @@ -2161,7 +2300,7 @@ GENERATE_XML = NO XML_OUTPUT = xml -# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# If the XML_PROGRAMLISTING tag is set to YES, Doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size # of the XML output. @@ -2170,7 +2309,7 @@ XML_OUTPUT = xml XML_PROGRAMLISTING = YES -# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, Doxygen will include # namespace members in file scope as well, matching the HTML output. # The default value is: NO. # This tag requires that the tag GENERATE_XML is set to YES. @@ -2181,7 +2320,7 @@ XML_NS_MEMB_FILE_SCOPE = NO # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- -# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# If the GENERATE_DOCBOOK tag is set to YES, Doxygen will generate Docbook files # that can be used to generate PDF. # The default value is: NO. @@ -2199,19 +2338,45 @@ DOCBOOK_OUTPUT = docbook # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# If the GENERATE_AUTOGEN_DEF tag is set to YES, Doxygen will generate an +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to Sqlite3 output +#--------------------------------------------------------------------------- + +# If the GENERATE_SQLITE3 tag is set to YES Doxygen will generate a Sqlite3 +# database with symbols found by Doxygen stored in tables. +# The default value is: NO. + +GENERATE_SQLITE3 = NO + +# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be +# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put +# in front of it. +# The default directory is: sqlite3. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_OUTPUT = sqlite3 + +# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db +# database file will be recreated with each Doxygen run. If set to NO, Doxygen +# will warn if a database file is already found and not modify it. +# The default value is: YES. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_RECREATE_DB = YES + #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# If the GENERATE_PERLMOD tag is set to YES, Doxygen will generate a Perl module # file that captures the structure of the code including all documentation. # # Note that this feature is still experimental and incomplete at the moment. @@ -2219,7 +2384,7 @@ GENERATE_AUTOGEN_DEF = NO GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# If the PERLMOD_LATEX tag is set to YES, Doxygen will generate the necessary # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI # output from the Perl module output. # The default value is: NO. @@ -2249,13 +2414,13 @@ PERLMOD_MAKEVAR_PREFIX = # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# If the ENABLE_PREPROCESSING tag is set to YES, Doxygen will evaluate all # C-preprocessor directives found in the sources and include files. # The default value is: YES. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# If the MACRO_EXPANSION tag is set to YES, Doxygen will expand all macro names # in the source code. If set to NO, only conditional compilation will be # performed. Macro expansion can be done in a controlled way by setting # EXPAND_ONLY_PREDEF to YES. @@ -2339,7 +2504,7 @@ PREDEFINED = DOXYGEN \ EXPAND_AS_DEFINED = -# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# If the SKIP_FUNCTION_MACROS tag is set to YES then Doxygen's preprocessor will # remove all references to function-like macros that are alone on a line, have # an all uppercase name, and do not end with a semicolon. Such function macros # are typically used for boiler-plate code, and will confuse the parser if not @@ -2363,26 +2528,26 @@ SKIP_FUNCTION_MACROS = NO # section "Linking to external documentation" for more information about the use # of tag files. # Note: Each tag file must have a unique name (where the name does NOT include -# the path). If a tag file is not located in the directory in which doxygen is +# the path). If a tag file is not located in the directory in which Doxygen is # run, you must also specify the path to the tagfile here. TAGFILES = -# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# When a file name is specified after GENERATE_TAGFILE, Doxygen will create a # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES, all external class will be listed in -# the class index. If set to NO, only the inherited external classes will be -# listed. +# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces +# will be listed in the class and namespace index. If set to NO, only the +# inherited external classes will be listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will be +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. @@ -2396,33 +2561,26 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = NO #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# You can include diagrams made with dia in doxygen documentation. Doxygen will -# then run dia to produce the diagram and insert it in the documentation. The -# DIA_PATH tag allows you to specify the directory where the dia binary resides. -# If left empty dia is assumed to be found in the default search path. - -DIA_PATH = - # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. HIDE_UNDOC_RELATIONS = YES -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# If you set the HAVE_DOT tag to YES then Doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO -# The default value is: NO. +# The default value is: YES. HAVE_DOT = NO -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed -# to run in parallel. When set to 0 doxygen will base this on the number of +# The DOT_NUM_THREADS specifies the number of dot invocations Doxygen is allowed +# to run in parallel. When set to 0 Doxygen will base this on the number of # processors available in the system. You can set it explicitly to a value # larger than 0 to get control over the balance between CPU load and processing # speed. @@ -2433,7 +2591,7 @@ DOT_NUM_THREADS = 0 # DOT_COMMON_ATTR is common attributes for nodes, edges and labels of # subgraphs. When you want a differently looking font in the dot files that -# doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# Doxygen generates you can specify fontname, fontcolor and fontsize attributes. # For details please see Node, # Edge and Graph Attributes specification You need to make sure dot is able # to find the font, which can be done by putting it in a standard location or by @@ -2467,35 +2625,47 @@ DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a -# graph for each documented class showing the direct and indirect inheritance -# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, -# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set -# to TEXT the direct and indirect inheritance relations will be shown as texts / -# links. -# Possible values are: NO, YES, TEXT and GRAPH. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then Doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. Explicit enabling an inheritance +# graph or choosing a different representation for an inheritance graph of a +# specific class, can be accomplished by means of the command \inheritancegraph. +# Disabling an inheritance graph can be accomplished by means of the command +# \hideinheritancegraph. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. CLASS_GRAPH = TEXT -# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# If the COLLABORATION_GRAPH tag is set to YES then Doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES -# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. See also the chapter Grouping -# in the manual. +# If the GROUP_GRAPHS tag is set to YES then Doxygen will generate a graph for +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# If the UML_LOOK tag is set to YES, Doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. # The default value is: NO. @@ -2516,10 +2686,10 @@ UML_LOOK = NO UML_LIMIT_NUM_FIELDS = 10 -# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# If the DOT_UML_DETAILS tag is set to NO, Doxygen will show attributes and # methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS -# tag is set to YES, doxygen will add type and arguments for attributes and -# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# tag is set to YES, Doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, Doxygen # will not generate fields with class member information in the UML graphs. The # class diagrams will look similar to the default class diagrams but using UML # notation for the relationships. @@ -2531,8 +2701,8 @@ DOT_UML_DETAILS = NO # The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters # to display on a single line. If the actual line length exceeds this threshold -# significantly it will wrapped across multiple lines. Some heuristics are apply -# to avoid ugly line breaks. +# significantly it will be wrapped across multiple lines. Some heuristics are +# applied to avoid ugly line breaks. # Minimum value: 0, maximum value: 1000, default value: 17. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2547,24 +2717,29 @@ DOT_WRAP_THRESHOLD = 17 TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to -# YES then doxygen will generate a graph for each documented file showing the +# YES then Doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are -# set to YES then doxygen will generate a graph for each documented file showing +# set to YES then Doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. INCLUDED_BY_GRAPH = YES -# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# If the CALL_GRAPH tag is set to YES then Doxygen will generate a call # dependency graph for every global function or class method. # # Note that enabling this option will significantly increase the time of a run. @@ -2576,7 +2751,7 @@ INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO -# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# If the CALLER_GRAPH tag is set to YES then Doxygen will generate a caller # dependency graph for every global function or class method. # # Note that enabling this option will significantly increase the time of a run. @@ -2588,17 +2763,20 @@ CALL_GRAPH = NO CALLER_GRAPH = NO -# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# If the GRAPHICAL_HIERARCHY tag is set to YES then Doxygen will graphical # hierarchy of all classes instead of a textual one. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GRAPHICAL_HIERARCHY = YES -# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# If the DIRECTORY_GRAPH tag is set to YES then Doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2614,25 +2792,30 @@ DIR_GRAPH_MAX_DEPTH = 1 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: -# http://www.graphviz.org/)). -# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order -# to make the SVG files visible in IE 9+ (other browsers do not have this -# requirement). +# https://www.graphviz.org/)). +# +# Note the formats svg:cairo and svg:cairo:cairo cannot be used in combination +# with INTERACTIVE_SVG (the INTERACTIVE_SVG will be set to NO). # Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, -# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and -# png:gdiplus:gdiplus. +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus, +# png:gdiplus:gdiplus, svg:cairo, svg:cairo:cairo, svg:svg, svg:svg:core, +# gif:cairo, gif:cairo:gd, gif:cairo:gdiplus, gif:gdiplus, gif:gdiplus:gdiplus, +# gif:gd, gif:gd:gd, jpg:cairo, jpg:cairo:gd, jpg:cairo:gdiplus, jpg:gd, +# jpg:gd:gd, jpg:gdiplus and jpg:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. DOT_IMAGE_FORMAT = png -# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to -# enable generation of interactive SVG images that allow zooming and panning. +# If DOT_IMAGE_FORMAT is set to svg or svg:svg or svg:svg:core, then this option +# can be set to YES to enable generation of interactive SVG images that allow +# zooming and panning. # # Note that this requires a modern browser other than Internet Explorer. Tested # and working are Firefox, Chrome, Safari, and Opera. -# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make -# the SVG files visible. Older versions of IE do not have SVG support. +# +# Note This option will be automatically disabled when DOT_IMAGE_FORMAT is set +# to svg:cairo or svg:cairo:cairo. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2651,11 +2834,12 @@ DOT_PATH = DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile -# command). +# You can include diagrams made with dia in Doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. -MSCFILE_DIRS = +DIA_PATH = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile @@ -2663,7 +2847,7 @@ MSCFILE_DIRS = DIAFILE_DIRS = -# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# When using PlantUML, the PLANTUML_JAR_PATH tag should be used to specify the # path where java can find the plantuml.jar file or to the filename of jar file # to be used. If left blank, it is assumed PlantUML is not used or called during # a preprocessing step. Doxygen will generate a warning when it encounters a @@ -2671,20 +2855,26 @@ DIAFILE_DIRS = PLANTUML_JAR_PATH = -# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a -# configuration file for plantuml. +# When using PlantUML, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for PlantUML. PLANTUML_CFG_FILE = -# When using plantuml, the specified paths are searched for files specified by -# the !include statement in a plantuml block. +# When using PlantUML, the specified paths are searched for files specified by +# the !include statement in a PlantUML block. PLANTUML_INCLUDE_PATH = +# The PLANTUMLFILE_DIRS tag can be used to specify one or more directories that +# contain PlantUml files that are included in the documentation (see the +# \plantumlfile command). + +PLANTUMLFILE_DIRS = + # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes -# larger than this value, doxygen will truncate the graph, which is visualized -# by representing a node as a red box. Note that doxygen if the number of direct +# larger than this value, Doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that if the number of direct # children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that # the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. @@ -2714,17 +2904,17 @@ MAX_DOT_GRAPH_DEPTH = 0 DOT_MULTI_TARGETS = NO -# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# If the GENERATE_LEGEND tag is set to YES Doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. -# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# Note: This tag requires that UML_LOOK isn't set, i.e. the Doxygen internal # graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate +# If the DOT_CLEANUP tag is set to YES, Doxygen will remove the intermediate # files that are used to generate the various graphs. # # Note: This setting is not only used for dot files but also for msc temporary @@ -2732,3 +2922,19 @@ GENERATE_LEGEND = YES # The default value is: YES. DOT_CLEANUP = YES + +# You can define message sequence charts within Doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then Doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, Doxygen will call the tool as prog -T +# -o . The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = From 818740976ba23424ab23e1d81e9ad4a7798859a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 17 Feb 2025 15:01:57 +0300 Subject: [PATCH 027/181] =?UTF-8?q?mdbx-doc:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D1=81=D1=8B=D0=BB?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=BD=D0=B0=20=D0=BF=D1=80=D0=B8=D0=B2=D1=8F?= =?UTF-8?q?=D0=B7=D0=BA=D1=83=20=D0=BA=20Zig.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1bad0676..69f67b9b 100644 --- a/README.md +++ b/README.md @@ -690,6 +690,7 @@ Bindings | Java | [mdbxjni](https://github.com/castortech/mdbxjni) | [Castor Technologies](https://castortech.com/) | | Go | [mdbx-go](https://github.com/torquem-ch/mdbx-go) | [Alex Sharov](https://github.com/AskAlexSharov) | | Ruby | [ruby-mdbx](https://rubygems.org/gems/mdbx/) | [Mahlon E. Smith](https://github.com/mahlonsmith) | +| Zig | [mdbx-zig](https://github.com/theseyan/lmdbx-zig) | [Sayan J. Das](https://github.com/theseyan) | ##### Obsolete/Outdated/Unsupported: From 05cdf9d202b14ac09c801c7893e65271fa27f378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Wed, 19 Feb 2025 23:06:39 +0300 Subject: [PATCH 028/181] =?UTF-8?q?mdbx:=20=D1=83=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B8=D0=B7=D0=BB=D0=B8=D1=88?= =?UTF-8?q?=D0=BD=D0=B5=D0=B3=D0=BE=20=D0=BF=D1=80=D0=B5=D0=B4=D1=83=D0=BF?= =?UTF-8?q?=D1=80=D0=B5=D0=B6=D0=B4=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=20=D1=81=D0=BC=D0=B5=D0=BD=D0=B5=20=D1=80=D0=B0=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D1=80=D0=B0=20=D0=91=D0=94=20=D0=B2=D0=BE=20=D0=B2?= =?UTF-8?q?=D1=80=D0=B5=D0=BC=D1=8F=20=D0=BE=D1=82=D0=BA=D1=80=D1=8B=D1=82?= =?UTF-8?q?=D0=B8=D1=8F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Изменение геометрии (увеличение размера) больших БД может быть не возможно после их открытия вследствие системных ограничений (отсутствия свободного адресного пространства). Поэтому API предусматривает возможность запросить изменение геометрии/размера БД перед её открытием. В этом сценарии ранее могло выдаваться лишнее/ненужное предупреждение о несоответствии файла БД новому размеру. Теперь этот недостаток исправлен. Спасибо Илье Михееву (Erigon) за сообщение об этом недочете. --- src/dxb.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/dxb.c b/src/dxb.c index c5a08752..2e963dd0 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -567,6 +567,7 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit return err; } + bool new_size_from_user = false; const size_t used_bytes = pgno2bytes(env, header.geometry.first_unallocated); const size_t used_aligned2os_bytes = ceil_powerof2(used_bytes, globals.sys_pagesize); if ((env->flags & MDBX_RDONLY) /* readonly */ @@ -601,6 +602,8 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit /* pre-shrink if enabled */ env->geo_in_bytes.now = used_bytes + env->geo_in_bytes.shrink - used_bytes % env->geo_in_bytes.shrink; + /* сейчас БД еще не открыта, поэтому этот вызов не изменит геометрию, но проверит и скорректирует параметры + * с учетом реального размера страницы. */ err = mdbx_env_set_geometry(env, env->geo_in_bytes.lower, env->geo_in_bytes.now, env->geo_in_bytes.upper, env->geo_in_bytes.grow, env->geo_in_bytes.shrink, header.pagesize); if (unlikely(err != MDBX_SUCCESS)) { @@ -608,8 +611,10 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit return (err == MDBX_EINVAL) ? MDBX_INCOMPATIBLE : err; } - /* update meta fields */ - header.geometry.now = bytes2pgno(env, env->geo_in_bytes.now); + /* altering fields to match geometry given from user */ + new_size_from_user = header.geometry.now != bytes2pgno(env, env->geo_in_bytes.now); + if (new_size_from_user) + header.geometry.now = bytes2pgno(env, env->geo_in_bytes.now); header.geometry.lower = bytes2pgno(env, env->geo_in_bytes.lower); header.geometry.upper = bytes2pgno(env, env->geo_in_bytes.upper); header.geometry.grow_pv = pages2pv(bytes2pgno(env, env->geo_in_bytes.grow)); @@ -646,9 +651,10 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit env->geo_in_bytes.now, bytes2pgno(env, env->geo_in_bytes.now), filesize_before, bytes2pgno(env, (size_t)filesize_before)); } else { - WARNING("filesize mismatch (expect %" PRIuSIZE "b/%" PRIaPGNO "p, have %" PRIu64 "b/%" PRIaPGNO "p)", - env->geo_in_bytes.now, bytes2pgno(env, env->geo_in_bytes.now), filesize_before, - bytes2pgno(env, (size_t)filesize_before)); + if (!new_size_from_user) + WARNING("filesize mismatch (expect %" PRIuSIZE "b/%" PRIaPGNO "p, have %" PRIu64 "b/%" PRIaPGNO "p)", + env->geo_in_bytes.now, bytes2pgno(env, env->geo_in_bytes.now), filesize_before, + bytes2pgno(env, (size_t)filesize_before)); if (filesize_before < used_bytes) { ERROR("last-page beyond end-of-file (last %" PRIaPGNO ", have %" PRIaPGNO ")", header.geometry.first_unallocated, bytes2pgno(env, (size_t)filesize_before)); From 0ef0f49e2e3b33c5b89e5834ed0e12ce3edd6629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Wed, 19 Feb 2025 23:38:15 +0300 Subject: [PATCH 029/181] =?UTF-8?q?mdbx:=20=D1=83=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B8=D0=B7=D0=BB=D0=B8=D1=88?= =?UTF-8?q?=D0=BD=D0=B5=D0=B3=D0=BE=20=D0=BF=D1=80=D0=B5=D0=B4=D1=83=D0=BF?= =?UTF-8?q?=D1=80=D0=B5=D0=B6=D0=B4=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=20=D1=81=D0=BC=D0=B5=D0=BD=D0=B5=20=D1=80=D0=B0=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D1=80=D0=B0=20=D0=91=D0=94=20=D0=B2=D0=BE=20=D0=B2?= =?UTF-8?q?=D1=80=D0=B5=D0=BC=D1=8F=20=D0=BE=D1=82=D0=BA=D1=80=D1=8B=D1=82?= =?UTF-8?q?=D0=B8=D1=8F=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Изменение геометрии (увеличение размера) больших БД может быть не возможно после их открытия вследствие системных ограничений (отсутствия свободного адресного пространства). Поэтому API предусматривает возможность запросить изменение геометрии/размера БД перед её открытием. В этом сценарии ранее могло выдаваться лишнее/ненужное предупреждение о несоответствии файла БД новому размеру. Теперь этот недостаток исправлен. Спасибо Илье Михееву (Erigon) за сообщение об этом недочете. --- ChangeLog.md | 7 +++++++ src/dxb.c | 16 +++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index f9df0108..a1859394 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -11,7 +11,14 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx Благодарности: - [Erigon](https://docs.erigon.tech/) за спонсорство. + - [Илье Михееву](https://t.me/IlyaMkhv) за сообщение о лишнем/ненужном предупреждении несоответствия файла БД новому размеру. +Исправления: + + - Устранение лишнего/ненужного предупреждения в сценарии изменения размера БД посредством вызова `mdbx_env_set_geometry()` до её открытия. + API предусматривает возможность запросить изменение геометрии/размера БД перед её открытием, чтобы избежать как лишних накладных расходов, + так и потенциальных ошибок из-за нехватки адресного пространства. В этом сценарии ранее могло выдаваться лишнее/ненужное предупреждение + о несоответствии файла БД новому размеру. Теперь этот недостаток исправлен. -------------------------------------------------------------------------------- diff --git a/src/dxb.c b/src/dxb.c index aa222025..22379d33 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -567,6 +567,7 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit return err; } + bool new_size_from_user = false; const size_t used_bytes = pgno2bytes(env, header.geometry.first_unallocated); const size_t used_aligned2os_bytes = ceil_powerof2(used_bytes, globals.sys_pagesize); if ((env->flags & MDBX_RDONLY) /* readonly */ @@ -601,6 +602,8 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit /* pre-shrink if enabled */ env->geo_in_bytes.now = used_bytes + env->geo_in_bytes.shrink - used_bytes % env->geo_in_bytes.shrink; + /* сейчас БД еще не открыта, поэтому этот вызов не изменит геометрию, но проверит и скорректирует параметры + * с учетом реального размера страницы. */ err = mdbx_env_set_geometry(env, env->geo_in_bytes.lower, env->geo_in_bytes.now, env->geo_in_bytes.upper, env->geo_in_bytes.grow, env->geo_in_bytes.shrink, header.pagesize); if (unlikely(err != MDBX_SUCCESS)) { @@ -608,8 +611,10 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit return (err == MDBX_EINVAL) ? MDBX_INCOMPATIBLE : err; } - /* update meta fields */ - header.geometry.now = bytes2pgno(env, env->geo_in_bytes.now); + /* altering fields to match geometry given from user */ + new_size_from_user = header.geometry.now != bytes2pgno(env, env->geo_in_bytes.now); + if (new_size_from_user) + header.geometry.now = bytes2pgno(env, env->geo_in_bytes.now); header.geometry.lower = bytes2pgno(env, env->geo_in_bytes.lower); header.geometry.upper = bytes2pgno(env, env->geo_in_bytes.upper); header.geometry.grow_pv = pages2pv(bytes2pgno(env, env->geo_in_bytes.grow)); @@ -646,9 +651,10 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit env->geo_in_bytes.now, bytes2pgno(env, env->geo_in_bytes.now), filesize_before, bytes2pgno(env, (size_t)filesize_before)); } else { - WARNING("filesize mismatch (expect %" PRIuSIZE "b/%" PRIaPGNO "p, have %" PRIu64 "b/%" PRIaPGNO "p)", - env->geo_in_bytes.now, bytes2pgno(env, env->geo_in_bytes.now), filesize_before, - bytes2pgno(env, (size_t)filesize_before)); + if (!new_size_from_user) + WARNING("filesize mismatch (expect %" PRIuSIZE "b/%" PRIaPGNO "p, have %" PRIu64 "b/%" PRIaPGNO "p)", + env->geo_in_bytes.now, bytes2pgno(env, env->geo_in_bytes.now), filesize_before, + bytes2pgno(env, (size_t)filesize_before)); if (filesize_before < used_bytes) { ERROR("last-page beyond end-of-file (last %" PRIaPGNO ", have %" PRIaPGNO ")", header.geometry.first_unallocated, bytes2pgno(env, (size_t)filesize_before)); From 806f819bae9dc69986cb748ee5866ad9fae449ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Wed, 19 Feb 2025 16:44:30 +0300 Subject: [PATCH 030/181] =?UTF-8?q?mdbx-tests:=20=D0=B4=D0=BE=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20extra-open.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/open.c++ | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/extra/open.c++ b/test/extra/open.c++ index 55b58c8c..0722b227 100644 --- a/test/extra/open.c++ +++ b/test/extra/open.c++ @@ -44,6 +44,13 @@ int main(int argc, const char *argv[]) { txn2.commit(); } + { + mdbx::env::operate_parameters operateParameters(100, 10); + mdbx::env_managed::create_parameters createParameters; + createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, 2 * mdbx::env::geometry::TiB); + mdbx::env_managed env(path, createParameters, operateParameters); + } + mdbx::env::operate_parameters operateParameters(100, 10); mdbx::env_managed::create_parameters createParameters; createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, 84 * mdbx::env::geometry::MiB); From 26cd5ebc4323488cbc33c2d3fbd29c3ede8841e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Feb 2025 00:13:21 +0300 Subject: [PATCH 031/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 95e2ad76..be1b644e 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -14,6 +14,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - [Alain Picard](https://github.com/castortech) for support [Java bindings](https://github.com/castortech/mdbxjni) and MacOS universal binaries patch for CMake build scenario. - [Alex Sharov](https://github.com/AskAlexSharov) за сообщение об ошибках и тестирование. - [Виктору Логунову](https://t.me/vl_username) за сообщение об опечатки в имени переменной в Conan-рецепте. + - [Илье Михееву](https://t.me/IlyaMkhv) за сообщение о лишнем/ненужном предупреждении несоответствия файла БД новому размеру. Новое: @@ -42,6 +43,11 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx Ошибка присутствует в выпусках v0.13.1, v0.13.2, v0.13.3 и оставалась незамеченной из-за специфических условий и низкой вероятности проявления. Более подробная информация в описании коммита `cb8eec6d11cdab4f7d3cf87913e8009149dcf60b`. + - Устранение лишнего/ненужного предупреждения в сценарии изменения размера БД посредством вызова `mdbx_env_set_geometry()` до её открытия. + API предусматривает возможность запросить изменение геометрии/размера БД перед её открытием, чтобы избежать как лишних накладных расходов, + так и потенциальных ошибок из-за нехватки адресного пространства. В этом сценарии ранее могло выдаваться лишнее/ненужное предупреждение + о несоответствии файла БД новому размеру. Теперь этот недостаток исправлен. + Прочие доработки: - Существенный рефакторинг с реструктуризацией кода, переименованием внутренних структур, их полей и внутренних функций. From 54d8c0d2908dc598e7d6c0981d1b5c1ffce1684f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Feb 2025 22:21:47 +0300 Subject: [PATCH 032/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=B5=D1=80=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D0=B0=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0=20=D0=91=D0=94=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D0=BE=D1=82=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D0=B8?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Переработка 05cdf9d202b14ac09c801c7893e65271fa27f378. У предыдущего варианта был недостаток, при необходимости выдачи предупреждения и открытии БД с изменением геометрии, предупреждение не выдавалось, что может затруднять анализ/разбор проблемных ситуаций. --- src/dxb.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/dxb.c b/src/dxb.c index 2e963dd0..fc453b1c 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -567,7 +567,7 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit return err; } - bool new_size_from_user = false; + size_t expected_filesize = 0; const size_t used_bytes = pgno2bytes(env, header.geometry.first_unallocated); const size_t used_aligned2os_bytes = ceil_powerof2(used_bytes, globals.sys_pagesize); if ((env->flags & MDBX_RDONLY) /* readonly */ @@ -612,28 +612,25 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit } /* altering fields to match geometry given from user */ - new_size_from_user = header.geometry.now != bytes2pgno(env, env->geo_in_bytes.now); - if (new_size_from_user) - header.geometry.now = bytes2pgno(env, env->geo_in_bytes.now); + expected_filesize = pgno_align2os_bytes(env, header.geometry.now); + header.geometry.now = bytes2pgno(env, env->geo_in_bytes.now); header.geometry.lower = bytes2pgno(env, env->geo_in_bytes.lower); header.geometry.upper = bytes2pgno(env, env->geo_in_bytes.upper); header.geometry.grow_pv = pages2pv(bytes2pgno(env, env->geo_in_bytes.grow)); header.geometry.shrink_pv = pages2pv(bytes2pgno(env, env->geo_in_bytes.shrink)); - VERBOSE("amended: root %" PRIaPGNO "/%" PRIaPGNO ", geo %" PRIaPGNO "/%" PRIaPGNO "-%" PRIaPGNO "/%" PRIaPGNO + VERBOSE("amending: root %" PRIaPGNO "/%" PRIaPGNO ", geo %" PRIaPGNO "/%" PRIaPGNO "-%" PRIaPGNO "/%" PRIaPGNO " +%u -%u, txn_id %" PRIaTXN ", %s", header.trees.main.root, header.trees.gc.root, header.geometry.lower, header.geometry.first_unallocated, header.geometry.now, header.geometry.upper, pv2pages(header.geometry.grow_pv), pv2pages(header.geometry.shrink_pv), unaligned_peek_u64(4, header.txnid_a), durable_caption(&header)); } else { - /* fetch back 'now/current' size, since it was ignored during comparison - * and may differ. */ + /* fetch back 'now/current' size, since it was ignored during comparison and may differ. */ env->geo_in_bytes.now = pgno_align2os_bytes(env, header.geometry.now); } ENSURE(env, header.geometry.now >= header.geometry.first_unallocated); } else { - /* geo-params are not pre-configured by user, - * get current values from the meta. */ + /* geo-params are not pre-configured by user, get current values from the meta. */ env->geo_in_bytes.now = pgno2bytes(env, header.geometry.now); env->geo_in_bytes.lower = pgno2bytes(env, header.geometry.lower); env->geo_in_bytes.upper = pgno2bytes(env, header.geometry.upper); @@ -643,18 +640,19 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit ENSURE(env, pgno_align2os_bytes(env, header.geometry.now) == env->geo_in_bytes.now); ENSURE(env, env->geo_in_bytes.now >= used_bytes); + if (!expected_filesize) + expected_filesize = env->geo_in_bytes.now; const uint64_t filesize_before = env->dxb_mmap.filesize; if (unlikely(filesize_before != env->geo_in_bytes.now)) { if (lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE) { - VERBOSE("filesize mismatch (expect %" PRIuPTR "b/%" PRIaPGNO "p, have %" PRIu64 "b/%" PRIaPGNO "p), " - "assume other process working", + VERBOSE("filesize mismatch (expect %" PRIuPTR "b/%" PRIaPGNO "p, have %" PRIu64 "b/%" PRIu64 + "p), assume other process working", env->geo_in_bytes.now, bytes2pgno(env, env->geo_in_bytes.now), filesize_before, - bytes2pgno(env, (size_t)filesize_before)); + filesize_before >> env->ps2ln); } else { - if (!new_size_from_user) - WARNING("filesize mismatch (expect %" PRIuSIZE "b/%" PRIaPGNO "p, have %" PRIu64 "b/%" PRIaPGNO "p)", - env->geo_in_bytes.now, bytes2pgno(env, env->geo_in_bytes.now), filesize_before, - bytes2pgno(env, (size_t)filesize_before)); + if (filesize_before != expected_filesize) + WARNING("filesize mismatch (expect %" PRIuSIZE "b/%" PRIaPGNO "p, have %" PRIu64 "b/%" PRIu64 "p)", + expected_filesize, bytes2pgno(env, expected_filesize), filesize_before, filesize_before >> env->ps2ln); if (filesize_before < used_bytes) { ERROR("last-page beyond end-of-file (last %" PRIaPGNO ", have %" PRIaPGNO ")", header.geometry.first_unallocated, bytes2pgno(env, (size_t)filesize_before)); From 66c747e4a91af231701d79c2288e69e07418e4a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Feb 2025 22:22:34 +0300 Subject: [PATCH 033/181] =?UTF-8?q?mdbx-cmake:=20=D0=BA=D0=BE=D1=80=D1=80?= =?UTF-8?q?=D0=B5=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20=D1=84?= =?UTF-8?q?=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20(=D0=BA=D0=BE=D1=81=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D0=B8=D0=BA=D0=B0).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmake/compiler.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake index ac2280aa..a3d789ce 100644 --- a/cmake/compiler.cmake +++ b/cmake/compiler.cmake @@ -668,7 +668,9 @@ if(CMAKE_COMPILER_IS_CLANG) if(CMAKE_CLANG_AR AND CMAKE_CLANG_NM AND CMAKE_CLANG_RANLIB - AND ((CLANG_LTO_PLUGIN AND CMAKE_LD_GOLD) OR CMAKE_CLANG_LD OR APPLE)) + AND ((CLANG_LTO_PLUGIN AND CMAKE_LD_GOLD) + OR CMAKE_CLANG_LD + OR APPLE)) if(ANDROID AND CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 12) set(CLANG_LTO_AVAILABLE FALSE) message( From 9b31c517e65ebbd758f5cc810f563112ce268093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Feb 2025 23:04:56 +0300 Subject: [PATCH 034/181] =?UTF-8?q?mdbx:=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D1=8F=D0=B5=D0=BC=20=D0=B2=D1=8B=D1=80=D0=B0=D0=B2=D0=BD?= =?UTF-8?q?=D0=B8=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B0=D0=B7=D0=BC?= =?UTF-8?q?=D0=B5=D1=80=D0=B0=20=D0=91=D0=94=20=D0=BD=D0=B0=20=D1=8E=D0=BD?= =?UTF-8?q?=D0=B8=D1=82=20=D0=B2=D1=8B=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BF=D0=B0=D0=BC=D1=8F=D1=82=D0=B8,=20=D0=B0=20?= =?UTF-8?q?=D0=BD=D0=B5=20=D0=BD=D0=B0=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D1=80=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D1=8B.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Теоретически до этого коммита могла быть некоторая неувязка: - при открытии БД с размером страницы 4K на Windows (где размер секции кратен 64K) в режиме read-only, - после того как БД использовалась на POSIX (где размер отображения кратен размеру системной страницы). Ранее ошибка могла возвращаться со стороны системы (например INVALID_PARAMETER) и по ней крайне сложно было понять в чем дело. Теперь же будет логирование ошибки и возврат MDBX_WANNA_RECOVERY. --- src/dxb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dxb.c b/src/dxb.c index fc453b1c..f55e4b76 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -660,8 +660,9 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit } if (env->flags & MDBX_RDONLY) { - if (filesize_before & (globals.sys_pagesize - 1)) { - ERROR("%s", "filesize should be rounded-up to system page"); + if (filesize_before & (globals.sys_allocation_granularity - 1)) { + ERROR("filesize should be rounded-up to system allocation granularity %u", + globals.sys_allocation_granularity); return MDBX_WANNA_RECOVERY; } WARNING("%s", "ignore filesize mismatch in readonly-mode"); From c14bb7814f35f334a142a1149b4ea8322f4c4565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Feb 2025 23:48:48 +0300 Subject: [PATCH 035/181] =?UTF-8?q?mdbx-tests:=20=D0=B8=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20extra-open=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=2032-=D0=B1=D0=B8=D1=82=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?=D1=81=D0=B1=D0=BE=D1=80=D0=BE=D0=BA.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/open.c++ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/extra/open.c++ b/test/extra/open.c++ index 0722b227..d5344a11 100644 --- a/test/extra/open.c++ +++ b/test/extra/open.c++ @@ -47,7 +47,7 @@ int main(int argc, const char *argv[]) { { mdbx::env::operate_parameters operateParameters(100, 10); mdbx::env_managed::create_parameters createParameters; - createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, 2 * mdbx::env::geometry::TiB); + createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, mdbx::env::geometry::GiB); mdbx::env_managed env(path, createParameters, operateParameters); } From 9fee0bc3a6a9ff2e7ba9a749e80478a383ecc3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 1 Mar 2025 22:52:19 +0300 Subject: [PATCH 036/181] =?UTF-8?q?mdbx-tests:=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=D0=BE=D0=B9=20=D0=91=D0=94=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=20?= =?UTF-8?q?=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=D0=BC=20=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=B0=20=D0=B2=20`extra/dupfix=5Faddodd`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/dupfix_addodd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/extra/dupfix_addodd.c b/test/extra/dupfix_addodd.c index b2e6aeea..7d976f9b 100644 --- a/test/extra/dupfix_addodd.c +++ b/test/extra/dupfix_addodd.c @@ -25,6 +25,9 @@ int main() { MDBX_val key, data; MDBX_txn *txn = NULL; + const char *db_filename = "./example-db"; + mdbx_env_delete(db_filename, MDBX_ENV_JUST_DELETE); + rc = mdbx_env_create(&env); if (rc != MDBX_SUCCESS) { fprintf(stderr, "mdbx_env_create: (%d) %s\n", rc, mdbx_strerror(rc)); @@ -37,7 +40,7 @@ int main() { exit(EXIT_FAILURE); } - rc = mdbx_env_open(env, "./example-db", MDBX_NOSUBDIR | MDBX_LIFORECLAIM, 0664); + rc = mdbx_env_open(env, db_filename, MDBX_NOSUBDIR | MDBX_LIFORECLAIM, 0664); if (rc != MDBX_SUCCESS) { fprintf(stderr, "mdbx_env_open: (%d) %s\n", rc, mdbx_strerror(rc)); exit(EXIT_FAILURE); From 6ca63b46d8a648fabbd92555f973a8672468ff77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 1 Mar 2025 22:52:44 +0300 Subject: [PATCH 037/181] =?UTF-8?q?mdbx:=20=D1=83=D0=BC=D0=B5=D0=BD=D1=8C?= =?UTF-8?q?=D1=88=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=2016=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B7=20=D0=BF=D1=80=D0=B5=D0=B4=D0=BB=D0=B0=D0=B3=D0=B0=D0=B5?= =?UTF-8?q?=D0=BC=D0=BE=D0=B3=D0=BE=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=20=D0=91=D0=94=20=D0=B4=D0=BB=D1=8F=20=D1=83=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B1=D0=BB=D0=B5=D0=BC=20Valgrind/ASAN.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-env.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/api-env.c b/src/api-env.c index 9b0d7305..af3a38e3 100644 --- a/src/api-env.c +++ b/src/api-env.c @@ -11,6 +11,12 @@ __cold static intptr_t reasonable_db_maxsize(void) { /* the 32-bit limit is good enough for fallback */ return cached_result = MAX_MAPSIZE32; +#if defined(__SANITIZE_ADDRESS__) + total_ram_pages >>= 4; +#endif /* __SANITIZE_ADDRESS__ */ + if (RUNNING_ON_VALGRIND) + total_ram_pages >>= 4; + if (unlikely((size_t)total_ram_pages * 2 > MAX_MAPSIZE / (size_t)pagesize)) return cached_result = MAX_MAPSIZE; assert(MAX_MAPSIZE >= (size_t)(total_ram_pages * pagesize * 2)); From 1240ed2ba33d9a2076d5fce8ef0ac0ed0460ffb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 1 Mar 2025 22:58:12 +0300 Subject: [PATCH 038/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=BB=D0=BE?= =?UTF-8?q?=D1=88=D0=BD=D0=BE=D1=81=D1=82=D0=B8=20=D0=B2=20=D1=81=D0=BF?= =?UTF-8?q?=D0=B5=D1=86=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=86=D0=B8=D0=B8=20?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B0=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=20=D0=BB=D0=BE=D0=B3=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B8=20=D0=B8=D0=BC=D0=B5=D0=BD=20=D1=82=D0=B0=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8=D1=86.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/audit.c | 2 +- src/table.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/audit.c b/src/audit.c index bd677f91..b7304a58 100644 --- a/src/audit.c +++ b/src/audit.c @@ -78,7 +78,7 @@ __cold static int audit_ex_locked(MDBX_txn *txn, size_t retired_stored, bool don if (db) ctx.used += audit_db_used(db); else if (dbi_state(txn, dbi)) - WARNING("audit %s@%" PRIaTXN ": unable account dbi %zd / \"%*s\", state 0x%02x", txn->parent ? "nested-" : "", + WARNING("audit %s@%" PRIaTXN ": unable account dbi %zd / \"%.*s\", state 0x%02x", txn->parent ? "nested-" : "", txn->txnid, dbi, (int)env->kvs[dbi].name.iov_len, (const char *)env->kvs[dbi].name.iov_base, dbi_state(txn, dbi)); } diff --git a/src/table.c b/src/table.c index 690ab9ff..faa44da1 100644 --- a/src/table.c +++ b/src/table.c @@ -38,7 +38,7 @@ int tbl_fetch(MDBX_txn *txn, size_t dbi) { rc = tree_search(&couple.outer, &kvx->name, 0); if (unlikely(rc != MDBX_SUCCESS)) { bailout: - NOTICE("dbi %zu refs to inaccessible table `%*s` for txn %" PRIaTXN " (err %d)", dbi, (int)kvx->name.iov_len, + NOTICE("dbi %zu refs to inaccessible table `%.*s` for txn %" PRIaTXN " (err %d)", dbi, (int)kvx->name.iov_len, (const char *)kvx->name.iov_base, txn->txnid, rc); return (rc == MDBX_NOTFOUND) ? MDBX_BAD_DBI : rc; } @@ -50,7 +50,7 @@ int tbl_fetch(MDBX_txn *txn, size_t dbi) { goto bailout; } if (unlikely((node_flags(nsr.node) & (N_DUP | N_TREE)) != N_TREE)) { - NOTICE("dbi %zu refs to not a named table `%*s` for txn %" PRIaTXN " (%s)", dbi, (int)kvx->name.iov_len, + NOTICE("dbi %zu refs to not a named table `%.*s` for txn %" PRIaTXN " (%s)", dbi, (int)kvx->name.iov_len, (const char *)kvx->name.iov_base, txn->txnid, "wrong flags"); return MDBX_INCOMPATIBLE; /* not a named DB */ } @@ -60,7 +60,7 @@ int tbl_fetch(MDBX_txn *txn, size_t dbi) { return rc; if (unlikely(data.iov_len != sizeof(tree_t))) { - NOTICE("dbi %zu refs to not a named table `%*s` for txn %" PRIaTXN " (%s)", dbi, (int)kvx->name.iov_len, + NOTICE("dbi %zu refs to not a named table `%.*s` for txn %" PRIaTXN " (%s)", dbi, (int)kvx->name.iov_len, (const char *)kvx->name.iov_base, txn->txnid, "wrong rec-size"); return MDBX_INCOMPATIBLE; /* not a named DB */ } @@ -70,7 +70,7 @@ int tbl_fetch(MDBX_txn *txn, size_t dbi) { * have dropped and recreated the DB with other flags. */ tree_t *const db = &txn->dbs[dbi]; if (unlikely((db->flags & DB_PERSISTENT_FLAGS) != flags)) { - NOTICE("dbi %zu refs to the re-created table `%*s` for txn %" PRIaTXN + NOTICE("dbi %zu refs to the re-created table `%.*s` for txn %" PRIaTXN " with different flags (present 0x%X != wanna 0x%X)", dbi, (int)kvx->name.iov_len, (const char *)kvx->name.iov_base, txn->txnid, db->flags & DB_PERSISTENT_FLAGS, flags); From e035f102aba367cca23445837c923af3745b9c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 1 Mar 2025 23:11:44 +0300 Subject: [PATCH 039/181] =?UTF-8?q?mdbx:=20=D1=83=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=B1=D0=BE=D1=8F=20?= =?UTF-8?q?=D0=B0=D1=83=D0=B4=D0=B8=D1=82=D0=B0=20=D1=82=D0=B0=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8=D1=86=20=D0=BF=D1=80=D0=B8=20=D0=B8=D0=BD=D0=B2=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B4=D0=B0=D1=86=D0=B8=D0=B8=20dbi-=D1=85=D0=B5?= =?UTF-8?q?=D0=BD=D0=B4=D0=BB=D0=B0=20=D0=B2=D1=81=D0=BB=D0=B5=D0=B4=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D0=B8=D0=B5=20=D0=BE=D1=82=D0=BC=D0=B5=D0=BD=D1=8B?= =?UTF-8?q?=20=D0=B2=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=BD=D0=BE=D0=B9=20?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dbi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dbi.c b/src/dbi.c index 6176c06b..871632a8 100644 --- a/src/dbi.c +++ b/src/dbi.c @@ -677,7 +677,7 @@ __cold const tree_t *dbi_dig(const MDBX_txn *txn, const size_t dbi, tree_t *fall case DBI_OLDEN: return dig->dbs + dbi; case 0: - return nullptr; + return fallback; case DBI_VALID | DBI_STALE: case DBI_OLDEN | DBI_STALE: break; From 9273e2ee60cc53dad46ec99d23828b17ff628c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 2 Mar 2025 00:40:18 +0300 Subject: [PATCH 040/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B0=D1=81=D0=BB?= =?UTF-8?q?=D0=B5=D0=B4=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20dbi-=D1=85?= =?UTF-8?q?=D0=B5=D0=BD=D0=B4=D0=BB=D0=B0=20=D0=BE=D1=82=D0=BA=D1=80=D1=8B?= =?UTF-8?q?=D1=82=D0=BE=D0=B3=D0=BE=20=D0=B2=20=D0=B4=D0=BE=D1=87=D0=B5?= =?UTF-8?q?=D1=80=D0=BD=D0=B5=D0=B9=20=D1=82=D1=80=D0=B0=D0=BD=D0=B7=D0=B0?= =?UTF-8?q?=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B1=D0=B5=D0=B7=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D1=85.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/txn-nested.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/txn-nested.c b/src/txn-nested.c index 162c9afe..09cd87aa 100644 --- a/src/txn-nested.c +++ b/src/txn-nested.c @@ -480,18 +480,26 @@ int txn_nested_join(MDBX_txn *txn, struct commit_timestamp *ts) { eASSERT(env, dpl_check(txn)); if (txn->wr.dirtylist->length == 0 && !(txn->flags & MDBX_TXN_DIRTY) && parent->n_dbi == txn->n_dbi) { - TXN_FOREACH_DBI_ALL(txn, i) { - tASSERT(txn, (txn->dbi_state[i] & DBI_DIRTY) == 0); - if ((txn->dbi_state[i] & DBI_STALE) && !(parent->dbi_state[i] & DBI_STALE)) - tASSERT(txn, memcmp(&parent->dbs[i], &txn->dbs[i], sizeof(tree_t)) == 0); - } + VERBOSE("fast-complete pure nested txn %" PRIaTXN, txn->txnid); tASSERT(txn, memcmp(&parent->geo, &txn->geo, sizeof(parent->geo)) == 0); tASSERT(txn, memcmp(&parent->canary, &txn->canary, sizeof(parent->canary)) == 0); tASSERT(txn, !txn->wr.spilled.list || MDBX_PNL_GETSIZE(txn->wr.spilled.list) == 0); tASSERT(txn, txn->wr.loose_count == 0); - VERBOSE("fast-complete pure nested txn %" PRIaTXN, txn->txnid); + /* Update parent's DBs array */ + eASSERT(env, parent->n_dbi == txn->n_dbi); + TXN_FOREACH_DBI_ALL(txn, dbi) { + tASSERT(txn, (txn->dbi_state[dbi] & (DBI_CREAT | DBI_DIRTY)) == 0); + if (txn->dbi_state[dbi] & DBI_FRESH) { + parent->dbs[dbi] = txn->dbs[dbi]; + /* preserve parent's status */ + const uint8_t state = txn->dbi_state[dbi] | DBI_FRESH; + DEBUG("dbi %zu dbi-state %s 0x%02x -> 0x%02x", dbi, (parent->dbi_state[dbi] != state) ? "update" : "still", + parent->dbi_state[dbi], state); + parent->dbi_state[dbi] = state; + } + } return txn_end(txn, TXN_END_PURE_COMMIT | TXN_END_SLOT | TXN_END_FREE); } From bc464521c0b9a8c1f00c6ad3c1d292c8292b1eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 2 Mar 2025 00:42:55 +0300 Subject: [PATCH 041/181] =?UTF-8?q?mdbx-tests:=20=D1=80=D0=B0=D1=81=D1=88?= =?UTF-8?q?=D0=B8=D1=80=D0=B5=D0=BD=D0=B8=D0=B5=20`extra/dbi`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/dbi.c++ | 51 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/test/extra/dbi.c++ b/test/extra/dbi.c++ index 9ed37c45..fe238415 100644 --- a/test/extra/dbi.c++ +++ b/test/extra/dbi.c++ @@ -20,18 +20,53 @@ int main(int argc, const char *argv[]) { mdbx::path db_filename = "test-dbi"; mdbx::env::remove(db_filename); - mdbx::env::operate_parameters operateParameters(100, 10); + mdbx::env::operate_parameters operateParameters(100, 10, mdbx::env::nested_transactions); mdbx::env_managed::create_parameters createParameters; { - mdbx::env_managed env2(db_filename, createParameters, operateParameters); - mdbx::txn_managed txn2 = env2.start_write(false); - /* mdbx::map_handle testHandle2 = */ txn2.create_map("fap1", mdbx::key_mode::reverse, mdbx::value_mode::single); - txn2.commit(); + mdbx::env_managed env(db_filename, createParameters, operateParameters); + mdbx::txn_managed txn = env.start_write(); + /* mdbx::map_handle dbi = */ txn.create_map("fap1", mdbx::key_mode::reverse, mdbx::value_mode::single); + txn.commit(); } + mdbx::env_managed env(db_filename, createParameters, operateParameters); - mdbx::txn_managed txn = env.start_write(false); - /* mdbx::map_handle testHandle = */ txn.create_map("fap1", mdbx::key_mode::usual, mdbx::value_mode::single); - txn.commit(); + { + // проверяем доступность в родительской транзакции хендла открытого в дочерней транзакции после коммита + mdbx::txn_managed txn = env.start_write(); + mdbx::txn_managed nested = txn.start_nested(); + mdbx::map_handle dbi = nested.open_map_accede("fap1"); + nested.commit(); + MDBX_MAYBE_UNUSED auto stat = txn.get_map_stat(dbi); + txn.commit(); + env.close_map(dbi); + } + + { + // проверяем НЕ доступность в родительской транзакции хендла открытого в дочерней транзакции после прерывания + mdbx::txn_managed txn = env.start_write(); + mdbx::txn_managed nested = txn.start_nested(); + mdbx::map_handle dbi = nested.open_map_accede("fap1"); + nested.abort(); + MDBX_stat stat; + int err = mdbx_dbi_stat(txn, dbi, &stat, sizeof(stat)); + if (err != MDBX_BAD_DBI) { + std::cerr << "unexpected result err-code " << err; + return EXIT_FAILURE; + } + txn.commit(); + } + + { + // снова проверяем что таблица открывается и хендл доступень в родительской транзакции после коммита открывшей его + // дочерней + mdbx::txn_managed txn = env.start_write(); + mdbx::txn_managed nested = txn.start_nested(); + mdbx::map_handle dbi = nested.open_map_accede("fap1"); + nested.commit(); + MDBX_MAYBE_UNUSED auto stat = txn.get_map_stat(dbi); + txn.commit(); + env.close_map(dbi); + } std::cout << "OK\n"; return EXIT_SUCCESS; From fbb93f9cfb92a71419446783ab14cc7adea7a2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 2 Mar 2025 10:41:38 +0300 Subject: [PATCH 042/181] =?UTF-8?q?mdbx:=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20`const`=20=D1=83=20=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B2=20`cursor?= =?UTF-8?q?=5Fbind()`=20=D0=B8=20`cursor=5Frenew()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 6 +++--- mdbx.h++ | 8 ++++---- src/api-cursor.c | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mdbx.h b/mdbx.h index da6b47fb..db73e83e 100644 --- a/mdbx.h +++ b/mdbx.h @@ -5139,7 +5139,7 @@ MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *mdbx_cursor_get_userctx(const MDBX_ * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. * \retval MDBX_EINVAL An invalid parameter was specified. */ -LIBMDBX_API int mdbx_cursor_bind(const MDBX_txn *txn, MDBX_cursor *cursor, MDBX_dbi dbi); +LIBMDBX_API int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *cursor, MDBX_dbi dbi); /** \brief Unbind cursor from a transaction. * \ingroup c_cursors @@ -5208,7 +5208,7 @@ LIBMDBX_API int mdbx_cursor_reset(MDBX_cursor *cursor); * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. * \retval MDBX_EINVAL An invalid parameter was specified. */ -LIBMDBX_API int mdbx_cursor_open(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **cursor); +LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **cursor); /** \brief Close a cursor handle. * \ingroup c_cursors @@ -5271,7 +5271,7 @@ LIBMDBX_API int mdbx_txn_release_all_cursors(const MDBX_txn *txn, bool unbind); * \retval MDBX_EINVAL An invalid parameter was specified. * \retval MDBX_BAD_DBI The cursor was not bound to a DBI-handle * or such a handle became invalid. */ -LIBMDBX_API int mdbx_cursor_renew(const MDBX_txn *txn, MDBX_cursor *cursor); +LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor); /** \brief Return the cursor's transaction handle. * \ingroup c_cursors diff --git a/mdbx.h++ b/mdbx.h++ index 62315f61..1bd23fef 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -4474,11 +4474,11 @@ public: /// \brief Renew/bind a cursor with a new transaction and previously used /// key-value map handle. - inline void renew(const ::mdbx::txn &txn); + inline void renew(::mdbx::txn &txn); /// \brief Bind/renew a cursor with a new transaction and specified key-value /// map handle. - inline void bind(const ::mdbx::txn &txn, ::mdbx::map_handle map_handle); + inline void bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle); /// \brief Unbind cursor from a transaction. inline void unbind(); @@ -6167,9 +6167,9 @@ inline cursor::estimate_result cursor::estimate(move_operation operation) const return estimate_result(*this, operation); } -inline void cursor::renew(const ::mdbx::txn &txn) { error::success_or_throw(::mdbx_cursor_renew(txn, handle_)); } +inline void cursor::renew(::mdbx::txn &txn) { error::success_or_throw(::mdbx_cursor_renew(txn, handle_)); } -inline void cursor::bind(const ::mdbx::txn &txn, ::mdbx::map_handle map_handle) { +inline void cursor::bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle) { error::success_or_throw(::mdbx_cursor_bind(txn, handle_, map_handle.dbi)); } diff --git a/src/api-cursor.c b/src/api-cursor.c index d0b39660..324ef287 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -23,7 +23,7 @@ MDBX_cursor *mdbx_cursor_create(void *context) { return &couple->outer; } -int mdbx_cursor_renew(const MDBX_txn *txn, MDBX_cursor *mc) { +int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) { return likely(mc) ? mdbx_cursor_bind(txn, mc, (kvx_t *)mc->clc - txn->env->kvs) : LOG_IFERR(MDBX_EINVAL); } @@ -40,7 +40,7 @@ int mdbx_cursor_reset(MDBX_cursor *mc) { return MDBX_SUCCESS; } -int mdbx_cursor_bind(const MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { +int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { if (unlikely(!mc)) return LOG_IFERR(MDBX_EINVAL); @@ -88,7 +88,7 @@ int mdbx_cursor_bind(const MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { mc->next = txn->cursors[dbi]; txn->cursors[dbi] = mc; - ((MDBX_txn *)txn)->flags |= txn_may_have_cursors; + txn->flags |= txn_may_have_cursors; return MDBX_SUCCESS; } @@ -127,7 +127,7 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) { return MDBX_SUCCESS; } -int mdbx_cursor_open(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) { +int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) { if (unlikely(!ret)) return LOG_IFERR(MDBX_EINVAL); *ret = nullptr; From 28ca18972a5ee44b94df053376005fc06c8d5ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 2 Mar 2025 11:44:10 +0300 Subject: [PATCH 043/181] =?UTF-8?q?mdbx:=20=D0=B1=D0=BE=D0=BB=D0=B5=D0=B5?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=BB=D0=BD=D0=B0=D1=8F=20=D0=BE=D1=87=D0=B8?= =?UTF-8?q?=D1=81=D1=82=D0=BA=D0=B0=20=D0=BA=D1=83=D1=80=D1=81=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=BF=D1=80=D0=B8=20=D0=B7=D0=B0=D0=BA=D1=80?= =?UTF-8?q?=D1=8B=D1=82=D0=B8=D0=B8/=D0=BE=D1=82=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cursor.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api-cursor.c b/src/api-cursor.c index 324ef287..393748a8 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -122,8 +122,8 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) { } mc->next = mc; } + be_poor(mc); mc->signature = cur_signature_ready4dispose; - mc->flags = 0; return MDBX_SUCCESS; } @@ -172,6 +172,7 @@ void mdbx_cursor_close(MDBX_cursor *mc) { /* Cursor closed before nested txn ends */ tASSERT(txn, mc->signature == cur_signature_live); ENSURE(txn->env, check_txn_rw(txn, 0) == MDBX_SUCCESS); + be_poor(mc); mc->signature = cur_signature_wait4eot; } } @@ -219,8 +220,8 @@ int mdbx_txn_release_all_cursors(const MDBX_txn *txn, bool unbind) { txn->cursors[i] = mc->next; mc->next = mc; if (unbind) { + be_poor(mc); mc->signature = cur_signature_ready4dispose; - mc->flags = 0; } else { mc->signature = 0; osal_free(mc); From dd9f60832030a4b239295ffd0ebf68340637cdc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 2 Mar 2025 11:45:28 +0300 Subject: [PATCH 044/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8=20=D1=81=D0=B8=D0=B3?= =?UTF-8?q?=D0=BD=D0=B0=D1=82=D1=83=D1=80=20=D0=BA=D1=83=D1=80=D1=81=D0=BE?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=20=D0=BF=D1=80=D0=B8=20=D0=B8=D1=82=D0=B5?= =?UTF-8?q?=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D1=81=D0=B2=D1=8F=D0=B7=D0=B0?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D1=85=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cursor.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/api-cursor.c b/src/api-cursor.c index 393748a8..65e16544 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -115,8 +115,12 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) { cASSERT(mc, dbi < mc->txn->n_dbi); if (dbi < mc->txn->n_dbi) { MDBX_cursor **prev = &mc->txn->cursors[dbi]; - while (*prev && *prev != mc) + while (*prev) { + ENSURE(mc->txn->env, (*prev)->signature == cur_signature_live || (*prev)->signature == cur_signature_wait4eot); + if (*prev == mc) + break; prev = &(*prev)->next; + } cASSERT(mc, *prev == mc); *prev = mc->next; } @@ -159,8 +163,12 @@ void mdbx_cursor_close(MDBX_cursor *mc) { tASSERT(txn, dbi < txn->n_dbi); if (dbi < txn->n_dbi) { MDBX_cursor **prev = &txn->cursors[dbi]; - while (*prev && *prev != mc) + while (*prev) { + ENSURE(txn->env, (*prev)->signature == cur_signature_live || (*prev)->signature == cur_signature_wait4eot); + if (*prev == mc) + break; prev = &(*prev)->next; + } tASSERT(txn, *prev == mc); *prev = mc->next; } From c585fcd61356d0669c72c589d84f3929c7c4ab0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Feb 2025 23:48:48 +0300 Subject: [PATCH 045/181] =?UTF-8?q?mdbx-tests:=20=D1=80=D0=B0=D1=81=D1=88?= =?UTF-8?q?=D0=B8=D1=80=D0=B5=D0=BD=D0=B8=D0=B5=20`extra/open`=20(backport?= =?UTF-8?q?).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/open.c++ | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/extra/open.c++ b/test/extra/open.c++ index 55b58c8c..459ca708 100644 --- a/test/extra/open.c++ +++ b/test/extra/open.c++ @@ -44,6 +44,13 @@ int main(int argc, const char *argv[]) { txn2.commit(); } + { + mdbx::env::operate_parameters operateParameters(100, 10); + mdbx::env_managed::create_parameters createParameters; + createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, mdbx::env::geometry::GiB / 2); + mdbx::env_managed env(path, createParameters, operateParameters); + } + mdbx::env::operate_parameters operateParameters(100, 10); mdbx::env_managed::create_parameters createParameters; createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, 84 * mdbx::env::geometry::MiB); From 22c6763d57b1f045b224a2a9a7083d0db5d52f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 1 Mar 2025 22:52:19 +0300 Subject: [PATCH 046/181] =?UTF-8?q?mdbx-tests:=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=D0=BE=D0=B9=20=D0=91=D0=94=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=20?= =?UTF-8?q?=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=D0=BC=20=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=B0=20=D0=B2=20`extra/dupfix=5Faddodd`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/dupfix_addodd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/extra/dupfix_addodd.c b/test/extra/dupfix_addodd.c index b2e6aeea..7d976f9b 100644 --- a/test/extra/dupfix_addodd.c +++ b/test/extra/dupfix_addodd.c @@ -25,6 +25,9 @@ int main() { MDBX_val key, data; MDBX_txn *txn = NULL; + const char *db_filename = "./example-db"; + mdbx_env_delete(db_filename, MDBX_ENV_JUST_DELETE); + rc = mdbx_env_create(&env); if (rc != MDBX_SUCCESS) { fprintf(stderr, "mdbx_env_create: (%d) %s\n", rc, mdbx_strerror(rc)); @@ -37,7 +40,7 @@ int main() { exit(EXIT_FAILURE); } - rc = mdbx_env_open(env, "./example-db", MDBX_NOSUBDIR | MDBX_LIFORECLAIM, 0664); + rc = mdbx_env_open(env, db_filename, MDBX_NOSUBDIR | MDBX_LIFORECLAIM, 0664); if (rc != MDBX_SUCCESS) { fprintf(stderr, "mdbx_env_open: (%d) %s\n", rc, mdbx_strerror(rc)); exit(EXIT_FAILURE); From 23600241e18a8bbe202d6e93cc486925f6aebc9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 1 Mar 2025 22:52:44 +0300 Subject: [PATCH 047/181] =?UTF-8?q?mdbx:=20=D1=83=D0=BC=D0=B5=D0=BD=D1=8C?= =?UTF-8?q?=D1=88=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=2016=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B7=20=D0=BF=D1=80=D0=B5=D0=B4=D0=BB=D0=B0=D0=B3=D0=B0=D0=B5?= =?UTF-8?q?=D0=BC=D0=BE=D0=B3=D0=BE=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=20=D0=91=D0=94=20=D0=B4=D0=BB=D1=8F=20=D1=83=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B1=D0=BB=D0=B5=D0=BC=20Valgrind/ASAN=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-env.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/api-env.c b/src/api-env.c index 9a6be7b3..6a9a719b 100644 --- a/src/api-env.c +++ b/src/api-env.c @@ -11,6 +11,12 @@ __cold static intptr_t reasonable_db_maxsize(void) { /* the 32-bit limit is good enough for fallback */ return cached_result = MAX_MAPSIZE32; +#if defined(__SANITIZE_ADDRESS__) + total_ram_pages >>= 4; +#endif /* __SANITIZE_ADDRESS__ */ + if (RUNNING_ON_VALGRIND) + total_ram_pages >>= 4; + if (unlikely((size_t)total_ram_pages * 2 > MAX_MAPSIZE / (size_t)pagesize)) return cached_result = MAX_MAPSIZE; assert(MAX_MAPSIZE >= (size_t)(total_ram_pages * pagesize * 2)); From c712147eeb9c6c0017bcdac294d091f037877c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 1 Mar 2025 22:58:12 +0300 Subject: [PATCH 048/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=BB=D0=BE?= =?UTF-8?q?=D1=88=D0=BD=D0=BE=D1=81=D1=82=D0=B8=20=D0=B2=20=D1=81=D0=BF?= =?UTF-8?q?=D0=B5=D1=86=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=86=D0=B8=D0=B8=20?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B0=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=20=D0=BB=D0=BE=D0=B3=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B8=20=D0=B8=D0=BC=D0=B5=D0=BD=20=D1=82=D0=B0=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8=D1=86=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/audit.c | 2 +- src/table.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/audit.c b/src/audit.c index 094722ff..0fa86625 100644 --- a/src/audit.c +++ b/src/audit.c @@ -78,7 +78,7 @@ __cold static int audit_ex_locked(MDBX_txn *txn, size_t retired_stored, bool don if (db) ctx.used += audit_db_used(db); else if (dbi_state(txn, dbi)) - WARNING("audit %s@%" PRIaTXN ": unable account dbi %zd / \"%*s\", state 0x%02x", txn->parent ? "nested-" : "", + WARNING("audit %s@%" PRIaTXN ": unable account dbi %zd / \"%.*s\", state 0x%02x", txn->parent ? "nested-" : "", txn->txnid, dbi, (int)env->kvs[dbi].name.iov_len, (const char *)env->kvs[dbi].name.iov_base, dbi_state(txn, dbi)); } diff --git a/src/table.c b/src/table.c index 690ab9ff..faa44da1 100644 --- a/src/table.c +++ b/src/table.c @@ -38,7 +38,7 @@ int tbl_fetch(MDBX_txn *txn, size_t dbi) { rc = tree_search(&couple.outer, &kvx->name, 0); if (unlikely(rc != MDBX_SUCCESS)) { bailout: - NOTICE("dbi %zu refs to inaccessible table `%*s` for txn %" PRIaTXN " (err %d)", dbi, (int)kvx->name.iov_len, + NOTICE("dbi %zu refs to inaccessible table `%.*s` for txn %" PRIaTXN " (err %d)", dbi, (int)kvx->name.iov_len, (const char *)kvx->name.iov_base, txn->txnid, rc); return (rc == MDBX_NOTFOUND) ? MDBX_BAD_DBI : rc; } @@ -50,7 +50,7 @@ int tbl_fetch(MDBX_txn *txn, size_t dbi) { goto bailout; } if (unlikely((node_flags(nsr.node) & (N_DUP | N_TREE)) != N_TREE)) { - NOTICE("dbi %zu refs to not a named table `%*s` for txn %" PRIaTXN " (%s)", dbi, (int)kvx->name.iov_len, + NOTICE("dbi %zu refs to not a named table `%.*s` for txn %" PRIaTXN " (%s)", dbi, (int)kvx->name.iov_len, (const char *)kvx->name.iov_base, txn->txnid, "wrong flags"); return MDBX_INCOMPATIBLE; /* not a named DB */ } @@ -60,7 +60,7 @@ int tbl_fetch(MDBX_txn *txn, size_t dbi) { return rc; if (unlikely(data.iov_len != sizeof(tree_t))) { - NOTICE("dbi %zu refs to not a named table `%*s` for txn %" PRIaTXN " (%s)", dbi, (int)kvx->name.iov_len, + NOTICE("dbi %zu refs to not a named table `%.*s` for txn %" PRIaTXN " (%s)", dbi, (int)kvx->name.iov_len, (const char *)kvx->name.iov_base, txn->txnid, "wrong rec-size"); return MDBX_INCOMPATIBLE; /* not a named DB */ } @@ -70,7 +70,7 @@ int tbl_fetch(MDBX_txn *txn, size_t dbi) { * have dropped and recreated the DB with other flags. */ tree_t *const db = &txn->dbs[dbi]; if (unlikely((db->flags & DB_PERSISTENT_FLAGS) != flags)) { - NOTICE("dbi %zu refs to the re-created table `%*s` for txn %" PRIaTXN + NOTICE("dbi %zu refs to the re-created table `%.*s` for txn %" PRIaTXN " with different flags (present 0x%X != wanna 0x%X)", dbi, (int)kvx->name.iov_len, (const char *)kvx->name.iov_base, txn->txnid, db->flags & DB_PERSISTENT_FLAGS, flags); From 1ec13c63abd418f20c1584911fb7e2558caf5a9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 1 Mar 2025 23:11:44 +0300 Subject: [PATCH 049/181] =?UTF-8?q?mdbx:=20=D1=83=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=B1=D0=BE=D1=8F=20?= =?UTF-8?q?=D0=B0=D1=83=D0=B4=D0=B8=D1=82=D0=B0=20=D1=82=D0=B0=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8=D1=86=20=D0=BF=D1=80=D0=B8=20=D0=B8=D0=BD=D0=B2=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B4=D0=B0=D1=86=D0=B8=D0=B8=20dbi-=D1=85=D0=B5?= =?UTF-8?q?=D0=BD=D0=B4=D0=BB=D0=B0=20=D0=B2=D1=81=D0=BB=D0=B5=D0=B4=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D0=B8=D0=B5=20=D0=BE=D1=82=D0=BC=D0=B5=D0=BD=D1=8B?= =?UTF-8?q?=20=D0=B2=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=BD=D0=BE=D0=B9=20?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B8=20?= =?UTF-8?q?(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dbi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dbi.c b/src/dbi.c index 13d5a3eb..691911e9 100644 --- a/src/dbi.c +++ b/src/dbi.c @@ -683,7 +683,7 @@ __cold const tree_t *dbi_dig(const MDBX_txn *txn, const size_t dbi, tree_t *fall case DBI_OLDEN: return dig->dbs + dbi; case 0: - return nullptr; + return fallback; case DBI_VALID | DBI_STALE: case DBI_OLDEN | DBI_STALE: break; From 90635e72481ff0ecbee44ec6e68fcd0af42f5127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 2 Mar 2025 01:05:32 +0300 Subject: [PATCH 050/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B0=D1=81=D0=BB?= =?UTF-8?q?=D0=B5=D0=B4=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20dbi-=D1=85?= =?UTF-8?q?=D0=B5=D0=BD=D0=B4=D0=BB=D0=B0=20=D0=BE=D1=82=D0=BA=D1=80=D1=8B?= =?UTF-8?q?=D1=82=D0=BE=D0=B3=D0=BE=20=D0=B2=20=D0=B4=D0=BE=D1=87=D0=B5?= =?UTF-8?q?=D1=80=D0=BD=D0=B5=D0=B9=20=D1=82=D1=80=D0=B0=D0=BD=D0=B7=D0=B0?= =?UTF-8?q?=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B1=D0=B5=D0=B7=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D1=85.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-txn.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/api-txn.c b/src/api-txn.c index 61b994bd..1f24c930 100644 --- a/src/api-txn.c +++ b/src/api-txn.c @@ -453,20 +453,29 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) { eASSERT(env, dpl_check(txn)); if (txn->tw.dirtylist->length == 0 && !(txn->flags & MDBX_TXN_DIRTY) && parent->n_dbi == txn->n_dbi) { - TXN_FOREACH_DBI_ALL(txn, i) { - tASSERT(txn, (txn->dbi_state[i] & DBI_DIRTY) == 0); - if ((txn->dbi_state[i] & DBI_STALE) && !(parent->dbi_state[i] & DBI_STALE)) - tASSERT(txn, memcmp(&parent->dbs[i], &txn->dbs[i], sizeof(tree_t)) == 0); - } + /* fast completion of pure nested transaction */ + VERBOSE("fast-complete pure nested txn %" PRIaTXN, txn->txnid); tASSERT(txn, memcmp(&parent->geo, &txn->geo, sizeof(parent->geo)) == 0); tASSERT(txn, memcmp(&parent->canary, &txn->canary, sizeof(parent->canary)) == 0); tASSERT(txn, !txn->tw.spilled.list || MDBX_PNL_GETSIZE(txn->tw.spilled.list) == 0); tASSERT(txn, txn->tw.loose_count == 0); - /* fast completion of pure nested transaction */ - VERBOSE("fast-complete pure nested txn %" PRIaTXN, txn->txnid); - end_mode = TXN_END_PURE_COMMIT | TXN_END_SLOT | TXN_END_FREE; + /* Update parent's DBs array */ + eASSERT(env, parent->n_dbi == txn->n_dbi); + TXN_FOREACH_DBI_ALL(txn, dbi) { + tASSERT(txn, (txn->dbi_state[dbi] & (DBI_CREAT | DBI_DIRTY)) == 0); + if (txn->dbi_state[dbi] & DBI_FRESH) { + parent->dbs[dbi] = txn->dbs[dbi]; + /* preserve parent's status */ + const uint8_t state = txn->dbi_state[dbi] | DBI_FRESH; + DEBUG("dbi %zu dbi-state %s 0x%02x -> 0x%02x", dbi, (parent->dbi_state[dbi] != state) ? "update" : "still", + parent->dbi_state[dbi], state); + parent->dbi_state[dbi] = state; + } + } + txn_done_cursors(txn, true); + end_mode = TXN_END_PURE_COMMIT | TXN_END_SLOT | TXN_END_FREE | TXN_END_EOTDONE; goto done; } From 1792bdc7635116f6539cd445c5848fa5d0ca6048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 2 Mar 2025 00:42:55 +0300 Subject: [PATCH 051/181] =?UTF-8?q?mdbx-tests:=20=D1=80=D0=B0=D1=81=D1=88?= =?UTF-8?q?=D0=B8=D1=80=D0=B5=D0=BD=D0=B8=D0=B5=20`extra/dbi`=20(backport)?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/dbi.c++ | 51 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/test/extra/dbi.c++ b/test/extra/dbi.c++ index 9ed37c45..fe238415 100644 --- a/test/extra/dbi.c++ +++ b/test/extra/dbi.c++ @@ -20,18 +20,53 @@ int main(int argc, const char *argv[]) { mdbx::path db_filename = "test-dbi"; mdbx::env::remove(db_filename); - mdbx::env::operate_parameters operateParameters(100, 10); + mdbx::env::operate_parameters operateParameters(100, 10, mdbx::env::nested_transactions); mdbx::env_managed::create_parameters createParameters; { - mdbx::env_managed env2(db_filename, createParameters, operateParameters); - mdbx::txn_managed txn2 = env2.start_write(false); - /* mdbx::map_handle testHandle2 = */ txn2.create_map("fap1", mdbx::key_mode::reverse, mdbx::value_mode::single); - txn2.commit(); + mdbx::env_managed env(db_filename, createParameters, operateParameters); + mdbx::txn_managed txn = env.start_write(); + /* mdbx::map_handle dbi = */ txn.create_map("fap1", mdbx::key_mode::reverse, mdbx::value_mode::single); + txn.commit(); } + mdbx::env_managed env(db_filename, createParameters, operateParameters); - mdbx::txn_managed txn = env.start_write(false); - /* mdbx::map_handle testHandle = */ txn.create_map("fap1", mdbx::key_mode::usual, mdbx::value_mode::single); - txn.commit(); + { + // проверяем доступность в родительской транзакции хендла открытого в дочерней транзакции после коммита + mdbx::txn_managed txn = env.start_write(); + mdbx::txn_managed nested = txn.start_nested(); + mdbx::map_handle dbi = nested.open_map_accede("fap1"); + nested.commit(); + MDBX_MAYBE_UNUSED auto stat = txn.get_map_stat(dbi); + txn.commit(); + env.close_map(dbi); + } + + { + // проверяем НЕ доступность в родительской транзакции хендла открытого в дочерней транзакции после прерывания + mdbx::txn_managed txn = env.start_write(); + mdbx::txn_managed nested = txn.start_nested(); + mdbx::map_handle dbi = nested.open_map_accede("fap1"); + nested.abort(); + MDBX_stat stat; + int err = mdbx_dbi_stat(txn, dbi, &stat, sizeof(stat)); + if (err != MDBX_BAD_DBI) { + std::cerr << "unexpected result err-code " << err; + return EXIT_FAILURE; + } + txn.commit(); + } + + { + // снова проверяем что таблица открывается и хендл доступень в родительской транзакции после коммита открывшей его + // дочерней + mdbx::txn_managed txn = env.start_write(); + mdbx::txn_managed nested = txn.start_nested(); + mdbx::map_handle dbi = nested.open_map_accede("fap1"); + nested.commit(); + MDBX_MAYBE_UNUSED auto stat = txn.get_map_stat(dbi); + txn.commit(); + env.close_map(dbi); + } std::cout << "OK\n"; return EXIT_SUCCESS; From 9277daa1850ab22d933be080cf9d171617becd3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 2 Mar 2025 11:44:10 +0300 Subject: [PATCH 052/181] =?UTF-8?q?mdbx:=20=D0=B1=D0=BE=D0=BB=D0=B5=D0=B5?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=BB=D0=BD=D0=B0=D1=8F=20=D0=BE=D1=87=D0=B8?= =?UTF-8?q?=D1=81=D1=82=D0=BA=D0=B0=20=D0=BA=D1=83=D1=80=D1=81=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=BF=D1=80=D0=B8=20=D0=B7=D0=B0=D0=BA=D1=80?= =?UTF-8?q?=D1=8B=D1=82=D0=B8=D0=B8/=D0=BE=D1=82=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B8=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cursor.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api-cursor.c b/src/api-cursor.c index a10e09ef..f58d37f5 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -121,8 +121,8 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) { } mc->next = mc; } + be_poor(mc); mc->signature = cur_signature_ready4dispose; - mc->flags = 0; return MDBX_SUCCESS; } @@ -171,6 +171,7 @@ void mdbx_cursor_close(MDBX_cursor *mc) { /* Cursor closed before nested txn ends */ tASSERT(txn, mc->signature == cur_signature_live); ENSURE(txn->env, check_txn_rw(txn, 0) == MDBX_SUCCESS); + be_poor(mc); mc->signature = cur_signature_wait4eot; } } @@ -218,8 +219,8 @@ int mdbx_txn_release_all_cursors(const MDBX_txn *txn, bool unbind) { txn->cursors[i] = mc->next; mc->next = mc; if (unbind) { + be_poor(mc); mc->signature = cur_signature_ready4dispose; - mc->flags = 0; } else { mc->signature = 0; osal_free(mc); From d313008d8260302854da5c94c9ffea11a93e5e58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 2 Mar 2025 11:45:28 +0300 Subject: [PATCH 053/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8=20=D1=81=D0=B8=D0=B3?= =?UTF-8?q?=D0=BD=D0=B0=D1=82=D1=83=D1=80=20=D0=BA=D1=83=D1=80=D1=81=D0=BE?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=20=D0=BF=D1=80=D0=B8=20=D0=B8=D1=82=D0=B5?= =?UTF-8?q?=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D1=81=D0=B2=D1=8F=D0=B7=D0=B0?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D1=85=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cursor.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/api-cursor.c b/src/api-cursor.c index f58d37f5..b925ac8b 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -114,8 +114,12 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) { cASSERT(mc, dbi < mc->txn->n_dbi); if (dbi < mc->txn->n_dbi) { MDBX_cursor **prev = &mc->txn->cursors[dbi]; - while (*prev && *prev != mc) + while (*prev) { + ENSURE(mc->txn->env, (*prev)->signature == cur_signature_live || (*prev)->signature == cur_signature_wait4eot); + if (*prev == mc) + break; prev = &(*prev)->next; + } cASSERT(mc, *prev == mc); *prev = mc->next; } @@ -158,8 +162,12 @@ void mdbx_cursor_close(MDBX_cursor *mc) { tASSERT(txn, dbi < txn->n_dbi); if (dbi < txn->n_dbi) { MDBX_cursor **prev = &txn->cursors[dbi]; - while (*prev && *prev != mc) + while (*prev) { + ENSURE(txn->env, (*prev)->signature == cur_signature_live || (*prev)->signature == cur_signature_wait4eot); + if (*prev == mc) + break; prev = &(*prev)->next; + } tASSERT(txn, *prev == mc); *prev = mc->next; } From 0fa21a3c0d4408bc5390aa8e058ae56cd600cafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 2 Mar 2025 21:38:28 +0300 Subject: [PATCH 054/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=BA=D0=B0=20`env=5Fowned=5Fwrtxn()`=20=D0=B8=20?= =?UTF-8?q?=D0=BC=D0=B5=D1=81=D1=82=20=D0=B5=D1=91=20=D0=B2=D1=8B=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Цель в том чтобы избавить от коллизии блокировки возникающей внутри dxb_sanitize_tail() при использовании Valgrind/ASAN, а также упросить код. --- src/api-cold.c | 2 +- src/api-env.c | 27 ++++++++++++--------------- src/api-opts.c | 2 +- src/dxb.c | 2 +- src/env.c | 21 +++++++++++++-------- src/proto.h | 2 +- 6 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/api-cold.c b/src/api-cold.c index 1d124852..8a8c8588 100644 --- a/src/api-cold.c +++ b/src/api-cold.c @@ -342,7 +342,7 @@ __cold int mdbx_env_set_flags(MDBX_env *env, MDBX_env_flags_t flags, bool onoff) if (unlikely(env->flags & MDBX_RDONLY)) return LOG_IFERR(MDBX_EACCESS); - const bool lock_needed = (env->flags & ENV_ACTIVE) && !env_txn0_owned(env); + const bool lock_needed = (env->flags & ENV_ACTIVE) && !env_owned_wrtxn(env); bool should_unlock = false; if (lock_needed) { rc = lck_txn_lock(env, false); diff --git a/src/api-env.c b/src/api-env.c index af3a38e3..ae1324e4 100644 --- a/src/api-env.c +++ b/src/api-env.c @@ -931,8 +931,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t si if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - const bool txn0_owned = env->basal_txn && env_txn0_owned(env); - const bool inside_txn = txn0_owned && env->txn; + MDBX_txn *const txn_owned = env_owned_wrtxn(env); bool should_unlock = false; #if MDBX_DEBUG && 0 /* минимальные шаги для проверки/отладки уже не нужны */ @@ -948,7 +947,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t si if (unlikely(env->flags & MDBX_RDONLY)) return LOG_IFERR(MDBX_EACCESS); - if (!txn0_owned) { + if (!txn_owned) { int err = lck_txn_lock(env, false); if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); @@ -962,8 +961,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t si /* get untouched params from current TXN or DB */ if (pagesize <= 0 || pagesize >= INT_MAX) pagesize = env->ps; - const geo_t *const geo = - inside_txn ? &env->txn->geo : &meta_recent(env, &env->basal_txn->wr.troika).ptr_c->geometry; + const geo_t *const geo = env->txn ? &env->txn->geo : &meta_recent(env, &env->basal_txn->wr.troika).ptr_c->geometry; if (size_lower < 0) size_lower = pgno2bytes(env, geo->lower); if (size_now < 0) @@ -988,7 +986,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t si size_now = usedbytes; } else { /* env NOT yet mapped */ - if (unlikely(inside_txn)) + if (unlikely(env->txn)) return LOG_IFERR(MDBX_PANIC); /* is requested some auto-value for pagesize ? */ @@ -1177,8 +1175,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t si ENSURE(env, pagesize == (intptr_t)env->ps); meta_t meta; memset(&meta, 0, sizeof(meta)); - if (!inside_txn) { - eASSERT(env, should_unlock); + if (!env->txn) { const meta_ptr_t head = meta_recent(env, &env->basal_txn->wr.troika); uint64_t timestamp = 0; @@ -1268,7 +1265,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t si if (unlikely(rc != MDBX_SUCCESS)) goto bailout; } - if (inside_txn) { + if (env->txn) { env->txn->geo = new_geo; env->txn->flags |= MDBX_TXN_DIRTY; } else { @@ -1393,17 +1390,17 @@ __cold int mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn, MDBX_stat if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); - if (env->txn && env_txn0_owned(env)) + MDBX_txn *txn_owned = env_owned_wrtxn(env); + if (txn_owned) /* inside write-txn */ - return LOG_IFERR(stat_acc(env->txn, dest, bytes)); + return LOG_IFERR(stat_acc(txn_owned, dest, bytes)); - MDBX_txn *tmp_txn; - err = mdbx_txn_begin((MDBX_env *)env, nullptr, MDBX_TXN_RDONLY, &tmp_txn); + err = mdbx_txn_begin((MDBX_env *)env, nullptr, MDBX_TXN_RDONLY, &txn_owned); if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); - const int rc = stat_acc(tmp_txn, dest, bytes); - err = mdbx_txn_abort(tmp_txn); + const int rc = stat_acc(txn_owned, dest, bytes); + err = mdbx_txn_abort(txn_owned); if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); return LOG_IFERR(rc); diff --git a/src/api-opts.c b/src/api-opts.c index 2465864a..4f13d875 100644 --- a/src/api-opts.c +++ b/src/api-opts.c @@ -180,7 +180,7 @@ __cold int mdbx_env_set_option(MDBX_env *env, const MDBX_option_t option, uint64 if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); - const bool lock_needed = ((env->flags & ENV_ACTIVE) && env->basal_txn && !env_txn0_owned(env)); + const bool lock_needed = ((env->flags & ENV_ACTIVE) && env->basal_txn && !env_owned_wrtxn(env)); bool should_unlock = false; switch (option) { case MDBX_opt_sync_bytes: diff --git a/src/dxb.c b/src/dxb.c index f55e4b76..c2568a1c 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -368,7 +368,7 @@ void dxb_sanitize_tail(MDBX_env *env, MDBX_txn *txn) { if (env->pid != osal_getpid()) { /* resurrect after fork */ return; - } else if (env->txn && env_txn0_owned(env)) { + } else if (env_owned_wrtxn(env)) { /* inside write-txn */ last = meta_recent(env, &env->basal_txn->wr.troika).ptr_v->geometry.first_unallocated; } else if (env->flags & MDBX_RDONLY) { diff --git a/src/env.c b/src/env.c index 70d9bff4..e2540144 100644 --- a/src/env.c +++ b/src/env.c @@ -3,9 +3,14 @@ #include "internals.h" -bool env_txn0_owned(const MDBX_env *env) { - return (env->flags & MDBX_NOSTICKYTHREADS) ? (env->basal_txn->owner != 0) - : (env->basal_txn->owner == osal_thread_self()); +MDBX_txn *env_owned_wrtxn(const MDBX_env *env) { + if (likely(env->basal_txn)) { + const bool is_owned = (env->flags & MDBX_NOSTICKYTHREADS) ? (env->basal_txn->owner != 0) + : (env->basal_txn->owner == osal_thread_self()); + if (is_owned) + return env->txn ? env->txn : env->basal_txn; + } + return nullptr; } int env_page_auxbuffer(MDBX_env *env) { @@ -60,7 +65,7 @@ __cold int env_sync(MDBX_env *env, bool force, bool nonblock) { if (unlikely(env->flags & MDBX_RDONLY)) return MDBX_EACCESS; - const bool txn0_owned = env_txn0_owned(env); + MDBX_txn *const txn_owned = env_owned_wrtxn(env); bool should_unlock = false; int rc = MDBX_RESULT_TRUE /* means "nothing to sync" */; @@ -71,7 +76,7 @@ retry:; goto bailout; } - const troika_t troika = (txn0_owned | should_unlock) ? env->basal_txn->wr.troika : meta_tap(env); + const troika_t troika = (txn_owned || should_unlock) ? env->basal_txn->wr.troika : meta_tap(env); const meta_ptr_t head = meta_recent(env, &troika); const uint64_t unsynced_pages = atomic_load64(&env->lck->unsynced_pages, mo_Relaxed); if (unsynced_pages == 0) { @@ -104,7 +109,7 @@ retry:; osal_monotime() - eoos_timestamp >= autosync_period)) flags &= MDBX_WRITEMAP /* clear flags for full steady sync */; - if (!txn0_owned) { + if (!txn_owned) { if (!should_unlock) { #if MDBX_ENABLE_PGOP_STAT unsigned wops = 0; @@ -163,8 +168,8 @@ retry:; flags |= txn_shrink_allowed; } - eASSERT(env, txn0_owned || should_unlock); - eASSERT(env, !txn0_owned || (flags & txn_shrink_allowed) == 0); + eASSERT(env, txn_owned || should_unlock); + eASSERT(env, !txn_owned || (flags & txn_shrink_allowed) == 0); if (!head.is_steady && unlikely(env->stuck_meta >= 0) && troika.recent != (uint8_t)env->stuck_meta) { NOTICE("skip %s since wagering meta-page (%u) is mispatch the recent " diff --git a/src/proto.h b/src/proto.h index 01c81024..c0e46d0a 100644 --- a/src/proto.h +++ b/src/proto.h @@ -92,7 +92,7 @@ MDBX_INTERNAL int env_open(MDBX_env *env, mdbx_mode_t mode); MDBX_INTERNAL int env_info(const MDBX_env *env, const MDBX_txn *txn, MDBX_envinfo *out, size_t bytes, troika_t *troika); MDBX_INTERNAL int env_sync(MDBX_env *env, bool force, bool nonblock); MDBX_INTERNAL int env_close(MDBX_env *env, bool resurrect_after_fork); -MDBX_INTERNAL bool env_txn0_owned(const MDBX_env *env); +MDBX_INTERNAL MDBX_txn *env_owned_wrtxn(const MDBX_env *env); MDBX_INTERNAL int __must_check_result env_page_auxbuffer(MDBX_env *env); MDBX_INTERNAL unsigned env_setup_pagesize(MDBX_env *env, const size_t pagesize); From da24fda578e88184eef7d88fe36f6cd11cb3e654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 3 Mar 2025 00:22:47 +0300 Subject: [PATCH 055/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20print-=D0=BF=D0=BE=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=BD=D1=8B=D1=85=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D0=B9=20=D0=B2=20chk=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D1=81=D1=82=D0=B2=D0=B0=20=D0=BE=D1=82=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=BA=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chk.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/chk.c b/src/chk.c index d848b014..9c83795c 100644 --- a/src/chk.c +++ b/src/chk.c @@ -159,6 +159,19 @@ __cold static MDBX_chk_line_t *MDBX_PRINTF_ARGS(2, 3) chk_print(MDBX_chk_line_t return line; } +__cold MDBX_MAYBE_UNUSED static void chk_println_va(MDBX_chk_scope_t *const scope, enum MDBX_chk_severity severity, + const char *fmt, va_list args) { + chk_line_end(chk_print_va(chk_line_begin(scope, severity), fmt, args)); +} + +__cold MDBX_MAYBE_UNUSED static void chk_println(MDBX_chk_scope_t *const scope, enum MDBX_chk_severity severity, + const char *fmt, ...) { + va_list args; + va_start(args, fmt); + chk_println_va(scope, severity, fmt, args); + va_end(args); +} + __cold static MDBX_chk_line_t *chk_print_size(MDBX_chk_line_t *line, const char *prefix, const uint64_t value, const char *suffix) { static const char sf[] = "KMGTPEZY"; /* LY: Kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta! */ @@ -455,9 +468,8 @@ __cold static void chk_dispose(MDBX_chk_internal_t *chk) { chk->cb->table_dispose(chk->usr, tbl); tbl->cookie = nullptr; } - if (tbl != &chk->table_gc && tbl != &chk->table_main) { + if (tbl != &chk->table_gc && tbl != &chk->table_main) osal_free(tbl); - } } } osal_free(chk->v2a_buf.iov_base); From 826cdb708f79d4b2f683ea7ee3548c318518aa97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 3 Mar 2025 01:10:50 +0300 Subject: [PATCH 056/181] =?UTF-8?q?mdbx:=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20`log=5Ferror?= =?UTF-8?q?()`=20=D0=B4=D0=BB=D1=8F=20=D1=83=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BB=D0=BE=D0=B6=D0=BD=D1=8B=D1=85?= =?UTF-8?q?=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA=20=D0=BF=D1=80=D0=B8=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B5=20mdbx=5Fchk=20=D1=81=20?= =?UTF-8?q?=D0=B2=D1=8B=D1=81=D0=BE=D0=BA=D0=B8=D0=BC=20=D1=83=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=BD=D0=B5=D0=BC=20=D0=BB=D0=BE=D0=B3=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Некая проблема была в том, что при высоком уровне логирования в логгер также отправлялись неизбежные MDBX_NOTFOND при достижении конца интегрируемых данных. В свою очередь, chk-логика формирования отчета подсчитывала эти сообщения как ошибки при проверке БД... --- src/logging_and_debug.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/logging_and_debug.c b/src/logging_and_debug.c index e8538934..71153f1f 100644 --- a/src/logging_and_debug.c +++ b/src/logging_and_debug.c @@ -58,10 +58,11 @@ __cold void debug_log(int level, const char *function, int line, const char *fmt __cold void log_error(const int err, const char *func, unsigned line) { assert(err != MDBX_SUCCESS); - if (unlikely(globals.loglevel >= MDBX_LOG_DEBUG) && - (globals.loglevel >= MDBX_LOG_TRACE || !(err == MDBX_RESULT_TRUE || err == MDBX_NOTFOUND))) { + if (unlikely(globals.loglevel >= MDBX_LOG_DEBUG)) { + const bool is_error = err != MDBX_RESULT_TRUE && err != MDBX_NOTFOUND; char buf[256]; - debug_log(MDBX_LOG_ERROR, func, line, "error %d (%s)\n", err, mdbx_strerror_r(err, buf, sizeof(buf))); + debug_log(is_error ? MDBX_LOG_ERROR : MDBX_LOG_VERBOSE, func, line, "%s %d (%s)\n", + is_error ? "error" : "condition", err, mdbx_strerror_r(err, buf, sizeof(buf))); } } From 5e714ed946b42be7d61d847cfde3e2cf7db70164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 3 Mar 2025 01:48:36 +0300 Subject: [PATCH 057/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=BA=D0=B0=20`env=5Fowned=5Fwrtxn()`=20=D0=B8=20?= =?UTF-8?q?=D0=BC=D0=B5=D1=81=D1=82=20=D0=B5=D1=91=20=D0=B2=D1=8B=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Цель в том чтобы избавить от коллизии блокировки возникающей внутри dxb_sanitize_tail() при использовании Valgrind/ASAN, а также упросить код. --- src/api-cold.c | 2 +- src/api-env.c | 27 ++++++++++++--------------- src/api-opts.c | 2 +- src/dxb.c | 2 +- src/env.c | 21 +++++++++++++-------- src/proto.h | 2 +- 6 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/api-cold.c b/src/api-cold.c index 1d124852..8a8c8588 100644 --- a/src/api-cold.c +++ b/src/api-cold.c @@ -342,7 +342,7 @@ __cold int mdbx_env_set_flags(MDBX_env *env, MDBX_env_flags_t flags, bool onoff) if (unlikely(env->flags & MDBX_RDONLY)) return LOG_IFERR(MDBX_EACCESS); - const bool lock_needed = (env->flags & ENV_ACTIVE) && !env_txn0_owned(env); + const bool lock_needed = (env->flags & ENV_ACTIVE) && !env_owned_wrtxn(env); bool should_unlock = false; if (lock_needed) { rc = lck_txn_lock(env, false); diff --git a/src/api-env.c b/src/api-env.c index 6a9a719b..2bfbdeb2 100644 --- a/src/api-env.c +++ b/src/api-env.c @@ -958,8 +958,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t si if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - const bool txn0_owned = env->basal_txn && env_txn0_owned(env); - const bool inside_txn = txn0_owned && env->txn; + MDBX_txn *const txn_owned = env_owned_wrtxn(env); bool should_unlock = false; #if MDBX_DEBUG && 0 /* минимальные шаги для проверки/отладки уже не нужны */ @@ -975,7 +974,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t si if (unlikely(env->flags & MDBX_RDONLY)) return LOG_IFERR(MDBX_EACCESS); - if (!txn0_owned) { + if (!txn_owned) { int err = lck_txn_lock(env, false); if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); @@ -989,8 +988,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t si /* get untouched params from current TXN or DB */ if (pagesize <= 0 || pagesize >= INT_MAX) pagesize = env->ps; - const geo_t *const geo = - inside_txn ? &env->txn->geo : &meta_recent(env, &env->basal_txn->tw.troika).ptr_c->geometry; + const geo_t *const geo = env->txn ? &env->txn->geo : &meta_recent(env, &env->basal_txn->tw.troika).ptr_c->geometry; if (size_lower < 0) size_lower = pgno2bytes(env, geo->lower); if (size_now < 0) @@ -1015,7 +1013,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t si size_now = usedbytes; } else { /* env NOT yet mapped */ - if (unlikely(inside_txn)) + if (unlikely(env->txn)) return LOG_IFERR(MDBX_PANIC); /* is requested some auto-value for pagesize ? */ @@ -1204,8 +1202,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t si ENSURE(env, pagesize == (intptr_t)env->ps); meta_t meta; memset(&meta, 0, sizeof(meta)); - if (!inside_txn) { - eASSERT(env, should_unlock); + if (!env->txn) { const meta_ptr_t head = meta_recent(env, &env->basal_txn->tw.troika); uint64_t timestamp = 0; @@ -1295,7 +1292,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t si if (unlikely(rc != MDBX_SUCCESS)) goto bailout; } - if (inside_txn) { + if (env->txn) { env->txn->geo = new_geo; env->txn->flags |= MDBX_TXN_DIRTY; } else { @@ -1420,17 +1417,17 @@ __cold int mdbx_env_stat_ex(const MDBX_env *env, const MDBX_txn *txn, MDBX_stat if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); - if (env->txn && env_txn0_owned(env)) + MDBX_txn *txn_owned = env_owned_wrtxn(env); + if (txn_owned) /* inside write-txn */ - return LOG_IFERR(stat_acc(env->txn, dest, bytes)); + return LOG_IFERR(stat_acc(txn_owned, dest, bytes)); - MDBX_txn *tmp_txn; - err = mdbx_txn_begin((MDBX_env *)env, nullptr, MDBX_TXN_RDONLY, &tmp_txn); + err = mdbx_txn_begin((MDBX_env *)env, nullptr, MDBX_TXN_RDONLY, &txn_owned); if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); - const int rc = stat_acc(tmp_txn, dest, bytes); - err = mdbx_txn_abort(tmp_txn); + const int rc = stat_acc(txn_owned, dest, bytes); + err = mdbx_txn_abort(txn_owned); if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); return LOG_IFERR(rc); diff --git a/src/api-opts.c b/src/api-opts.c index 2465864a..4f13d875 100644 --- a/src/api-opts.c +++ b/src/api-opts.c @@ -180,7 +180,7 @@ __cold int mdbx_env_set_option(MDBX_env *env, const MDBX_option_t option, uint64 if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); - const bool lock_needed = ((env->flags & ENV_ACTIVE) && env->basal_txn && !env_txn0_owned(env)); + const bool lock_needed = ((env->flags & ENV_ACTIVE) && env->basal_txn && !env_owned_wrtxn(env)); bool should_unlock = false; switch (option) { case MDBX_opt_sync_bytes: diff --git a/src/dxb.c b/src/dxb.c index 22379d33..2b3cc03a 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -368,7 +368,7 @@ void dxb_sanitize_tail(MDBX_env *env, MDBX_txn *txn) { if (env->pid != osal_getpid()) { /* resurrect after fork */ return; - } else if (env->txn && env_txn0_owned(env)) { + } else if (env_owned_wrtxn(env)) { /* inside write-txn */ last = meta_recent(env, &env->basal_txn->tw.troika).ptr_v->geometry.first_unallocated; } else if (env->flags & MDBX_RDONLY) { diff --git a/src/env.c b/src/env.c index 525ed8ec..e9b33646 100644 --- a/src/env.c +++ b/src/env.c @@ -3,9 +3,14 @@ #include "internals.h" -bool env_txn0_owned(const MDBX_env *env) { - return (env->flags & MDBX_NOSTICKYTHREADS) ? (env->basal_txn->owner != 0) - : (env->basal_txn->owner == osal_thread_self()); +MDBX_txn *env_owned_wrtxn(const MDBX_env *env) { + if (likely(env->basal_txn)) { + const bool is_owned = (env->flags & MDBX_NOSTICKYTHREADS) ? (env->basal_txn->owner != 0) + : (env->basal_txn->owner == osal_thread_self()); + if (is_owned) + return env->txn ? env->txn : env->basal_txn; + } + return nullptr; } int env_page_auxbuffer(MDBX_env *env) { @@ -60,7 +65,7 @@ __cold int env_sync(MDBX_env *env, bool force, bool nonblock) { if (unlikely(env->flags & MDBX_RDONLY)) return MDBX_EACCESS; - const bool txn0_owned = env_txn0_owned(env); + MDBX_txn *const txn_owned = env_owned_wrtxn(env); bool should_unlock = false; int rc = MDBX_RESULT_TRUE /* means "nothing to sync" */; @@ -71,7 +76,7 @@ retry:; goto bailout; } - const troika_t troika = (txn0_owned | should_unlock) ? env->basal_txn->tw.troika : meta_tap(env); + const troika_t troika = (txn_owned || should_unlock) ? env->basal_txn->tw.troika : meta_tap(env); const meta_ptr_t head = meta_recent(env, &troika); const uint64_t unsynced_pages = atomic_load64(&env->lck->unsynced_pages, mo_Relaxed); if (unsynced_pages == 0) { @@ -104,7 +109,7 @@ retry:; osal_monotime() - eoos_timestamp >= autosync_period)) flags &= MDBX_WRITEMAP /* clear flags for full steady sync */; - if (!txn0_owned) { + if (!txn_owned) { if (!should_unlock) { #if MDBX_ENABLE_PGOP_STAT unsigned wops = 0; @@ -163,8 +168,8 @@ retry:; flags |= txn_shrink_allowed; } - eASSERT(env, txn0_owned || should_unlock); - eASSERT(env, !txn0_owned || (flags & txn_shrink_allowed) == 0); + eASSERT(env, txn_owned || should_unlock); + eASSERT(env, !txn_owned || (flags & txn_shrink_allowed) == 0); if (!head.is_steady && unlikely(env->stuck_meta >= 0) && troika.recent != (uint8_t)env->stuck_meta) { NOTICE("skip %s since wagering meta-page (%u) is mispatch the recent " diff --git a/src/proto.h b/src/proto.h index 842cbf62..f0a6657f 100644 --- a/src/proto.h +++ b/src/proto.h @@ -76,7 +76,7 @@ MDBX_INTERNAL int env_open(MDBX_env *env, mdbx_mode_t mode); MDBX_INTERNAL int env_info(const MDBX_env *env, const MDBX_txn *txn, MDBX_envinfo *out, size_t bytes, troika_t *troika); MDBX_INTERNAL int env_sync(MDBX_env *env, bool force, bool nonblock); MDBX_INTERNAL int env_close(MDBX_env *env, bool resurrect_after_fork); -MDBX_INTERNAL bool env_txn0_owned(const MDBX_env *env); +MDBX_INTERNAL MDBX_txn *env_owned_wrtxn(const MDBX_env *env); MDBX_INTERNAL int __must_check_result env_page_auxbuffer(MDBX_env *env); MDBX_INTERNAL unsigned env_setup_pagesize(MDBX_env *env, const size_t pagesize); From 40f655e2da0fe30c88cea04ec3c9e9fa252808fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 3 Mar 2025 01:49:32 +0300 Subject: [PATCH 058/181] =?UTF-8?q?mdbx:=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20`log=5Ferror?= =?UTF-8?q?()`=20=D0=B4=D0=BB=D1=8F=20=D1=83=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BB=D0=BE=D0=B6=D0=BD=D1=8B=D1=85?= =?UTF-8?q?=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA=20=D0=BF=D1=80=D0=B8=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B5=20mdbx=5Fchk=20=D1=81=20?= =?UTF-8?q?=D0=B2=D1=8B=D1=81=D0=BE=D0=BA=D0=B8=D0=BC=20=D1=83=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=BD=D0=B5=D0=BC=20=D0=BB=D0=BE=D0=B3=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Некая проблема была в том, что при высоком уровне логирования в логгер также отправлялись неизбежные MDBX_NOTFOND при достижении конца интегрируемых данных. В свою очередь, chk-логика формирования отчета подсчитывала эти сообщения как ошибки при проверке БД... --- src/logging_and_debug.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/logging_and_debug.c b/src/logging_and_debug.c index e8538934..71153f1f 100644 --- a/src/logging_and_debug.c +++ b/src/logging_and_debug.c @@ -58,10 +58,11 @@ __cold void debug_log(int level, const char *function, int line, const char *fmt __cold void log_error(const int err, const char *func, unsigned line) { assert(err != MDBX_SUCCESS); - if (unlikely(globals.loglevel >= MDBX_LOG_DEBUG) && - (globals.loglevel >= MDBX_LOG_TRACE || !(err == MDBX_RESULT_TRUE || err == MDBX_NOTFOUND))) { + if (unlikely(globals.loglevel >= MDBX_LOG_DEBUG)) { + const bool is_error = err != MDBX_RESULT_TRUE && err != MDBX_NOTFOUND; char buf[256]; - debug_log(MDBX_LOG_ERROR, func, line, "error %d (%s)\n", err, mdbx_strerror_r(err, buf, sizeof(buf))); + debug_log(is_error ? MDBX_LOG_ERROR : MDBX_LOG_VERBOSE, func, line, "%s %d (%s)\n", + is_error ? "error" : "condition", err, mdbx_strerror_r(err, buf, sizeof(buf))); } } From 05e7a9461961eab6bf4f7746519a6db11ecc7237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 3 Mar 2025 02:31:32 +0300 Subject: [PATCH 059/181] =?UTF-8?q?mdbx-tests:=20=D0=B8=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20extra-open=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=2032-=D0=B1=D0=B8=D1=82=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?=D1=81=D0=B1=D0=BE=D1=80=D0=BE=D0=BA=20Windows=20(=D0=91=D0=94?= =?UTF-8?q?=20=D0=B5=D1=89=D0=B5=20=D0=BC=D0=B5=D0=BD=D1=8C=D1=88=D0=B5).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/open.c++ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/extra/open.c++ b/test/extra/open.c++ index d5344a11..459ca708 100644 --- a/test/extra/open.c++ +++ b/test/extra/open.c++ @@ -47,7 +47,7 @@ int main(int argc, const char *argv[]) { { mdbx::env::operate_parameters operateParameters(100, 10); mdbx::env_managed::create_parameters createParameters; - createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, mdbx::env::geometry::GiB); + createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, mdbx::env::geometry::GiB / 2); mdbx::env_managed env(path, createParameters, operateParameters); } From 4fd165f8d2ddb7510f9e8ea27d574e2d8de84863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 3 Mar 2025 20:16:51 +0300 Subject: [PATCH 060/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index be1b644e..068aee64 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -15,6 +15,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - [Alex Sharov](https://github.com/AskAlexSharov) за сообщение об ошибках и тестирование. - [Виктору Логунову](https://t.me/vl_username) за сообщение об опечатки в имени переменной в Conan-рецепте. - [Илье Михееву](https://t.me/IlyaMkhv) за сообщение о лишнем/ненужном предупреждении несоответствия файла БД новому размеру. + - [maxc0d3r](https://gitflic.ru/user/maxc0d3r) for bug reporting and testing. Новое: @@ -43,16 +44,37 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx Ошибка присутствует в выпусках v0.13.1, v0.13.2, v0.13.3 и оставалась незамеченной из-за специфических условий и низкой вероятности проявления. Более подробная информация в описании коммита `cb8eec6d11cdab4f7d3cf87913e8009149dcf60b`. - - Устранение лишнего/ненужного предупреждения в сценарии изменения размера БД посредством вызова `mdbx_env_set_geometry()` до её открытия. + - Устранено лишнее/ненужное предупреждение в сценарии изменения размера БД посредством вызова `mdbx_env_set_geometry()` до её открытия. API предусматривает возможность запросить изменение геометрии/размера БД перед её открытием, чтобы избежать как лишних накладных расходов, так и потенциальных ошибок из-за нехватки адресного пространства. В этом сценарии ранее могло выдаваться лишнее/ненужное предупреждение о несоответствии файла БД новому размеру. Теперь этот недостаток исправлен. + - Восстановлена доступность дескрипторов таблиц, открытых в дочерней транзакции, после её фиксации, в случае отсутствия изменений в данных. + Проблема не была замечена ранее из-за специфического сценария проявления. + Ошибка присутствует в версиях 0.13.x и последующих, начиная с коммита `e6af7d7c53428ca2892bcbf7eec1c2acee06fd44` от 2023-11-05. + + - Устранён сбой аудита таблиц при инвалидации дескрипторов таблиц вследствие отмены вложенной транзакции. + Проблема не была замечена ранее из-за специфического сценария проявления. + Ошибка присутствует в версиях 0.13.x и последующих, начиная с коммита `e6af7d7c53428ca2892bcbf7eec1c2acee06fd44` от 2023-11-05. + + - Устранена причина потенциальных сбоев и/и деградации производительности в сценарии закрытия курсора до завершения вложенной транзакции, + с последующим изменением данных той-же таблицы в текущей вложенной транзакции, либо её дочерних транзакциях. + Проблема обнаружена при ручном анализе кода, сценарии воспроизведения/проявления проблемы пока не известны. + Ошибка присутствует в версиях 0.13.x и последующих, начиная с коммита `3de3d425a128a3c6f7866503f5f93b80c09dbe41` от 2024-05-19. + + - Устранена причина ложных ошибок при работе `mdbx_chk` с высоким уровнем логирования. + Проблема возникала из-за неверной трактовки `MDBX_NOTFOUND` при штатном окончании итерируемых данных. + + - Устранена причина попыток рекурсивного захвата мьютекса при работе `mdbx_chk -w` в сборах с поддержкой Valring/ASAN и под управлением этих инструментов. + Прочие доработки: - Существенный рефакторинг с реструктуризацией кода, переименованием внутренних структур, их полей и внутренних функций. - - Доработка использования LTO в CMake-сценариях: использование `-flto=auto` для GCC >= 11.4, расслабление условий для включения LTO для CLANG на Linux, расширение поиска `LLVMgold.so` в относительных lib-директориях. + - Доработка использования LTO в CMake-сценариях: использование `-flto=auto` для GCC >= 11.4, + расслабление условий для включения LTO для CLANG на Linux, расширение поиска `LLVMgold.so` в относительных lib-директориях. + + - Добавлены дополнительные проверки сигнатур курсоров при итерации связанных списков. -------------------------------------------------------------------------------- From 329eee4e4f2c4061f5d833b3b6ddf29f38dc3dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 3 Mar 2025 23:12:55 +0300 Subject: [PATCH 061/181] =?UTF-8?q?mdbx-make:=20=D0=BF=D0=BE=D0=B8=D1=81?= =?UTF-8?q?=D0=BA=20`gnu-sed`=20=D0=BD=D0=B0=20Darwin/MacOS.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GNUmakefile | 57 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index e8da9a35..a475993f 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -164,6 +164,10 @@ else $(info $(TIP) Use `make V=1` for verbose.) endif +ifeq ($(UNAME),Darwin) + $(info $(TIP) Use `brew install gnu-sed gnu-tar` and add ones to the beginning of the PATH.) +endif + all: show-options $(LIBRARIES) $(MDBX_TOOLS) help: @@ -392,6 +396,9 @@ TEST_ITER := $(shell $(uname2titer)) TEST_SRC := test/osal-$(TEST_OSAL).c++ $(filter-out $(wildcard test/osal-*.c++),$(wildcard test/*.c++)) $(call select_by,MDBX_BUILD_CXX,,src/mdbx.c++) TEST_INC := $(wildcard test/*.h++) TEST_OBJ := $(patsubst %.c++,%.o,$(TEST_SRC)) +ifndef SED +SED := $(shell which gnu-sed 2>&- || echo sed) +endif TAR ?= $(shell which gnu-tar 2>&- || echo tar) ZIP ?= $(shell which zip || echo "echo 'Please install zip'") CLANG_FORMAT ?= $(shell (which clang-format-19 || which clang-format) 2>/dev/null) @@ -408,11 +415,11 @@ MAN_SRCDIR := src/man1/ ALLOY_DEPS := $(shell git ls-files src/ | grep -e /tools -e /man -v) MDBX_GIT_DIR := $(shell if [ -d .git ]; then echo .git; elif [ -s .git -a -f .git ]; then grep '^gitdir: ' .git | cut -d ':' -f 2; else echo git_directory_is_absent; fi) MDBX_GIT_LASTVTAG := $(shell git describe --tags --dirty=-DIRTY --abbrev=0 '--match=v[0-9]*' 2>&- || echo 'Please fetch tags and/or install non-obsolete git version') -MDBX_GIT_3DOT := $(shell set -o pipefail; echo "$(MDBX_GIT_LASTVTAG)" | sed -n 's|^v*\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\(.*\)|\1|p' || echo 'Please fetch tags and/or use non-obsolete git version') +MDBX_GIT_3DOT := $(shell set -o pipefail; echo "$(MDBX_GIT_LASTVTAG)" | $(SED) -n 's|^v*\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\(.*\)|\1|p' || echo 'Please fetch tags and/or use non-obsolete git version') MDBX_GIT_TWEAK := $(shell set -o pipefail; git rev-list $(shell git describe --tags --abbrev=0 '--match=v[0-9]*')..HEAD --count 2>&- || echo 'Please fetch tags and/or use non-obsolete git version') MDBX_GIT_TIMESTAMP := $(shell git show --no-patch --format=%cI HEAD 2>&- || echo 'Please install latest get version') MDBX_GIT_DESCRIBE := $(shell git describe --tags --long --dirty '--match=v[0-9]*' 2>&- || echo 'Please fetch tags and/or install non-obsolete git version') -MDBX_GIT_PRERELEASE := $(shell echo "$(MDBX_GIT_LASTVTAG)" | sed -n 's|^v*\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\(.*\)-\([-.0-1a-zA-Z]\+\)|\3|p') +MDBX_GIT_PRERELEASE := $(shell echo "$(MDBX_GIT_LASTVTAG)" | $(SED) -n 's|^v*\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\(.*\)-\([-.0-1a-zA-Z]\+\)|\3|p') MDBX_VERSION_PURE = $(MDBX_GIT_3DOT)$(if $(filter-out 0,$(MDBX_GIT_TWEAK)),.$(MDBX_GIT_TWEAK),)$(if $(MDBX_GIT_PRERELEASE),-$(MDBX_GIT_PRERELEASE),) MDBX_VERSION_IDENT = $(shell set -o pipefail; echo -n '$(MDBX_GIT_DESCRIBE)' | tr -c -s '[a-zA-Z0-9.]' _) MDBX_VERSION_NODOT = $(subst .,_,$(MDBX_VERSION_IDENT)) @@ -552,7 +559,7 @@ $(MDBX_GIT_DIR)/HEAD $(MDBX_GIT_DIR)/index $(MDBX_GIT_DIR)/refs/tags: src/version.c: src/version.c.in $(lastword $(MAKEFILE_LIST)) $(MDBX_GIT_DIR)/HEAD $(MDBX_GIT_DIR)/index $(MDBX_GIT_DIR)/refs/tags LICENSE NOTICE @echo ' MAKE $@' - $(QUIET)sed \ + $(QUIET)$(SED) \ -e "s|@MDBX_GIT_TIMESTAMP@|$(MDBX_GIT_TIMESTAMP)|" \ -e "s|@MDBX_GIT_TREE@|$(shell git show --no-patch --format=%T HEAD || echo 'Please install latest get version')|" \ -e "s|@MDBX_GIT_COMMIT@|$(shell git show --no-patch --format=%H HEAD || echo 'Please install latest get version')|" \ @@ -586,7 +593,7 @@ mdbx-static.o: src/config.h src/version.c src/alloy.c $(ALLOY_DEPS) $(lastword $ docs/Doxyfile: docs/Doxyfile.in src/version.c $(lastword $(MAKEFILE_LIST)) @echo ' MAKE $@' - $(QUIET)sed \ + $(QUIET)$(SED) \ -e "s|@MDBX_GIT_TIMESTAMP@|$(MDBX_GIT_TIMESTAMP)|" \ -e "s|@MDBX_GIT_TREE@|$(shell git show --no-patch --format=%T HEAD || echo 'Please install latest get version')|" \ -e "s|@MDBX_GIT_COMMIT@|$(shell git show --no-patch --format=%H HEAD || echo 'Please install latest get version')|" \ @@ -602,7 +609,7 @@ docs/Doxyfile: docs/Doxyfile.in src/version.c $(lastword $(MAKEFILE_LIST)) define md-extract-section docs/__$(1).md: $(2) $(lastword $(MAKEFILE_LIST)) @echo ' EXTRACT $1' - $(QUIET)sed -n '//,//p' $(2) >$$@ && test -s $$@ + $(QUIET)$(SED) -n '//,//p' $(2) >$$@ && test -s $$@ endef $(foreach section,overview mithril characteristics improvements history usage performance bindings,$(eval $(call md-extract-section,$(section),README.md))) @@ -617,16 +624,16 @@ docs/overall.md: docs/__overview.md docs/_toc.md docs/__mithril.md docs/__histor docs/intro.md: docs/_preface.md docs/__characteristics.md docs/__improvements.md docs/_restrictions.md docs/__performance.md @echo ' MAKE $@' - $(QUIET)cat $^ | sed 's/^Performance comparison$$/Performance comparison {#performance}/;s/^Improvements beyond LMDB$$/Improvements beyond LMDB {#improvements}/' >$@ + $(QUIET)cat $^ | $(SED) 's/^Performance comparison$$/Performance comparison {#performance}/;s/^Improvements beyond LMDB$$/Improvements beyond LMDB {#improvements}/' >$@ docs/usage.md: docs/__usage.md docs/_starting.md docs/__bindings.md @echo ' MAKE $@' - $(QUIET)echo -e "\\page usage Usage\n\\section getting Building & Embedding" | cat - $^ | sed 's/^Bindings$$/Bindings {#bindings}/' >$@ + $(QUIET)echo -e "\\page usage Usage\n\\section getting Building & Embedding" | cat - $^ | $(SED) 's/^Bindings$$/Bindings {#bindings}/' >$@ doxygen: docs/Doxyfile docs/overall.md docs/intro.md docs/usage.md mdbx.h mdbx.h++ src/options.h ChangeLog.md COPYRIGHT LICENSE NOTICE docs/favicon.ico docs/manifest.webmanifest $(lastword $(MAKEFILE_LIST)) @echo ' RUNNING doxygen...' $(QUIET)rm -rf docs/html && \ - cat mdbx.h | tr '\n' '\r' | sed -e 's/LIBMDBX_INLINE_API\s*(\s*\([^,]\+\),\s*\([^,]\+\),\s*(\s*\([^)]\+\)\s*)\s*)\s*{/inline \1 \2(\3) {/g' | tr '\r' '\n' >docs/mdbx.h && \ + cat mdbx.h | tr '\n' '\r' | $(SED) -e 's/LIBMDBX_INLINE_API\s*(\s*\([^,]\+\),\s*\([^,]\+\),\s*(\s*\([^)]\+\)\s*)\s*)\s*{/inline \1 \2(\3) {/g' | tr '\r' '\n' >docs/mdbx.h && \ cp mdbx.h++ src/options.h ChangeLog.md docs/ && (cd docs && doxygen Doxyfile $(HUSH)) && cp COPYRIGHT LICENSE NOTICE docs/favicon.ico docs/manifest.webmanifest docs/html/ mdbx++-dylib.o: src/config.h src/mdbx.c++ mdbx.h mdbx.h++ $(lastword $(MAKEFILE_LIST)) @@ -650,7 +657,7 @@ release-assets: libmdbx-amalgamated-$(MDBX_GIT_3DOT).zpaq \ libmdbx-amalgamated-$(MDBX_GIT_3DOT).tar.gz \ libmdbx-amalgamated-$(subst .,_,$(MDBX_GIT_3DOT)).zip $(QUIET)([ \ - "$$(set -o pipefail; git describe | sed -n '/^v[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}$$/p' || echo fail-left)" \ + "$$(set -o pipefail; git describe | $(SED) -n '/^v[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}$$/p' || echo fail-left)" \ == \ "$$(git describe --tags --dirty=-dirty || echo fail-right)" ] \ || (echo 'ERROR: Is not a valid release because not in the clean state with a suitable annotated tag!!!' >&2 && false)) \ @@ -687,7 +694,7 @@ $(DIST_DIR)/@tmp-essentials.inc: src/version.c $(ALLOY_DEPS) $(lastword $(MAKEFI @echo ' ALLOYING...' $(QUIET)mkdir -p dist \ && (grep -v '#include ' src/alloy.c && echo '#define MDBX_BUILD_SOURCERY $(MDBX_BUILD_SOURCERY)' \ - && sed \ + && $(SED) \ -e 's|#include "../mdbx.h"|@INCLUDE "mdbx.h"|' \ -e '/#include "preface.h"/r src/preface.h' \ -e '/#include "osal.h"/r src/osal.h' \ @@ -699,14 +706,14 @@ $(DIST_DIR)/@tmp-essentials.inc: src/version.c $(ALLOY_DEPS) $(lastword $(MAKEFI -e '/#include "utils.h"/r src/utils.h' \ -e '/#include "pnl.h"/r src/pnl.h' \ src/essentials.h \ - | sed \ + | $(SED) \ -e '/#pragma once/d' -e '/#include "/d' \ -e '/ clang-format o/d' -e '/ \*INDENT-O/d' \ | grep -v '^/// ') >$@ $(DIST_DIR)/@tmp-internals.inc: $(DIST_DIR)/@tmp-essentials.inc src/version.c $(ALLOY_DEPS) $(lastword $(MAKEFILE_LIST)) $(QUIET)(cat $(DIST_DIR)/@tmp-essentials.inc \ - && sed \ + && $(SED) \ -e '/#include "essentials.h"/d' \ -e '/#include "atomics-ops.h"/r src/atomics-ops.h' \ -e '/#include "proto.h"/r src/proto.h' \ @@ -728,22 +735,22 @@ $(DIST_DIR)/@tmp-internals.inc: $(DIST_DIR)/@tmp-essentials.inc src/version.c $( -e '/#include "walk.h"/r src/walk.h' \ -e '/#include "windows-import.h"/r src/windows-import.h' \ src/internals.h \ - | sed \ + | $(SED) \ -e '/#pragma once/d' -e '/#include "/d' \ -e '/ clang-format o/d' -e '/ \*INDENT-O/d' \ | grep -v '^/// ') >$@ $(DIST_DIR)/mdbx.c: $(DIST_DIR)/@tmp-internals.inc $(lastword $(MAKEFILE_LIST)) @echo ' MAKE $@' - $(QUIET)(cat $(DIST_DIR)/@tmp-internals.inc $(shell git ls-files src/*.c | grep -v alloy) src/version.c | sed \ + $(QUIET)(cat $(DIST_DIR)/@tmp-internals.inc $(shell git ls-files src/*.c | grep -v alloy) src/version.c | $(SED) \ -e '/#include "debug_begin.h"/r src/debug_begin.h' \ -e '/#include "debug_end.h"/r src/debug_end.h' \ - ) | sed -e '/#include "/d;/#pragma once/d' -e 's|@INCLUDE|#include|' \ + ) | $(SED) -e '/#include "/d;/#pragma once/d' -e 's|@INCLUDE|#include|' \ -e '/ clang-format o/d;/ \*INDENT-O/d' -e '3i /* clang-format off */' | cat -s >$@ $(DIST_DIR)/mdbx.c++: $(DIST_DIR)/@tmp-essentials.inc src/mdbx.c++ $(lastword $(MAKEFILE_LIST)) @echo ' MAKE $@' - $(QUIET)cat $(DIST_DIR)/@tmp-essentials.inc src/mdbx.c++ | sed \ + $(QUIET)cat $(DIST_DIR)/@tmp-essentials.inc src/mdbx.c++ | $(SED) \ -e '/#define xMDBX_ALLOY/d' \ -e '/#include "/d;/#pragma once/d' \ -e 's|@INCLUDE|#include|;s|"mdbx.h"|"mdbx.h++"|' \ @@ -753,12 +760,12 @@ define dist-tool-rule $(DIST_DIR)/mdbx_$(1).c: src/tools/$(1).c src/tools/wingetopt.h src/tools/wingetopt.c \ $(DIST_DIR)/@tmp-internals.inc $(lastword $(MAKEFILE_LIST)) @echo ' MAKE $$@' - $(QUIET)mkdir -p dist && sed \ + $(QUIET)mkdir -p dist && $(SED) \ -e '/#include "essentials.h"/r $(DIST_DIR)/@tmp-essentials.inc' \ -e '/#include "wingetopt.h"/r src/tools/wingetopt.c' \ -e '/ clang-format o/d' -e '/ \*INDENT-O/d' \ src/tools/$(1).c \ - | sed -e '/#include "/d;/#pragma once/d;/#define xMDBX_ALLOY/d' -e 's|@INCLUDE|#include|' \ + | $(SED) -e '/#include "/d;/#pragma once/d;/#define xMDBX_ALLOY/d' -e 's|@INCLUDE|#include|' \ -e '/ clang-format o/d;/ \*INDENT-O/d' -e '9i /* clang-format off */' | cat -s >$$@ endef @@ -767,7 +774,7 @@ $(foreach file,$(TOOLS),$(eval $(call dist-tool-rule,$(file)))) define dist-extra-rule $(DIST_DIR)/$(1): $(1) src/version.c $(lastword $(MAKEFILE_LIST)) @echo ' REFINE $$@' - $(QUIET)mkdir -p $$(dir $$@) && sed -e '/^#> dist-cutoff-begin/,/^#< dist-cutoff-end/d' $$< | cat -s >$$@ + $(QUIET)mkdir -p $$(dir $$@) && $(SED) -e '/^#> dist-cutoff-begin/,/^#< dist-cutoff-end/d' $$< | cat -s >$$@ endef $(foreach file,mdbx.h mdbx.h++ $(filter-out man1/% VERSION.json .clang-format-ignore %.in ntdll.def,$(DIST_EXTRA)),$(eval $(call dist-extra-rule,$(file)))) @@ -816,7 +823,7 @@ cross-gcc: @echo "FOR INSTANCE: sudo apt install \$$(apt list 'g++-*' | grep 'g++-[a-z0-9]\+-linux-gnu/' | cut -f 1 -d / | sort -u)" $(QUIET)for CC in $(CROSS_LIST_NOQEMU) $(CROSS_LIST); do \ echo "===================== $$CC"; \ - $(MAKE) IOARENA=false CXXSTD= clean && CC=$$CC CXX=$$(echo $$CC | sed 's/-gcc/-g++/') EXE_LDFLAGS=-static $(MAKE) IOARENA=false all || exit $$?; \ + $(MAKE) IOARENA=false CXXSTD= clean && CC=$$CC CXX=$$(echo $$CC | $(SED) 's/-gcc/-g++/') EXE_LDFLAGS=-static $(MAKE) IOARENA=false all || exit $$?; \ done # Unfortunately qemu don't provide robust support for futexes. @@ -830,7 +837,7 @@ cross-qemu: $(QUIET)for CC in $(CROSS_LIST); do \ echo "===================== $$CC + qemu"; \ $(MAKE) IOARENA=false CXXSTD= clean && \ - CC=$$CC CXX=$$(echo $$CC | sed 's/-gcc/-g++/') EXE_LDFLAGS=-static MDBX_BUILD_OPTIONS="-DMDBX_SAFE4QEMU $(MDBX_BUILD_OPTIONS)" \ + CC=$$CC CXX=$$(echo $$CC | $(SED) 's/-gcc/-g++/') EXE_LDFLAGS=-static MDBX_BUILD_OPTIONS="-DMDBX_SAFE4QEMU $(MDBX_BUILD_OPTIONS)" \ $(MAKE) IOARENA=false smoke-singleprocess test-singleprocess || exit $$?; \ done @@ -897,13 +904,13 @@ bench-$(1)_$(2).txt: $(3) $(IOARENA) $(lastword $(MAKEFILE_LIST)) $(QUIET)(export LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}"; \ ldd $(IOARENA) | grep -i $(1) && \ $(IOARENA) -D $(1) -B batch -m $(BENCH_CRUD_MODE) -n $(2) \ - | tee $$@ | grep throughput | sed 's/throughput/batch×N/' && \ + | tee $$@ | grep throughput | $(SED) 's/throughput/batch×N/' && \ $(IOARENA) -D $(1) -B crud -m $(BENCH_CRUD_MODE) -n $(2) \ - | tee -a $$@ | grep throughput | sed 's/throughput/ crud/' && \ + | tee -a $$@ | grep throughput | $(SED) 's/throughput/ crud/' && \ $(IOARENA) -D $(1) -B iterate,get,iterate,get,iterate -m $(BENCH_CRUD_MODE) -r 4 -n $(2) \ - | tee -a $$@ | grep throughput | sed '0,/throughput/{s/throughput/iterate/};s/throughput/ get/' && \ + | tee -a $$@ | grep throughput | $(SED) '0,/throughput/{s/throughput/iterate/};s/throughput/ get/' && \ $(IOARENA) -D $(1) -B delete -m $(BENCH_CRUD_MODE) -n $(2) \ - | tee -a $$@ | grep throughput | sed 's/throughput/ delete/' && \ + | tee -a $$@ | grep throughput | $(SED) 's/throughput/ delete/' && \ true) || mv -f $$@ $$@.error endef From e0843429a191f6c2cbcf6cbc8c7bb51baf98d4d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 4 Mar 2025 00:02:39 +0300 Subject: [PATCH 062/181] =?UTF-8?q?mdbx-doc:=20=D0=B0=D0=BA=D1=82=D1=83?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B7=D0=B4=D0=B5=D0=BB=D0=B0=20MacOS=20=D0=B2=20README.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 69f67b9b..d3cd1c1b 100644 --- a/README.md +++ b/README.md @@ -651,16 +651,19 @@ error when opening the database in a _WSL1_ environment. ### MacOS Current [native build tools](https://en.wikipedia.org/wiki/Xcode) for MacOS include GNU Make, CLANG and an outdated version of Bash. -Therefore, to build the library, it is enough to run `make all` in the +However, the build script uses GNU-kind of `sed` and `tar`. +So the easiest way to install all prerequirements is to use [Homebrew](https://brew.sh/), +just by `brew install bash make cmake ninja gnu-sed gnu-tar --with-default-names`. + +Next, to build the library, it is enough to run `make all` in the directory with source code, and run `make check` to execute the base tests. If something goes wrong, it is recommended to install [Homebrew](https://brew.sh/) and try again. To run the [long stochastic test scenario](test/stochastic.sh), you will need to install the current (not outdated) version of -[Bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)). To do this, I -recommend that you install [Homebrew](https://brew.sh/) and then execute -`brew install bash`. +[Bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)). +Just install it as noted above. ### Android I recommend using CMake to build _libmdbx_ for Android. From bc2f1c59cb449040157b29ae94ff146ec3ac478f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 4 Mar 2025 01:14:03 +0300 Subject: [PATCH 063/181] =?UTF-8?q?mdbx:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index a1859394..ebc5aac8 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -12,6 +12,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - [Erigon](https://docs.erigon.tech/) за спонсорство. - [Илье Михееву](https://t.me/IlyaMkhv) за сообщение о лишнем/ненужном предупреждении несоответствия файла БД новому размеру. + - [maxc0d3r](https://gitflic.ru/user/maxc0d3r) for bug reporting and testing. Исправления: @@ -20,6 +21,25 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx так и потенциальных ошибок из-за нехватки адресного пространства. В этом сценарии ранее могло выдаваться лишнее/ненужное предупреждение о несоответствии файла БД новому размеру. Теперь этот недостаток исправлен. + - Восстановлена доступность дескрипторов таблиц, открытых в дочерней транзакции, после её фиксации, в случае отсутствия изменений в данных. + Проблема не была замечена ранее из-за специфического сценария проявления. + Ошибка присутствует в версиях 0.13.x и последующих, начиная с коммита `e6af7d7c53428ca2892bcbf7eec1c2acee06fd44` от 2023-11-05. + + - Устранён сбой аудита таблиц при инвалидации дескрипторов таблиц вследствие отмены вложенной транзакции. + Проблема не была замечена ранее из-за специфического сценария проявления. + Ошибка присутствует в версиях 0.13.x и последующих, начиная с коммита `e6af7d7c53428ca2892bcbf7eec1c2acee06fd44` от 2023-11-05. + + - Устранена причина потенциальных сбоев и/и деградации производительности в сценарии закрытия курсора до завершения вложенной транзакции, + с последующим изменением данных той-же таблицы в текущей вложенной транзакции, либо её дочерних транзакциях. + Проблема обнаружена при ручном анализе кода, сценарии воспроизведения/проявления проблемы пока не известны. + Ошибка присутствует в версиях 0.13.x и последующих, начиная с коммита `3de3d425a128a3c6f7866503f5f93b80c09dbe41` от 2024-05-19. + + - Устранена причина ложных ошибок при работе `mdbx_chk` с высоким уровнем логирования. + Проблема возникала из-за неверной трактовки `MDBX_NOTFOUND` при штатном окончании итерируемых данных. + + - Устранена причина попыток рекурсивного захвата мьютекса при работе `mdbx_chk -w` в сборах с поддержкой Valring/ASAN и под управлением этих инструментов. + + -------------------------------------------------------------------------------- From 0604accecf43ef696d5b7c7dbd2cca00304c14b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 4 Mar 2025 10:44:42 +0300 Subject: [PATCH 064/181] =?UTF-8?q?mdbx:=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=BA=D0=B0=20=D0=B2=D0=BB=D0=B0=D0=B4=D0=B5=D0=BB=D1=8C?= =?UTF-8?q?=D1=86=D0=B0=20=D0=BF=D0=BE=D1=82=D0=BE=D0=BA=D0=B0=20=D0=B2?= =?UTF-8?q?=D0=BB=D0=B0=D0=B4=D0=B5=D1=8E=D1=89=D0=B5=D0=B3=D0=BE=20=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B5=D0=B9=20?= =?UTF-8?q?=D1=82=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=BF=D1=80=D0=B8=20`MD?= =?UTF-8?q?BX=5FTXN=5FCHECKOWNER=3DON`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-env.c | 2 +- src/api-extra.c | 3 ++- src/api-txn.c | 4 ++++ test/extra/txn.c++ | 2 ++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/api-env.c b/src/api-env.c index 2bfbdeb2..bd3702e9 100644 --- a/src/api-env.c +++ b/src/api-env.c @@ -648,7 +648,7 @@ __cold int mdbx_env_close_ex(MDBX_env *env, bool dont_sync) { #endif /* Windows */ } - if (env->basal_txn && env->basal_txn->owner == osal_thread_self()) + if (env->basal_txn && (MDBX_TXN_CHECKOWNER ? env->basal_txn->owner == osal_thread_self() : !!env->basal_txn->owner)) lck_txn_unlock(env); eASSERT(env, env->signature.weak == 0); diff --git a/src/api-extra.c b/src/api-extra.c index 61b0fac9..32ad4bfd 100644 --- a/src/api-extra.c +++ b/src/api-extra.c @@ -117,7 +117,6 @@ __cold int mdbx_thread_unregister(const MDBX_env *env) { return MDBX_RESULT_TRUE /* not registered */; eASSERT(env, r->pid.weak == env->pid); - eASSERT(env, r->tid.weak == osal_thread_self()); if (unlikely(r->pid.weak != env->pid || r->tid.weak != osal_thread_self())) return LOG_IFERR(MDBX_BAD_RSLOT); @@ -154,8 +153,10 @@ int mdbx_txn_unlock(MDBX_env *env) { if (unlikely(env->flags & MDBX_RDONLY)) return LOG_IFERR(MDBX_EACCESS); +#if MDBX_TXN_CHECKOWNER if (unlikely(env->basal_txn->owner != osal_thread_self())) return LOG_IFERR(MDBX_THREAD_MISMATCH); +#endif /* MDBX_TXN_CHECKOWNER */ if (unlikely((env->basal_txn->flags & MDBX_TXN_FINISHED) == 0)) return LOG_IFERR(MDBX_BUSY); diff --git a/src/api-txn.c b/src/api-txn.c index 1f24c930..2fe01a4e 100644 --- a/src/api-txn.c +++ b/src/api-txn.c @@ -101,11 +101,13 @@ int mdbx_txn_abort(MDBX_txn *txn) { if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); +#if MDBX_TXN_CHECKOWNER if ((txn->flags & (MDBX_TXN_RDONLY | MDBX_NOSTICKYTHREADS)) == MDBX_NOSTICKYTHREADS && unlikely(txn->owner != osal_thread_self())) { mdbx_txn_break(txn); return LOG_IFERR(MDBX_THREAD_MISMATCH); } +#endif /* MDBX_TXN_CHECKOWNER */ return LOG_IFERR(txn_abort(txn)); } @@ -420,11 +422,13 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) { goto done; } +#if MDBX_TXN_CHECKOWNER if (!txn->parent && (txn->flags & MDBX_NOSTICKYTHREADS) && unlikely(txn->owner != osal_thread_self())) { txn->flags |= MDBX_TXN_ERROR; rc = MDBX_THREAD_MISMATCH; return LOG_IFERR(rc); } +#endif /* MDBX_TXN_CHECKOWNER */ if (unlikely(txn->flags & MDBX_TXN_ERROR)) { rc = MDBX_RESULT_TRUE; diff --git a/test/extra/txn.c++ b/test/extra/txn.c++ index d817cc7e..3a616015 100644 --- a/test/extra/txn.c++ +++ b/test/extra/txn.c++ @@ -131,6 +131,7 @@ int main(int argc, const char *argv[]) { std::thread t([&]() { s.wait(); +#if MDBX_TXN_CHECKOWNER err = mdbx_txn_reset(c_txn); assert(err == MDBX_THREAD_MISMATCH); ok = ok && err == MDBX_THREAD_MISMATCH; @@ -143,6 +144,7 @@ int main(int argc, const char *argv[]) { err = mdbx_txn_abort(c_txn); assert(err == MDBX_THREAD_MISMATCH); ok = ok && err == MDBX_THREAD_MISMATCH; +#endif /* MDBX_TXN_CHECKOWNER */ err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); assert(err == MDBX_BAD_TXN); ok = ok && err == MDBX_BAD_TXN; From 709d524d21abae0fbebddd52c81fb458da2745bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 4 Mar 2025 10:52:30 +0300 Subject: [PATCH 065/181] =?UTF-8?q?mdbx:=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=BA=D0=B0=20=D0=B2=D0=BB=D0=B0=D0=B4=D0=B5=D0=BB=D1=8C?= =?UTF-8?q?=D1=86=D0=B0=20=D0=BF=D0=BE=D1=82=D0=BE=D0=BA=D0=B0=20=D0=B2?= =?UTF-8?q?=D0=BB=D0=B0=D0=B4=D0=B5=D1=8E=D1=89=D0=B5=D0=B3=D0=BE=20=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B5=D0=B9=20?= =?UTF-8?q?=D1=82=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=BF=D1=80=D0=B8=20`MD?= =?UTF-8?q?BX=5FTXN=5FCHECKOWNER=3DON`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-env.c | 2 +- src/api-extra.c | 3 ++- src/api-txn.c | 4 ++++ test/extra/txn.c++ | 2 ++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/api-env.c b/src/api-env.c index ae1324e4..f56e10be 100644 --- a/src/api-env.c +++ b/src/api-env.c @@ -621,7 +621,7 @@ __cold int mdbx_env_close_ex(MDBX_env *env, bool dont_sync) { #endif /* Windows */ } - if (env->basal_txn && env->basal_txn->owner == osal_thread_self()) + if (env->basal_txn && (MDBX_TXN_CHECKOWNER ? env->basal_txn->owner == osal_thread_self() : !!env->basal_txn->owner)) lck_txn_unlock(env); eASSERT(env, env->signature.weak == 0); diff --git a/src/api-extra.c b/src/api-extra.c index 61b0fac9..32ad4bfd 100644 --- a/src/api-extra.c +++ b/src/api-extra.c @@ -117,7 +117,6 @@ __cold int mdbx_thread_unregister(const MDBX_env *env) { return MDBX_RESULT_TRUE /* not registered */; eASSERT(env, r->pid.weak == env->pid); - eASSERT(env, r->tid.weak == osal_thread_self()); if (unlikely(r->pid.weak != env->pid || r->tid.weak != osal_thread_self())) return LOG_IFERR(MDBX_BAD_RSLOT); @@ -154,8 +153,10 @@ int mdbx_txn_unlock(MDBX_env *env) { if (unlikely(env->flags & MDBX_RDONLY)) return LOG_IFERR(MDBX_EACCESS); +#if MDBX_TXN_CHECKOWNER if (unlikely(env->basal_txn->owner != osal_thread_self())) return LOG_IFERR(MDBX_THREAD_MISMATCH); +#endif /* MDBX_TXN_CHECKOWNER */ if (unlikely((env->basal_txn->flags & MDBX_TXN_FINISHED) == 0)) return LOG_IFERR(MDBX_BUSY); diff --git a/src/api-txn.c b/src/api-txn.c index 7680b610..d38c5b0e 100644 --- a/src/api-txn.c +++ b/src/api-txn.c @@ -104,11 +104,13 @@ int mdbx_txn_abort(MDBX_txn *txn) { if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); +#if MDBX_TXN_CHECKOWNER if ((txn->flags & (MDBX_TXN_RDONLY | MDBX_NOSTICKYTHREADS)) == MDBX_NOSTICKYTHREADS && unlikely(txn->owner != osal_thread_self())) { mdbx_txn_break(txn); return LOG_IFERR(MDBX_THREAD_MISMATCH); } +#endif /* MDBX_TXN_CHECKOWNER */ return LOG_IFERR(txn_abort(txn)); } @@ -363,11 +365,13 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) { goto done; } +#if MDBX_TXN_CHECKOWNER if ((txn->flags & MDBX_NOSTICKYTHREADS) && txn == env->basal_txn && unlikely(txn->owner != osal_thread_self())) { txn->flags |= MDBX_TXN_ERROR; rc = MDBX_THREAD_MISMATCH; return LOG_IFERR(rc); } +#endif /* MDBX_TXN_CHECKOWNER */ if (unlikely(txn->flags & MDBX_TXN_ERROR)) { rc = MDBX_RESULT_TRUE; diff --git a/test/extra/txn.c++ b/test/extra/txn.c++ index d817cc7e..3a616015 100644 --- a/test/extra/txn.c++ +++ b/test/extra/txn.c++ @@ -131,6 +131,7 @@ int main(int argc, const char *argv[]) { std::thread t([&]() { s.wait(); +#if MDBX_TXN_CHECKOWNER err = mdbx_txn_reset(c_txn); assert(err == MDBX_THREAD_MISMATCH); ok = ok && err == MDBX_THREAD_MISMATCH; @@ -143,6 +144,7 @@ int main(int argc, const char *argv[]) { err = mdbx_txn_abort(c_txn); assert(err == MDBX_THREAD_MISMATCH); ok = ok && err == MDBX_THREAD_MISMATCH; +#endif /* MDBX_TXN_CHECKOWNER */ err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); assert(err == MDBX_BAD_TXN); ok = ok && err == MDBX_BAD_TXN; From a3265e11dc22422392c54e7ab0aab9b03c23ec1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 4 Mar 2025 14:18:08 +0300 Subject: [PATCH 066/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=20API=20`mdbx=5Ftxn=5Fr?= =?UTF-8?q?elease=5Fall=5Fcursors=5Fex()`=20=D0=B8=20=D0=B8=D0=B7=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=B5=D0=BC=D0=B0?= =?UTF-8?q?=D0=BD=D1=82=D0=B8=D0=BA=D0=B8=20=D1=80=D0=B5=D0=B7=D1=83=D0=BB?= =?UTF-8?q?=D1=8C=D1=82=D0=B0=D1=82=D0=B0=20`mdbx=5Ftxn=5Frelease=5Fall=5F?= =?UTF-8?q?cursors()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit По недосмотру в выпусках остался предварительный/черновой вариант функции mdbx_txn_release_all_cursors(), который смешивает в возвращаемом значении информацию об ошибке/успехе и количество обработанных курсоров. За-за чего невозможно отличить одно от другого, например ошибку EPERM на Linux от одного успешно закрытого курсора. Теперь mdbx_txn_release_all_cursors() возвращает только код ошибки, а для получения кол-ва закрытых курсоров в API добавлена функция mdbx_txn_release_all_cursors_ex(). --- mdbx.h | 37 +++++++++++++++++++++++++++++++------ src/api-cursor.c | 8 +++++--- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/mdbx.h b/mdbx.h index db73e83e..dbf622a8 100644 --- a/mdbx.h +++ b/mdbx.h @@ -5235,17 +5235,42 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); * \see mdbx_cursor_unbind() * \see mdbx_cursor_close() * - * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). - * \param [in] unbind If non-zero, unbinds cursors and leaves ones reusable. - * Otherwise close and dispose cursors. + * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). + * \param [in] unbind If non-zero, unbinds cursors and leaves ones reusable. + * Otherwise close and dispose cursors. + * \param [in,out] count An optional pointer to return the number of cursors + * processed by the requested operation. * - * \returns A negative error value on failure or the number of closed cursors - * on success, some possible errors are: + * \returns A non-zero error value on failure and 0 on success, + * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. * \retval MDBX_BAD_TXN Given transaction is invalid or has * a child/nested transaction transaction. */ -LIBMDBX_API int mdbx_txn_release_all_cursors(const MDBX_txn *txn, bool unbind); +LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count); + +/** \brief Unbind or closes all cursors of a given transaction. + * \ingroup c_cursors + * + * Unbinds either closes all cursors associated (opened or renewed) with + * a given transaction in a bulk with minimal overhead. + * + * \see mdbx_cursor_unbind() + * \see mdbx_cursor_close() + * + * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). + * \param [in] unbind If non-zero, unbinds cursors and leaves ones reusable. + * Otherwise close and dispose cursors. + * + * \returns A non-zero error value on failure and 0 on success, + * some possible errors are: + * \retval MDBX_THREAD_MISMATCH Given transaction is not owned + * by current thread. + * \retval MDBX_BAD_TXN Given transaction is invalid or has + * a child/nested transaction transaction. */ +LIBMDBX_INLINE_API(int, mdbx_txn_release_all_cursors, (const MDBX_txn *txn, bool unbind)) { + return mdbx_txn_release_all_cursors_ex(txn, unbind, NULL); +} /** \brief Renew a cursor handle for use within the given transaction. * \ingroup c_cursors diff --git a/src/api-cursor.c b/src/api-cursor.c index 65e16544..4a4b34c8 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -217,14 +217,15 @@ again: return MDBX_SUCCESS; } -int mdbx_txn_release_all_cursors(const MDBX_txn *txn, bool unbind) { +int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count) { int rc = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); + size_t n = 0; if (likely(rc == MDBX_SUCCESS)) { TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) { while (txn->cursors[i]) { + ++n; MDBX_cursor *mc = txn->cursors[i]; ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup); - rc = likely(rc < INT_MAX) ? rc + 1 : rc; txn->cursors[i] = mc->next; mc->next = mc; if (unbind) { @@ -237,9 +238,10 @@ int mdbx_txn_release_all_cursors(const MDBX_txn *txn, bool unbind) { } } } else { - eASSERT(nullptr, rc < 0); LOG_IFERR(rc); } + if (count) + *count = n; return rc; } From 9c161cdafd63ca6f600f300a5a2359d800adcbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 4 Mar 2025 14:27:53 +0300 Subject: [PATCH 067/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 068aee64..54daa2d4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -30,6 +30,8 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - Поддержка MacOS universal binaries при сборке посредством CMake. + - Для закрытия или отсоединения всех курсоров с получением их количества в API добавлена функция `mdbx_txn_release_all_cursors_ex()`. + Изменение поведения: - Теперь при вставке данных в dupsort-таблицу CoW копирование целевых страниц выполняется после проверки отсутствия добавляемого значения среди уже присутствующих multi-значений (aka дубликатов). @@ -38,6 +40,9 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - Использование системного кода ошибки `EREMOTEIO` ("Remote I/O error") вместо `ENOTBLK` ("Block device required") в качестве `MDBX_EREMOTE` для индикации ошибочной ситуации открытия БД расположенной на сетевом носителе. + - Функция `dbx_txn_release_all_cursors()` возвращает только код ошибки, не смешивая его с количеством обработанных/закрытых курсоров. + Для аналогичных действий с получением количества закрытых курсоров в API добавлена функция `mdbx_txn_release_all_cursors_ex()`. + Исправления: - Устранён регресс допускающий SIGSEGV в операциях обновления после вытеснения/spilling страниц в больших транзакциях. From 94a2abaf31a293fb3eddc7fe3b61a1d846a60a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 4 Mar 2025 14:45:13 +0300 Subject: [PATCH 068/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=20API=20`mdbx=5Ftxn=5Fr?= =?UTF-8?q?elease=5Fall=5Fcursors=5Fex()`=20=D0=B8=20=D0=B8=D0=B7=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=B5=D0=BC=D0=B0?= =?UTF-8?q?=D0=BD=D1=82=D0=B8=D0=BA=D0=B8=20=D1=80=D0=B5=D0=B7=D1=83=D0=BB?= =?UTF-8?q?=D1=8C=D1=82=D0=B0=D1=82=D0=B0=20`mdbx=5Ftxn=5Frelease=5Fall=5F?= =?UTF-8?q?cursors()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit По недосмотру в выпусках остался предварительный/черновой вариант функции mdbx_txn_release_all_cursors(), который смешивает в возвращаемом значении информацию об ошибке/успехе и количество обработанных курсоров. За-за чего невозможно отличить одно от другого, например ошибку EPERM на Linux от одного успешно закрытого курсора. Теперь mdbx_txn_release_all_cursors() возвращает только код ошибки, а для получения кол-ва закрытых курсоров в API добавлена функция mdbx_txn_release_all_cursors_ex(). --- mdbx.h | 37 +++++++++++++++++++++++++++++++------ src/api-cursor.c | 8 +++++--- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/mdbx.h b/mdbx.h index a0886799..99a34f49 100644 --- a/mdbx.h +++ b/mdbx.h @@ -5227,17 +5227,42 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); * \see mdbx_cursor_unbind() * \see mdbx_cursor_close() * - * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). - * \param [in] unbind If non-zero, unbinds cursors and leaves ones reusable. - * Otherwise close and dispose cursors. + * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). + * \param [in] unbind If non-zero, unbinds cursors and leaves ones reusable. + * Otherwise close and dispose cursors. + * \param [in,out] count An optional pointer to return the number of cursors + * processed by the requested operation. * - * \returns A negative error value on failure or the number of closed cursors - * on success, some possible errors are: + * \returns A non-zero error value on failure and 0 on success, + * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. * \retval MDBX_BAD_TXN Given transaction is invalid or has * a child/nested transaction transaction. */ -LIBMDBX_API int mdbx_txn_release_all_cursors(const MDBX_txn *txn, bool unbind); +LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count); + +/** \brief Unbind or closes all cursors of a given transaction. + * \ingroup c_cursors + * + * Unbinds either closes all cursors associated (opened or renewed) with + * a given transaction in a bulk with minimal overhead. + * + * \see mdbx_cursor_unbind() + * \see mdbx_cursor_close() + * + * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). + * \param [in] unbind If non-zero, unbinds cursors and leaves ones reusable. + * Otherwise close and dispose cursors. + * + * \returns A non-zero error value on failure and 0 on success, + * some possible errors are: + * \retval MDBX_THREAD_MISMATCH Given transaction is not owned + * by current thread. + * \retval MDBX_BAD_TXN Given transaction is invalid or has + * a child/nested transaction transaction. */ +LIBMDBX_INLINE_API(int, mdbx_txn_release_all_cursors, (const MDBX_txn *txn, bool unbind)) { + return mdbx_txn_release_all_cursors_ex(txn, unbind, NULL); +} /** \brief Renew a cursor handle for use within the given transaction. * \ingroup c_cursors diff --git a/src/api-cursor.c b/src/api-cursor.c index b925ac8b..1fefaf2a 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -216,14 +216,15 @@ again: return MDBX_SUCCESS; } -int mdbx_txn_release_all_cursors(const MDBX_txn *txn, bool unbind) { +int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count) { int rc = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); + size_t n = 0; if (likely(rc == MDBX_SUCCESS)) { TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) { while (txn->cursors[i]) { + ++n; MDBX_cursor *mc = txn->cursors[i]; ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup); - rc = likely(rc < INT_MAX) ? rc + 1 : rc; txn->cursors[i] = mc->next; mc->next = mc; if (unbind) { @@ -236,9 +237,10 @@ int mdbx_txn_release_all_cursors(const MDBX_txn *txn, bool unbind) { } } } else { - eASSERT(nullptr, rc < 0); LOG_IFERR(rc); } + if (count) + *count = n; return rc; } From 7504a8f8f2179a4065c040a1f523de58d0ea8152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 4 Mar 2025 14:47:13 +0300 Subject: [PATCH 069/181] =?UTF-8?q?mdbx:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index ebc5aac8..96ae55e4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -11,7 +11,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx Благодарности: - [Erigon](https://docs.erigon.tech/) за спонсорство. - - [Илье Михееву](https://t.me/IlyaMkhv) за сообщение о лишнем/ненужном предупреждении несоответствия файла БД новому размеру. + - [Илье Михееву](https://t.me/IlyaMkhv) за сообщения о недочетах и тестирование. - [maxc0d3r](https://gitflic.ru/user/maxc0d3r) for bug reporting and testing. Исправления: @@ -39,6 +39,13 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - Устранена причина попыток рекурсивного захвата мьютекса при работе `mdbx_chk -w` в сборах с поддержкой Valring/ASAN и под управлением этих инструментов. + - Проверка владельца потока владеющего транзакцией только при `MDBX_TXN_CHECKOWNER=ON`. + +Изменение поведения: + + - Функция `dbx_txn_release_all_cursors()` возвращает только код ошибки, не смешивая его с количеством обработанных/закрытых курсоров. + Для аналогичных действий с получением количества закрытых курсоров в API добавлена функция `mdbx_txn_release_all_cursors_ex()`. + -------------------------------------------------------------------------------- From 8efcdeae9d6363eb4284b70eb356aee111da5032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 4 Mar 2025 20:06:16 +0300 Subject: [PATCH 070/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=B5=D1=87?= =?UTF-8?q?=D0=B0=D1=82=D0=BA=D0=B8=20=D0=B2=20=D0=B4=D0=B0=D1=82=D0=B5=20?= =?UTF-8?q?=D0=B2=D0=BD=D1=83=D1=82=D1=80=D0=B8=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 54daa2d4..ac60b3fa 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -85,7 +85,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx -------------------------------------------------------------------------------- -## v0.14.0 от 2023-03-13 +## v0.14.0 от 2025-01-13 Технический тэг, отмечающий начало ветки `0.14` с новым функционалом и изменением API. From 805d84480d67285a3c6e5795d13cf950e122122b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Wed, 5 Mar 2025 01:44:21 +0300 Subject: [PATCH 071/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=B5=D1=87?= =?UTF-8?q?=D0=B0=D1=82=D0=BA=D0=B8=20=D0=B2=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 96ae55e4..3d4634e3 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -43,7 +43,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx Изменение поведения: - - Функция `dbx_txn_release_all_cursors()` возвращает только код ошибки, не смешивая его с количеством обработанных/закрытых курсоров. + - Функция `mdbx_txn_release_all_cursors()` возвращает только код ошибки, не смешивая его с количеством обработанных/закрытых курсоров. Для аналогичных действий с получением количества закрытых курсоров в API добавлена функция `mdbx_txn_release_all_cursors_ex()`. From 283c962fea272cee4d18717433aab313d89d0110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Wed, 5 Mar 2025 01:46:57 +0300 Subject: [PATCH 072/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=B5=D1=87?= =?UTF-8?q?=D0=B0=D1=82=D0=BA=D0=B8=20=D0=B2=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index ac60b3fa..02007336 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -40,7 +40,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - Использование системного кода ошибки `EREMOTEIO` ("Remote I/O error") вместо `ENOTBLK` ("Block device required") в качестве `MDBX_EREMOTE` для индикации ошибочной ситуации открытия БД расположенной на сетевом носителе. - - Функция `dbx_txn_release_all_cursors()` возвращает только код ошибки, не смешивая его с количеством обработанных/закрытых курсоров. + - Функция `mdbx_txn_release_all_cursors()` возвращает только код ошибки, не смешивая его с количеством обработанных/закрытых курсоров. Для аналогичных действий с получением количества закрытых курсоров в API добавлена функция `mdbx_txn_release_all_cursors_ex()`. Исправления: From 920d9b5b2f0b7b580ed3c11258af430cd05cdc63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Wed, 5 Mar 2025 12:54:51 +0300 Subject: [PATCH 073/181] =?UTF-8?q?mdbx-doc:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`ld+json`=20=D0=B2=20?= =?UTF-8?q?=D0=BA=D0=BE=D1=80=D0=BD=D0=B5=D0=B2=D0=BE=D0=B9=20index.hml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GNUmakefile | 5 +++-- docs/ld+json | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 docs/ld+json diff --git a/GNUmakefile b/GNUmakefile index a475993f..14d35430 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -630,11 +630,12 @@ docs/usage.md: docs/__usage.md docs/_starting.md docs/__bindings.md @echo ' MAKE $@' $(QUIET)echo -e "\\page usage Usage\n\\section getting Building & Embedding" | cat - $^ | $(SED) 's/^Bindings$$/Bindings {#bindings}/' >$@ -doxygen: docs/Doxyfile docs/overall.md docs/intro.md docs/usage.md mdbx.h mdbx.h++ src/options.h ChangeLog.md COPYRIGHT LICENSE NOTICE docs/favicon.ico docs/manifest.webmanifest $(lastword $(MAKEFILE_LIST)) +doxygen: docs/Doxyfile docs/overall.md docs/intro.md docs/usage.md mdbx.h mdbx.h++ src/options.h ChangeLog.md COPYRIGHT LICENSE NOTICE docs/favicon.ico docs/manifest.webmanifest docs/ld+json $(lastword $(MAKEFILE_LIST)) @echo ' RUNNING doxygen...' $(QUIET)rm -rf docs/html && \ cat mdbx.h | tr '\n' '\r' | $(SED) -e 's/LIBMDBX_INLINE_API\s*(\s*\([^,]\+\),\s*\([^,]\+\),\s*(\s*\([^)]\+\)\s*)\s*)\s*{/inline \1 \2(\3) {/g' | tr '\r' '\n' >docs/mdbx.h && \ - cp mdbx.h++ src/options.h ChangeLog.md docs/ && (cd docs && doxygen Doxyfile $(HUSH)) && cp COPYRIGHT LICENSE NOTICE docs/favicon.ico docs/manifest.webmanifest docs/html/ + cp mdbx.h++ src/options.h ChangeLog.md docs/ && (cd docs && doxygen Doxyfile $(HUSH)) && cp COPYRIGHT LICENSE NOTICE docs/favicon.ico docs/manifest.webmanifest docs/html/ && \ + $(SED) -i docs/html/index.html -e '/\/MathJax.js"><\/script>/r docs/ld+json' mdbx++-dylib.o: src/config.h src/mdbx.c++ mdbx.h mdbx.h++ $(lastword $(MAKEFILE_LIST)) @echo ' CC $@' diff --git a/docs/ld+json b/docs/ld+json new file mode 100644 index 00000000..790e4475 --- /dev/null +++ b/docs/ld+json @@ -0,0 +1,27 @@ + From 183610b0503e28007d6a548034e6126caa2c6750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 9 Mar 2025 11:41:02 +0300 Subject: [PATCH 074/181] =?UTF-8?q?mdbx-doc:=20=D0=B8=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20url=20=D0=B2=20sit?= =?UTF-8?q?emap.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Doxyfile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 329d9d4c..233d67ca 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -1640,7 +1640,7 @@ TOC_EXPAND = NO # protocol see https://www.sitemaps.org # This tag requires that the tag GENERATE_HTML is set to YES. -SITEMAP_URL = https://libmdbx.dqdkfa.ru/sitemap.xml +SITEMAP_URL = https://libmdbx.dqdkfa.ru # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that From 642474763645f035668ce62a4de9d254cfbf9494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 6 Mar 2025 22:31:38 +0300 Subject: [PATCH 075/181] =?UTF-8?q?mdbx++:=20=D0=B8=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20`mdbx?= =?UTF-8?q?=5Ftxn=5Frelease=5Fall=5Fcursors=5Fex()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mdbx.h++ b/mdbx.h++ index 1bd23fef..e993f17f 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -5604,10 +5604,9 @@ inline cursor_managed txn::open_cursor(map_handle map) const { } inline size_t txn::release_all_cursors(bool unbind) const { - int err = ::mdbx_txn_release_all_cursors(handle_, unbind); - if (MDBX_UNLIKELY(err < 0)) - MDBX_CXX20_UNLIKELY error::throw_exception(err); - return size_t(err); + size_t count; + error::success_or_throw(::mdbx_txn_release_all_cursors_ex(handle_, unbind, &count)); + return count; } inline ::mdbx::map_handle txn::open_map(const ::mdbx::slice &name, const ::mdbx::key_mode key_mode, From ca30365d3b9595bc88387b516c314550b766f4b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 6 Mar 2025 20:54:37 +0300 Subject: [PATCH 076/181] =?UTF-8?q?mdbx-make:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=86=D0=B5=D0=BB=D0=B8?= =?UTF-8?q?=20`ninja-assertions`=20=D0=B8=20=D0=B5=D1=91=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BF=D1=80=D0=B8=20`make=20check`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GNUmakefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 14d35430..46e0d5f7 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -299,6 +299,10 @@ lib-shared libmdbx.$(SO_SUFFIX): mdbx-dylib.o $(call select_by,MDBX_BUILD_CXX,md @echo ' LD $@' $(QUIET)$(call select_by,MDBX_BUILD_CXX,$(CXX) $(CXXFLAGS),$(CC) $(CFLAGS)) $^ -pthread -shared $(LDFLAGS) $(call select_by,MDBX_BUILD_CXX,$(LIB_STDCXXFS)) $(LIBS) -o $@ +ninja-assertions: CMAKE_OPT += -DMDBX_FORCE_ASSERTIONS=ON +ninja-assertions: cmake-build +ninja-debug: CMAKE_OPT += -DCMAKE_BUILD_TYPE=Debug +ninja-debug: cmake-build ninja: cmake-build cmake-build: @echo " RUN: cmake -G Ninja && cmake --build" @@ -431,7 +435,7 @@ MDBX_SMOKE_EXTRA ?= check: DESTDIR = $(shell pwd)/@check-install check: CMAKE_OPT = -Werror=dev -check: smoke-assertion ninja dist install test ctest +check: smoke-assertion ninja-assertions dist install test ctest smoke-assertion: MDBX_BUILD_OPTIONS:=$(strip $(MDBX_BUILD_OPTIONS) -DMDBX_FORCE_ASSERTIONS=1 -UNDEBUG -DMDBX_DEBUG=0) smoke-assertion: smoke @@ -668,7 +672,7 @@ release-assets: libmdbx-amalgamated-$(MDBX_GIT_3DOT).zpaq \ @echo -n ' VERIFY amalgamated sources...' $(QUIET)rm -rf $@ $(DIST_DIR)/@tmp-essentials.inc $(DIST_DIR)/@tmp-internals.inc \ && if grep -R "define xMDBX_ALLOY" dist | grep -q MDBX_BUILD_SOURCERY; then echo "sed output is WRONG!" >&2; exit 2; fi \ - && rm -rf @dist-check && cp -r -p $(DIST_DIR) @dist-check && ($(MAKE) -j IOARENA=false CXXSTD=$(CXXSTD) -C @dist-check all ninja >@dist-check.log 2>@dist-check.err || (cat @dist-check.err && exit 1)) \ + && rm -rf @dist-check && cp -r -p $(DIST_DIR) @dist-check && ($(MAKE) -j IOARENA=false CXXSTD=$(CXXSTD) -C @dist-check all ninja-assertions >@dist-check.log 2>@dist-check.err || (cat @dist-check.err && exit 1)) \ && touch $@ || (echo " FAILED! See @dist-check.log and @dist-check.err" >&2; exit 2) && echo " Ok" %.tar.gz: @dist-checked.tag From 4fcfb07b97863bb2e3b95a1b3bad2f27a220a9df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 6 Mar 2025 20:57:19 +0300 Subject: [PATCH 077/181] =?UTF-8?q?mdbx:=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20`mdbx=5Fpani?= =?UTF-8?q?c()`=20=D0=B4=D0=BB=D1=8F=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B0=D0=BD=D0=BD=D0=BE?= =?UTF-8?q?=D0=B3=D0=BE=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20`=5F=5Fassert=5Ffaile?= =?UTF-8?q?d()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/osal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/osal.c b/src/osal.c index ec2e0d7c..d7500142 100644 --- a/src/osal.c +++ b/src/osal.c @@ -248,7 +248,7 @@ __cold void mdbx_panic(const char *fmt, ...) { unlikely(num < 1 || !message) ? "" : message; if (globals.logger.ptr) - debug_log(MDBX_LOG_FATAL, "panic", 0, "%s", const_message); + debug_log(MDBX_LOG_FATAL, "mdbx-panic", 0, "%s", const_message); while (1) { #if defined(_WIN32) || defined(_WIN64) @@ -262,7 +262,7 @@ __cold void mdbx_panic(const char *fmt, ...) { #endif FatalExit(ERROR_UNHANDLED_ERROR); #else - __assert_fail(const_message, "mdbx", 0, "panic"); + __assert_fail(const_message, "mdbx-panic", 0, const_message); abort(); #endif } From b0665f7016306e658235703d15b454fcef7e6d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 6 Mar 2025 02:48:55 +0300 Subject: [PATCH 078/181] =?UTF-8?q?mdbx:=20=D0=B7=D0=B0=D0=BF=D1=80=D0=B5?= =?UTF-8?q?=D1=89=D0=B5=D0=BD=D0=B8=D0=B5=20unbind/close=20=D0=BA=D1=83?= =?UTF-8?q?=D1=80=D1=81=D0=BE=D1=80=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=B2=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=BD=D1=8B=D1=85=20=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 20 ++++++++++-- src/api-cursor.c | 79 +++++++++++++++++++++--------------------------- 2 files changed, 53 insertions(+), 46 deletions(-) diff --git a/mdbx.h b/mdbx.h index dbf622a8..e971ade5 100644 --- a/mdbx.h +++ b/mdbx.h @@ -5124,6 +5124,10 @@ MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *mdbx_cursor_get_userctx(const MDBX_ * the same table handle as it was created with. This may be done whether the * previous transaction is live or dead. * + * If the transaction is nested, then the cursor should not be used in its parent transaction. + * Otherwise it is no way to restore state if this nested transaction will be aborted, + * nor impossible to define the expected behavior. + * * \note In contrast to LMDB, the MDBX required that any opened cursors can be * reused and must be freed explicitly, regardless ones was opened in a * read-only or write transaction. The REASON for this is eliminates ambiguity @@ -5148,6 +5152,10 @@ LIBMDBX_API int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *cursor, MDBX_dbi db * the original DBI-handle internally. Thus it could be renewed with any running * transaction or closed. * + * If the transaction is nested, then the cursor should not be used in its parent transaction. + * Otherwise it is no way to restore state if this nested transaction will be aborted, + * nor impossible to define the expected behavior. + * * \see mdbx_cursor_renew() * \see mdbx_cursor_bind() * \see mdbx_cursor_close() @@ -5232,6 +5240,10 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); * Unbinds either closes all cursors associated (opened or renewed) with * a given transaction in a bulk with minimal overhead. * + * A transaction should not be nested, since in this case no way to restore + * state if this nested transaction will be aborted, nor impossible to define + * the expected behavior. + * * \see mdbx_cursor_unbind() * \see mdbx_cursor_close() * @@ -5245,7 +5257,7 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. - * \retval MDBX_BAD_TXN Given transaction is invalid or has + * \retval MDBX_BAD_TXN Given transaction is invalid, nested or has * a child/nested transaction transaction. */ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count); @@ -5255,6 +5267,10 @@ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind * Unbinds either closes all cursors associated (opened or renewed) with * a given transaction in a bulk with minimal overhead. * + * A transaction should not be nested, since in this case no way to restore + * state if this nested transaction will be aborted, nor impossible to define + * the expected behavior. + * * \see mdbx_cursor_unbind() * \see mdbx_cursor_close() * @@ -5266,7 +5282,7 @@ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. - * \retval MDBX_BAD_TXN Given transaction is invalid or has + * \retval MDBX_BAD_TXN Given transaction is invalid, nested or has * a child/nested transaction transaction. */ LIBMDBX_INLINE_API(int, mdbx_txn_release_all_cursors, (const MDBX_txn *txn, bool unbind)) { return mdbx_txn_release_all_cursors_ex(txn, unbind, NULL); diff --git a/src/api-cursor.c b/src/api-cursor.c index 4a4b34c8..05c98b4b 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -44,8 +44,10 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { if (unlikely(!mc)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(mc->signature != cur_signature_ready4dispose && mc->signature != cur_signature_live)) - return LOG_IFERR(MDBX_EBADSIGN); + if (unlikely(mc->signature != cur_signature_ready4dispose && mc->signature != cur_signature_live)) { + int rc = (mc->signature == cur_signature_wait4eot) ? MDBX_EINVAL : MDBX_EBADSIGN; + return LOG_IFERR(rc); + } int rc = check_txn(txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) @@ -58,24 +60,12 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { if (unlikely(dbi == FREE_DBI && !(txn->flags & MDBX_TXN_RDONLY))) return LOG_IFERR(MDBX_EACCESS); - if (unlikely(mc->backup)) /* Cursor from parent transaction */ { - cASSERT(mc, mc->signature == cur_signature_live); - if (unlikely(cursor_dbi(mc) != dbi || - /* paranoia */ mc->signature != cur_signature_live || mc->txn != txn)) - return LOG_IFERR(MDBX_EINVAL); - - cASSERT(mc, mc->tree == &txn->dbs[dbi]); - cASSERT(mc, mc->clc == &txn->env->kvs[dbi].clc); - cASSERT(mc, cursor_dbi(mc) == dbi); - return likely(cursor_dbi(mc) == dbi && - /* paranoia */ mc->signature == cur_signature_live && mc->txn == txn) - ? MDBX_SUCCESS - : LOG_IFERR(MDBX_EINVAL) /* Disallow change DBI in nested - transactions */ - ; - } + if (unlikely(mc->backup)) /* Cursor from parent transaction */ + LOG_IFERR(MDBX_EINVAL); if (mc->signature == cur_signature_live) { + if (mc->txn == txn && cursor_dbi(mc) == dbi) + return MDBX_SUCCESS; rc = mdbx_cursor_unbind(mc); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -100,25 +90,22 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) { return (mc->signature == cur_signature_ready4dispose) ? MDBX_SUCCESS : LOG_IFERR(MDBX_EBADSIGN); if (unlikely(mc->backup)) /* Cursor from parent transaction */ + /* TODO: реализовать при переходе на двусвязный список курсоров */ return LOG_IFERR(MDBX_EINVAL); - eASSERT(nullptr, mc->txn && mc->txn->signature == txn_signature); - cASSERT(mc, mc->signature == cur_signature_live); - cASSERT(mc, !mc->backup); if (unlikely(!mc->txn || mc->txn->signature != txn_signature)) { ERROR("Wrong cursor's transaction %p 0x%x", __Wpedantic_format_voidptr(mc->txn), mc->txn ? mc->txn->signature : 0); return LOG_IFERR(MDBX_PROBLEM); } + if (mc->next != mc) { - const size_t dbi = (kvx_t *)mc->clc - mc->txn->env->kvs; - cASSERT(mc, cursor_dbi(mc) == dbi); + const size_t dbi = cursor_dbi(mc); cASSERT(mc, dbi < mc->txn->n_dbi); + cASSERT(mc, &mc->txn->env->kvs[dbi].clc == mc->clc); if (dbi < mc->txn->n_dbi) { MDBX_cursor **prev = &mc->txn->cursors[dbi]; - while (*prev) { + while (/* *prev && */ *prev != mc) { ENSURE(mc->txn->env, (*prev)->signature == cur_signature_live || (*prev)->signature == cur_signature_wait4eot); - if (*prev == mc) - break; prev = &(*prev)->next; } cASSERT(mc, *prev == mc); @@ -219,30 +206,34 @@ again: int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count) { int rc = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + if (unlikely(txn->parent)) { + rc = MDBX_BAD_TXN; + ERROR("%s, err %d", "must not unbind or close cursors for a nested txn", rc); + return rc; + } + size_t n = 0; - if (likely(rc == MDBX_SUCCESS)) { - TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) { - while (txn->cursors[i]) { - ++n; - MDBX_cursor *mc = txn->cursors[i]; - ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup); - txn->cursors[i] = mc->next; - mc->next = mc; - if (unbind) { - be_poor(mc); - mc->signature = cur_signature_ready4dispose; - } else { - mc->signature = 0; - osal_free(mc); - } + TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) { + while (txn->cursors[i]) { + ++n; + MDBX_cursor *mc = txn->cursors[i]; + ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup); + txn->cursors[i] = mc->next; + mc->next = mc; + if (unbind) { + be_poor(mc); + mc->signature = cur_signature_ready4dispose; + } else { + mc->signature = 0; + osal_free(mc); } } - } else { - LOG_IFERR(rc); } if (count) *count = n; - return rc; + return MDBX_SUCCESS; } int mdbx_cursor_compare(const MDBX_cursor *l, const MDBX_cursor *r, bool ignore_multival) { From 436998ca83768d690e6bc1fa0c322cd8b828bf38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 6 Mar 2025 10:27:34 +0300 Subject: [PATCH 079/181] =?UTF-8?q?mdbx:=20=D0=BA=D0=BE=D1=81=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D0=B9=20=D1=80=D0=B5?= =?UTF-8?q?=D1=84=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20`curso?= =?UTF-8?q?r=5Fshadow()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cursor.c | 18 +++++++++--------- src/cursor.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cursor.c b/src/cursor.c index 766943f7..b0857e73 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -184,12 +184,12 @@ __hot int cursor_touch(MDBX_cursor *const mc, const MDBX_val *key, const MDBX_va /*----------------------------------------------------------------------------*/ -int cursor_shadow(MDBX_cursor *cursor, MDBX_txn *nested_txn, const size_t dbi) { - tASSERT(nested_txn, cursor->signature == cur_signature_live); - tASSERT(nested_txn, cursor->txn != nested_txn); +int cursor_shadow(MDBX_cursor *cursor, MDBX_txn *nested, const size_t dbi) { + tASSERT(nested, cursor->signature == cur_signature_live); + tASSERT(nested, cursor->txn != nested); cASSERT(cursor, cursor->txn->flags & txn_may_have_cursors); cASSERT(cursor, dbi == cursor_dbi(cursor)); - tASSERT(nested_txn, dbi > FREE_DBI && dbi < nested_txn->n_dbi); + tASSERT(nested, dbi > FREE_DBI && dbi < nested->n_dbi); const size_t size = cursor->subcur ? sizeof(MDBX_cursor) + sizeof(subcur_t) : sizeof(MDBX_cursor); MDBX_cursor *const shadow = osal_malloc(size); @@ -202,14 +202,14 @@ int cursor_shadow(MDBX_cursor *cursor, MDBX_txn *nested_txn, const size_t dbi) { #endif /* MDBX_DEBUG */ *shadow = *cursor; cursor->backup = shadow; - cursor->txn = nested_txn; - cursor->tree = &nested_txn->dbs[dbi]; - cursor->dbi_state = &nested_txn->dbi_state[dbi]; + cursor->txn = nested; + cursor->tree = &nested->dbs[dbi]; + cursor->dbi_state = &nested->dbi_state[dbi]; subcur_t *subcur = cursor->subcur; if (subcur) { *(subcur_t *)(shadow + 1) = *subcur; - subcur->cursor.txn = nested_txn; - subcur->cursor.dbi_state = cursor->dbi_state; + subcur->cursor.txn = nested; + subcur->cursor.dbi_state = &nested->dbi_state[dbi]; } return MDBX_SUCCESS; } diff --git a/src/cursor.h b/src/cursor.h index d4fc767b..8ca4ea72 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -293,7 +293,7 @@ MDBX_NOTHROW_PURE_FUNCTION static inline bool check_leaf_type(const MDBX_cursor } MDBX_INTERNAL void cursor_eot(MDBX_cursor *cursor); -MDBX_INTERNAL int cursor_shadow(MDBX_cursor *cursor, MDBX_txn *nested_txn, const size_t dbi); +MDBX_INTERNAL int cursor_shadow(MDBX_cursor *cursor, MDBX_txn *nested, const size_t dbi); MDBX_INTERNAL MDBX_cursor *cursor_cpstk(const MDBX_cursor *csrc, MDBX_cursor *cdst); From 333069e7a875799fe63ecf46b67c049bdefa0081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 6 Mar 2025 10:29:57 +0300 Subject: [PATCH 080/181] =?UTF-8?q?mdbx:=20=D1=80=D0=B5=D1=84=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20`cursor=5Feot()`=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BF=D1=80=D0=BE=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20`txn=5Fdone=5Fcursors()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cursor.c | 26 ++++++++++++++------------ src/cursor.h | 2 +- src/dbi.h | 2 +- src/txn.c | 8 +++----- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/cursor.c b/src/cursor.c index b0857e73..1fd8cbc1 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -214,18 +214,21 @@ int cursor_shadow(MDBX_cursor *cursor, MDBX_txn *nested, const size_t dbi) { return MDBX_SUCCESS; } -void cursor_eot(MDBX_cursor *cursor) { +MDBX_cursor *cursor_eot(MDBX_cursor *cursor, MDBX_txn *txn) { + MDBX_cursor *const next = cursor->next; + cursor->next = cursor; const unsigned stage = cursor->signature; MDBX_cursor *const shadow = cursor->backup; - ENSURE(cursor->txn->env, stage == cur_signature_live || (stage == cur_signature_wait4eot && shadow)); + ENSURE(txn->env, stage == cur_signature_live || (stage == cur_signature_wait4eot && shadow)); + tASSERT(txn, cursor->txn == txn); if (shadow) { subcur_t *subcur = cursor->subcur; - cASSERT(cursor, cursor->txn->parent != nullptr); - /* Zap: Using uninitialized memory '*cursor->backup'. */ + tASSERT(txn, txn->parent != nullptr && shadow->txn == txn->parent); + /* Zap: Using uninitialized memory '*mc->backup'. */ MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(6001); - ENSURE(cursor->txn->env, shadow->signature == cur_signature_live); - cASSERT(cursor, subcur == shadow->subcur); - if (((cursor->txn->flags | cursor->txn->parent->flags) & MDBX_TXN_ERROR) == 0) { + ENSURE(txn->env, shadow->signature == cur_signature_live); + tASSERT(txn, subcur == shadow->subcur); + if ((txn->flags & MDBX_TXN_ERROR) == 0) { /* Update pointers to parent txn */ cursor->next = shadow->next; cursor->backup = shadow->backup; @@ -233,25 +236,24 @@ void cursor_eot(MDBX_cursor *cursor) { cursor->tree = shadow->tree; cursor->dbi_state = shadow->dbi_state; if (subcur) { - subcur->cursor.txn = cursor->txn; - subcur->cursor.dbi_state = cursor->dbi_state; + subcur->cursor.txn = shadow->txn; + subcur->cursor.dbi_state = shadow->dbi_state; } } else { /* Restore from backup, i.e. rollback/abort nested txn */ *cursor = *shadow; + cursor->signature = stage /* Promote (cur_signature_wait4eot) state to parent txn */; if (subcur) *subcur = *(subcur_t *)(shadow + 1); } - if (stage == cur_signature_wait4eot /* Cursor was closed by user */) - cursor->signature = stage /* Promote closed state to parent txn */; shadow->signature = 0; osal_free(shadow); } else { ENSURE(cursor->txn->env, stage == cur_signature_live); be_poor(cursor); cursor->signature = cur_signature_ready4dispose /* Cursor may be reused */; - cursor->next = cursor; } + return next; } /*----------------------------------------------------------------------------*/ diff --git a/src/cursor.h b/src/cursor.h index 8ca4ea72..e53e91db 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -292,7 +292,7 @@ MDBX_NOTHROW_PURE_FUNCTION static inline bool check_leaf_type(const MDBX_cursor return (((page_type(mp) ^ mc->checking) & (z_branch | z_leaf | z_largepage | z_dupfix)) == 0); } -MDBX_INTERNAL void cursor_eot(MDBX_cursor *cursor); +MDBX_INTERNAL MDBX_cursor *cursor_eot(MDBX_cursor *cursor, MDBX_txn *txn); MDBX_INTERNAL int cursor_shadow(MDBX_cursor *cursor, MDBX_txn *nested, const size_t dbi); MDBX_INTERNAL MDBX_cursor *cursor_cpstk(const MDBX_cursor *csrc, MDBX_cursor *cdst); diff --git a/src/dbi.h b/src/dbi.h index 36c7e8bb..f634ee19 100644 --- a/src/dbi.h +++ b/src/dbi.h @@ -101,7 +101,7 @@ static inline bool dbi_changed(const MDBX_txn *txn, const size_t dbi) { const MDBX_env *const env = txn->env; eASSERT(env, dbi_state(txn, dbi) & DBI_LINDO); const uint32_t snap_seq = atomic_load32(&env->dbi_seqs[dbi], mo_AcquireRelease); - return snap_seq != txn->dbi_seqs[dbi]; + return unlikely(snap_seq != txn->dbi_seqs[dbi]); } static inline int dbi_check(const MDBX_txn *txn, const size_t dbi) { diff --git a/src/txn.c b/src/txn.c index 3d9c3aa3..09c4a3d0 100644 --- a/src/txn.c +++ b/src/txn.c @@ -15,11 +15,9 @@ void txn_done_cursors(MDBX_txn *txn) { MDBX_cursor *cursor = txn->cursors[i]; if (cursor) { txn->cursors[i] = nullptr; - do { - MDBX_cursor *const next = cursor->next; - cursor_eot(cursor); - cursor = next; - } while (cursor); + do + cursor = cursor_eot(cursor, txn); + while (cursor); } } txn->flags &= ~txn_may_have_cursors; From 12996534578771ea590efb321c0d1145b13cf9f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 6 Mar 2025 17:00:21 +0300 Subject: [PATCH 081/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`cursor=5Freset()`=20=D0=B8=20?= =?UTF-8?q?`cursor=5Fdrown()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cursor.c | 26 +++++++++++++------------- src/cursor.c | 6 +++--- src/cursor.h | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/api-cursor.c b/src/api-cursor.c index 05c98b4b..ca6c2b18 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -12,8 +12,7 @@ MDBX_cursor *mdbx_cursor_create(void *context) { couple->outer.signature = cur_signature_ready4dispose; couple->outer.next = &couple->outer; couple->userctx = context; - couple->outer.top_and_flags = z_poor_mark; - couple->inner.cursor.top_and_flags = z_poor_mark | z_inner; + cursor_reset(couple); VALGRIND_MAKE_MEM_DEFINED(&couple->outer.backup, sizeof(couple->outer.backup)); VALGRIND_MAKE_MEM_DEFINED(&couple->outer.tree, sizeof(couple->outer.tree)); VALGRIND_MAKE_MEM_DEFINED(&couple->outer.clc, sizeof(couple->outer.clc)); @@ -31,13 +30,15 @@ int mdbx_cursor_reset(MDBX_cursor *mc) { if (unlikely(!mc)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(mc->signature != cur_signature_ready4dispose && mc->signature != cur_signature_live)) - return LOG_IFERR(MDBX_EBADSIGN); + if (likely(mc->signature == cur_signature_live)) { + cursor_reset((cursor_couple_t *)mc); + return MDBX_SUCCESS; + } - cursor_couple_t *couple = (cursor_couple_t *)mc; - couple->outer.top_and_flags = z_poor_mark; - couple->inner.cursor.top_and_flags = z_poor_mark | z_inner; - return MDBX_SUCCESS; + if (likely(mc->signature == cur_signature_ready4dispose)) + return MDBX_SUCCESS; + + return LOG_IFERR(MDBX_EBADSIGN); } int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { @@ -113,7 +114,7 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) { } mc->next = mc; } - be_poor(mc); + cursor_drown((cursor_couple_t *)mc); mc->signature = cur_signature_ready4dispose; return MDBX_SUCCESS; } @@ -222,10 +223,9 @@ int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *co ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup); txn->cursors[i] = mc->next; mc->next = mc; - if (unbind) { - be_poor(mc); - mc->signature = cur_signature_ready4dispose; - } else { + mc->signature = cur_signature_ready4dispose; + cursor_drown((cursor_couple_t *)mc); + if (!unbind) { mc->signature = 0; osal_free(mc); } diff --git a/src/cursor.c b/src/cursor.c index 1fd8cbc1..d8199748 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -216,7 +216,6 @@ int cursor_shadow(MDBX_cursor *cursor, MDBX_txn *nested, const size_t dbi) { MDBX_cursor *cursor_eot(MDBX_cursor *cursor, MDBX_txn *txn) { MDBX_cursor *const next = cursor->next; - cursor->next = cursor; const unsigned stage = cursor->signature; MDBX_cursor *const shadow = cursor->backup; ENSURE(txn->env, stage == cur_signature_live || (stage == cur_signature_wait4eot && shadow)); @@ -224,7 +223,7 @@ MDBX_cursor *cursor_eot(MDBX_cursor *cursor, MDBX_txn *txn) { if (shadow) { subcur_t *subcur = cursor->subcur; tASSERT(txn, txn->parent != nullptr && shadow->txn == txn->parent); - /* Zap: Using uninitialized memory '*mc->backup'. */ + /* Zap: Using uninitialized memory '*subcur->backup'. */ MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(6001); ENSURE(txn->env, shadow->signature == cur_signature_live); tASSERT(txn, subcur == shadow->subcur); @@ -250,7 +249,8 @@ MDBX_cursor *cursor_eot(MDBX_cursor *cursor, MDBX_txn *txn) { osal_free(shadow); } else { ENSURE(cursor->txn->env, stage == cur_signature_live); - be_poor(cursor); + cursor_drown((cursor_couple_t *)cursor); + cursor->next = cursor; cursor->signature = cur_signature_ready4dispose /* Cursor may be reused */; } return next; diff --git a/src/cursor.h b/src/cursor.h index e53e91db..c8854faf 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -355,3 +355,19 @@ MDBX_MAYBE_UNUSED static inline void cursor_inner_refresh(const MDBX_cursor *mc, } MDBX_MAYBE_UNUSED MDBX_INTERNAL bool cursor_is_tracked(const MDBX_cursor *mc); + +static inline void cursor_reset(cursor_couple_t *couple) { + couple->outer.top_and_flags = z_fresh_mark; + couple->inner.cursor.top_and_flags = z_fresh_mark | z_inner; +} + +static inline void cursor_drown(cursor_couple_t *couple) { + couple->outer.top_and_flags = z_poor_mark; + couple->inner.cursor.top_and_flags = z_poor_mark | z_inner; + couple->outer.txn = nullptr; + couple->inner.cursor.txn = nullptr; + couple->outer.tree = nullptr; + /* сохраняем clc-указатель, так он используется для вычисления dbi в mdbx_cursor_renew(). */ + couple->outer.dbi_state = nullptr; + couple->inner.cursor.dbi_state = nullptr; +} From b2bd8bae3832ba17dfca8ac620890e6cbae43a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 6 Mar 2025 17:10:14 +0300 Subject: [PATCH 082/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`mdbx=5Fcursor=5Fclose2()`=20?= =?UTF-8?q?=D0=B2=20API.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 30 +++++++++++++++- mdbx.h++ | 5 ++- src/api-cursor.c | 91 ++++++++++++++++++++++++++++++------------------ src/cursor.c | 4 +-- src/mdbx.c++ | 9 ----- 5 files changed, 93 insertions(+), 46 deletions(-) diff --git a/mdbx.h b/mdbx.h index e971ade5..658c1b19 100644 --- a/mdbx.h +++ b/mdbx.h @@ -5218,12 +5218,17 @@ LIBMDBX_API int mdbx_cursor_reset(MDBX_cursor *cursor); * \retval MDBX_EINVAL An invalid parameter was specified. */ LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **cursor); -/** \brief Close a cursor handle. +/** \brief Closes a cursor handle without returning error code. * \ingroup c_cursors * * The cursor handle will be freed and must not be used again after this call, * but its transaction may still be live. * + * This function returns `void` but panic in case of error. Use \ref mdbx_cursor_close2() + * if you need to receive an error code instead of an app crash. + * + * \see mdbx_cursor_close2 + * * \note In contrast to LMDB, the MDBX required that any opened cursors can be * reused and must be freed explicitly, regardless ones was opened in a * read-only or write transaction. The REASON for this is eliminates ambiguity @@ -5234,6 +5239,29 @@ LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **curs * or \ref mdbx_cursor_create(). */ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); +/** \brief Closes a cursor handle with returning error code. + * \ingroup c_cursors + * + * The cursor handle will be freed and must not be used again after this call, + * but its transaction may still be live. + * + * \see mdbx_cursor_close + * + * \note In contrast to LMDB, the MDBX required that any opened cursors can be + * reused and must be freed explicitly, regardless ones was opened in a + * read-only or write transaction. The REASON for this is eliminates ambiguity + * which helps to avoid errors such as: use-after-free, double-free, i.e. + * memory corruption and segfaults. + * + * \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open() + * or \ref mdbx_cursor_create(). + * \returns A non-zero error value on failure and 0 on success, + * some possible errors are: + * \retval MDBX_THREAD_MISMATCH Given transaction is not owned + * by current thread. + * \retval MDBX_EINVAL An invalid parameter was specified. */ +LIBMDBX_API int mdbx_cursor_close2(MDBX_cursor *cursor); + /** \brief Unbind or closes all cursors of a given transaction. * \ingroup c_cursors * diff --git a/mdbx.h++ b/mdbx.h++ index e993f17f..3b6e6239 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -4545,7 +4545,10 @@ public: } /// \brief Explicitly closes the cursor. - void close(); + inline void close() { + error::success_or_throw(::mdbx_cursor_close2(handle_)); + handle_ = nullptr; + } cursor_managed(cursor_managed &&) = default; cursor_managed &operator=(cursor_managed &&other) noexcept { diff --git a/src/api-cursor.c b/src/api-cursor.c index ca6c2b18..b930f36c 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -94,6 +94,10 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) { /* TODO: реализовать при переходе на двусвязный список курсоров */ return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn(mc->txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + if (unlikely(!mc->txn || mc->txn->signature != txn_signature)) { ERROR("Wrong cursor's transaction %p 0x%x", __Wpedantic_format_voidptr(mc->txn), mc->txn ? mc->txn->signature : 0); return LOG_IFERR(MDBX_PROBLEM); @@ -138,42 +142,63 @@ int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) { return MDBX_SUCCESS; } -void mdbx_cursor_close(MDBX_cursor *mc) { - if (likely(mc)) { - ENSURE(nullptr, mc->signature == cur_signature_live || mc->signature == cur_signature_ready4dispose); - MDBX_txn *const txn = mc->txn; - if (!mc->backup) { - mc->txn = nullptr; - /* Unlink from txn, if tracked. */ - if (mc->next != mc) { - ENSURE(txn->env, check_txn(txn, 0) == MDBX_SUCCESS); - const size_t dbi = (kvx_t *)mc->clc - txn->env->kvs; - tASSERT(txn, dbi < txn->n_dbi); - if (dbi < txn->n_dbi) { - MDBX_cursor **prev = &txn->cursors[dbi]; - while (*prev) { - ENSURE(txn->env, (*prev)->signature == cur_signature_live || (*prev)->signature == cur_signature_wait4eot); - if (*prev == mc) - break; - prev = &(*prev)->next; - } - tASSERT(txn, *prev == mc); - *prev = mc->next; - } - mc->next = mc; - } - mc->signature = 0; - osal_free(mc); - } else { - /* Cursor closed before nested txn ends */ - tASSERT(txn, mc->signature == cur_signature_live); - ENSURE(txn->env, check_txn_rw(txn, 0) == MDBX_SUCCESS); - be_poor(mc); - mc->signature = cur_signature_wait4eot; - } +void mdbx_cursor_close(MDBX_cursor *cursor) { + if (likely(cursor)) { + int err = mdbx_cursor_close2(cursor); + if (unlikely(err != MDBX_SUCCESS)) + mdbx_panic("%s:%d error %d (%s) while closing cursor", __func__, __LINE__, err, mdbx_liberr2str(err)); } } +int mdbx_cursor_close2(MDBX_cursor *mc) { + if (unlikely(!mc)) + return LOG_IFERR(MDBX_EINVAL); + + if (mc->signature == cur_signature_ready4dispose) { + if (unlikely(mc->txn || mc->backup)) + return LOG_IFERR(MDBX_PANIC); + cursor_drown((cursor_couple_t *)mc); + mc->signature = 0; + osal_free(mc); + return MDBX_SUCCESS; + } + + if (unlikely(mc->signature != cur_signature_live)) + return LOG_IFERR(MDBX_EBADSIGN); + + MDBX_txn *const txn = mc->txn; + int rc = check_txn(txn, MDBX_TXN_FINISHED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + + if (mc->backup) { + /* Cursor closed before nested txn ends */ + cursor_reset((cursor_couple_t *)mc); + mc->signature = cur_signature_wait4eot; + return MDBX_SUCCESS; + } + + if (mc->next != mc) { + const size_t dbi = cursor_dbi(mc); + cASSERT(mc, dbi < mc->txn->n_dbi); + cASSERT(mc, &mc->txn->env->kvs[dbi].clc == mc->clc); + if (likely(dbi < txn->n_dbi)) { + MDBX_cursor **prev = &txn->cursors[dbi]; + while (/* *prev && */ *prev != mc) { + ENSURE(txn->env, (*prev)->signature == cur_signature_live || (*prev)->signature == cur_signature_wait4eot); + prev = &(*prev)->next; + } + tASSERT(txn, *prev == mc); + *prev = mc->next; + } + mc->next = mc; + } + cursor_drown((cursor_couple_t *)mc); + mc->signature = 0; + osal_free(mc); + return MDBX_SUCCESS; +} + int mdbx_cursor_copy(const MDBX_cursor *src, MDBX_cursor *dest) { if (unlikely(!src)) return LOG_IFERR(MDBX_EINVAL); diff --git a/src/cursor.c b/src/cursor.c index d8199748..6cb2d875 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -249,9 +249,9 @@ MDBX_cursor *cursor_eot(MDBX_cursor *cursor, MDBX_txn *txn) { osal_free(shadow); } else { ENSURE(cursor->txn->env, stage == cur_signature_live); - cursor_drown((cursor_couple_t *)cursor); - cursor->next = cursor; cursor->signature = cur_signature_ready4dispose /* Cursor may be reused */; + cursor->next = cursor; + cursor_drown((cursor_couple_t *)cursor); } return next; } diff --git a/src/mdbx.c++ b/src/mdbx.c++ index d891b654..63f56190 100644 --- a/src/mdbx.c++ +++ b/src/mdbx.c++ @@ -1590,15 +1590,6 @@ __cold bool txn::rename_map(const ::std::string &old_name, const ::std::string & //------------------------------------------------------------------------------ -void cursor_managed::close() { - if (MDBX_UNLIKELY(!handle_)) - MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL); - ::mdbx_cursor_close(handle_); - handle_ = nullptr; -} - -//------------------------------------------------------------------------------ - __cold ::std::ostream &operator<<(::std::ostream &out, const slice &it) { out << "{"; if (!it.is_valid()) From 8dda33329b4a9babcfa90005618fb5e3e84c5565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 6 Mar 2025 20:58:31 +0300 Subject: [PATCH 083/181] =?UTF-8?q?mdbx-tests:=20=D0=BF=D0=BE=D0=B4=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B6=D0=BA=D0=B0=20=D0=B7=D0=BD=D0=B0=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B9=20`on`/`off`=20=D0=B4=D0=BB=D1=8F=20=D0=BE?= =?UTF-8?q?=D0=BF=D1=86=D0=B8=D0=B9=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4?= =?UTF-8?q?=D0=BD=D0=BE=D0=B9=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/config.c++ | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/config.c++ b/test/config.c++ index 4188e3c0..f9e75dac 100644 --- a/test/config.c++ +++ b/test/config.c++ @@ -313,12 +313,12 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option, b return true; } - if (strcasecmp(value_cstr, "yes") == 0 || strcasecmp(value_cstr, "1") == 0) { + if (strcasecmp(value_cstr, "yes") == 0 || strcasecmp(value_cstr, "1") == 0 || strcasecmp(value_cstr, "on") == 0) { value = true; return true; } - if (strcasecmp(value_cstr, "no") == 0 || strcasecmp(value_cstr, "0") == 0) { + if (strcasecmp(value_cstr, "no") == 0 || strcasecmp(value_cstr, "0") == 0 || strcasecmp(value_cstr, "off") == 0) { value = false; return true; } From 42706c45a07abf4c4ebb4b3222a2af24f2aabc1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 7 Mar 2025 10:43:01 +0300 Subject: [PATCH 084/181] =?UTF-8?q?mdbx-tests:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=BE=D0=B4=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B6=D0=BA=D0=B8=20=D0=BE=D0=BF=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20`MDBX=5FVALIDATION`=20=D0=B8=20=D0=B8=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B2?= =?UTF-8?q?=20=D1=81=D1=82=D0=BE=D1=85=D0=B0=D1=81=D1=82=D0=B8=D1=87=D0=B5?= =?UTF-8?q?=D1=81=D0=BA=D0=BE=D0=BC=20=D1=82=D0=B5=D1=81=D1=82=D0=B5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/config.c++ | 1 + test/stochastic.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/config.c++ b/test/config.c++ index f9e75dac..4bc20b32 100644 --- a/test/config.c++ +++ b/test/config.c++ @@ -342,6 +342,7 @@ const struct option_verb mode_bits[] = {{"rdonly", unsigned(MDBX_RDONLY)}, {"perturb", unsigned(MDBX_PAGEPERTURB)}, {"accede", unsigned(MDBX_ACCEDE)}, {"exclusive", unsigned(MDBX_EXCLUSIVE)}, + {"validation", unsigned(MDBX_VALIDATION)}, {nullptr, 0}}; const struct option_verb table_bits[] = {{"key.reverse", unsigned(MDBX_REVERSEKEY)}, diff --git a/test/stochastic.sh b/test/stochastic.sh index 18ea6737..d7abcdf5 100755 --- a/test/stochastic.sh +++ b/test/stochastic.sh @@ -440,7 +440,7 @@ else fi if [ "$EXTRA" != "no" ]; then - options=(perturb nomeminit nordahead writemap lifo nostickythreads) + options=(perturb nomeminit nordahead writemap lifo nostickythreads validation) else options=(writemap lifo nostickythreads) fi From b546dc69d2b3525b7165bace9139d540f2e5571f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 9 Mar 2025 01:31:48 +0300 Subject: [PATCH 085/181] =?UTF-8?q?mdbx-doc:=20doxygen-=D0=BE=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=BB=D1=8F=20doubtless?= =?UTF-8?q?-positioning=20=D0=BA=D0=BE=D0=BD=D1=81=D1=82=D0=B0=D0=BD=D1=82?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/mdbx.h b/mdbx.h index 658c1b19..e5d3f523 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1791,26 +1791,28 @@ typedef enum MDBX_cursor_op { * \ref MDBX_NOTFOUND otherwise. */ MDBX_SET_UPPERBOUND, - /* Doubtless cursor positioning at a specified key. */ + /** Doubtless cursor positioning at a specified key. */ 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_KEY_LESSER_OR_EQUAL /** \copydoc MDBX_TO_KEY_LESSER_THAN */, + MDBX_TO_KEY_EQUAL /** \copydoc MDBX_TO_KEY_LESSER_THAN */, + MDBX_TO_KEY_GREATER_OR_EQUAL /** \copydoc MDBX_TO_KEY_LESSER_THAN */, + MDBX_TO_KEY_GREATER_THAN /** \copydoc MDBX_TO_KEY_LESSER_THAN */, - /* Doubtless cursor positioning at a specified key-value pair + /** Doubtless cursor positioning at a specified key-value pair * for dupsort/multi-value hives. */ 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_EXACT_KEY_VALUE_LESSER_OR_EQUAL /** \copydoc MDBX_TO_EXACT_KEY_VALUE_LESSER_THAN */, + MDBX_TO_EXACT_KEY_VALUE_EQUAL /** \copydoc MDBX_TO_EXACT_KEY_VALUE_LESSER_THAN */, + MDBX_TO_EXACT_KEY_VALUE_GREATER_OR_EQUAL /** \copydoc MDBX_TO_EXACT_KEY_VALUE_LESSER_THAN */, + MDBX_TO_EXACT_KEY_VALUE_GREATER_THAN /** \copydoc MDBX_TO_EXACT_KEY_VALUE_LESSER_THAN */, + /** Doubtless cursor positioning at a specified key-value pair + * for dupsort/multi-value hives. */ 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_TO_PAIR_LESSER_OR_EQUAL /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, + MDBX_TO_PAIR_EQUAL /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, + MDBX_TO_PAIR_GREATER_OR_EQUAL /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, + MDBX_TO_PAIR_GREATER_THAN /** \copydoc MDBX_TO_PAIR_LESSER_THAN */ } MDBX_cursor_op; /** \brief Errors and return codes From 2ffa5cf3712082e21e1cf43ee1651b86564d620f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 9 Mar 2025 01:40:31 +0300 Subject: [PATCH 086/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`MDBX=5FSEEK=5FAND=5FGET=5FMUL?= =?UTF-8?q?TIPLE`=20=D0=B2=20API=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B9=20=D0=BA=D1=83=D1=80=D1=81=D0=BE=D1=80=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 16 +++++++++++----- src/cursor.c | 38 +++++++++++++------------------------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/mdbx.h b/mdbx.h index e5d3f523..5a3552a8 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1718,7 +1718,7 @@ typedef enum MDBX_cursor_op { /** \ref MDBX_DUPFIXED -only: Return up to a page of duplicate data items * from current cursor position. Move cursor to prepare - * for \ref MDBX_NEXT_MULTIPLE. */ + * for \ref MDBX_NEXT_MULTIPLE. \see MDBX_SEEK_AND_GET_MULTIPLE */ MDBX_GET_MULTIPLE, /** Position at last key/data item */ @@ -1734,8 +1734,8 @@ typedef enum MDBX_cursor_op { MDBX_NEXT_DUP, /** \ref MDBX_DUPFIXED -only: Return up to a page of duplicate data items - * from next cursor position. Move cursor to prepare - * for `MDBX_NEXT_MULTIPLE`. */ + * from next cursor position. Move cursor to prepare for `MDBX_NEXT_MULTIPLE`. + * \see MDBX_SEEK_AND_GET_MULTIPLE \see MDBX_GET_MULTIPLE */ MDBX_NEXT_MULTIPLE, /** Position at first data item of next key */ @@ -1760,7 +1760,8 @@ typedef enum MDBX_cursor_op { MDBX_SET_RANGE, /** \ref MDBX_DUPFIXED -only: Position at previous page and return up to - * a page of duplicate data items. */ + * a page of duplicate data items. + * \see MDBX_SEEK_AND_GET_MULTIPLE \see MDBX_GET_MULTIPLE */ MDBX_PREV_MULTIPLE, /** Positions cursor at first key-value pair greater than or equal to @@ -1812,7 +1813,12 @@ typedef enum MDBX_cursor_op { MDBX_TO_PAIR_LESSER_OR_EQUAL /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, MDBX_TO_PAIR_EQUAL /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, MDBX_TO_PAIR_GREATER_OR_EQUAL /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, - MDBX_TO_PAIR_GREATER_THAN /** \copydoc MDBX_TO_PAIR_LESSER_THAN */ + MDBX_TO_PAIR_GREATER_THAN /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, + + /** \ref MDBX_DUPFIXED -only: Seek to given key and return up to a page of + * duplicate data items from current cursor position. Move cursor to prepare + * for \ref MDBX_NEXT_MULTIPLE. \see MDBX_GET_MULTIPLE */ + MDBX_SEEK_AND_GET_MULTIPLE } MDBX_cursor_op; /** \brief Errors and return codes diff --git a/src/cursor.c b/src/cursor.c index 6cb2d875..098b4d70 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -2049,27 +2049,24 @@ __hot int cursor_ops(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, const MDBX_ cASSERT(mc, is_poor(mc) && !is_filled(mc)); return rc; + case MDBX_SEEK_AND_GET_MULTIPLE: + if (unlikely(!key)) + return MDBX_EINVAL; + rc = cursor_seek(mc, key, data, MDBX_SET).err; + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + __fallthrough /* fall through */; case MDBX_GET_MULTIPLE: if (unlikely(!data)) return MDBX_EINVAL; if (unlikely((mc->tree->flags & MDBX_DUPFIXED) == 0)) return MDBX_INCOMPATIBLE; - if (unlikely(!is_pointed(mc))) { - if (unlikely(!key)) - return MDBX_EINVAL; - if (unlikely((mc->flags & z_fresh) == 0)) - return MDBX_ENODATA; - rc = cursor_seek(mc, key, data, MDBX_SET).err; - if (unlikely(rc != MDBX_SUCCESS)) - return rc; - } else { - if (unlikely(!is_filled(mc))) - return MDBX_ENODATA; - if (key) { - const page_t *mp = mc->pg[mc->top]; - const node_t *node = page_node(mp, mc->ki[mc->top]); - *key = get_key(node); - } + if (unlikely(!is_filled(mc))) + return MDBX_ENODATA; + if (key) { + const page_t *mp = mc->pg[mc->top]; + const node_t *node = page_node(mp, mc->ki[mc->top]); + *key = get_key(node); } cASSERT(mc, is_filled(mc)); if (unlikely(!inner_filled(mc))) { @@ -2104,15 +2101,6 @@ __hot int cursor_ops(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, const MDBX_ return MDBX_EINVAL; if (unlikely(mc->subcur == nullptr)) return MDBX_INCOMPATIBLE; - if (unlikely(!is_pointed(mc))) { - if (unlikely((mc->flags & z_fresh) == 0)) - return MDBX_ENODATA; - rc = outer_last(mc, key, data); - if (unlikely(rc != MDBX_SUCCESS)) - return rc; - mc->subcur->cursor.ki[mc->subcur->cursor.top] = 0; - goto fetch_multiple; - } if (unlikely(!is_filled(mc) || !inner_filled(mc))) return MDBX_ENODATA; rc = cursor_sibling_left(&mc->subcur->cursor); From 546b48b6ebc03a1f23e0e9b1fff36c86f5484671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 14 Mar 2025 00:31:51 +0300 Subject: [PATCH 087/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B8?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20`curso?= =?UTF-8?q?r=5Fvalidate()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cursor.c | 20 ++++++++++---------- src/cursor.h | 4 ++-- src/tree-ops.c | 16 ++++++++-------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/cursor.c b/src/cursor.c index 098b4d70..4281a0f3 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -5,7 +5,7 @@ #include "internals.h" -__cold int cursor_check(const MDBX_cursor *mc) { +__cold int cursor_validate(const MDBX_cursor *mc) { if (!mc->txn->wr.dirtylist) { cASSERT(mc, (mc->txn->flags & MDBX_WRITEMAP) != 0 && !MDBX_AVOID_MSYNC); } else { @@ -81,10 +81,10 @@ __cold int cursor_check(const MDBX_cursor *mc) { return MDBX_SUCCESS; } -__cold int cursor_check_updating(MDBX_cursor *mc) { +__cold int cursor_validate_updating(MDBX_cursor *mc) { const uint8_t checking = mc->checking; mc->checking |= z_updating; - const int rc = cursor_check(mc); + const int rc = cursor_validate(mc); mc->checking = checking; return rc; } @@ -938,7 +938,7 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig } if (AUDIT_ENABLED()) { - err = cursor_check(mc); + err = cursor_validate(mc); if (unlikely(err != MDBX_SUCCESS)) return err; } @@ -947,7 +947,7 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig more: if (AUDIT_ENABLED()) { - err = cursor_check(mc); + err = cursor_validate(mc); if (unlikely(err != MDBX_SUCCESS)) return err; } @@ -1008,7 +1008,7 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig memcpy(page_data(lp.page), data->iov_base, data->iov_len); if (AUDIT_ENABLED()) { - err = cursor_check(mc); + err = cursor_validate(mc); if (unlikely(err != MDBX_SUCCESS)) return err; } @@ -1275,7 +1275,7 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig } if (AUDIT_ENABLED()) { - err = cursor_check(mc); + err = cursor_validate(mc); if (unlikely(err != MDBX_SUCCESS)) return err; } @@ -1293,7 +1293,7 @@ insert_node:; if (page_room(mc->pg[mc->top]) < nsize) { rc = page_split(mc, key, ref_data, P_INVALID, insert_key ? naf : naf | MDBX_SPLIT_REPLACE); if (rc == MDBX_SUCCESS && AUDIT_ENABLED()) - rc = insert_key ? cursor_check(mc) : cursor_check_updating(mc); + rc = insert_key ? cursor_validate(mc) : cursor_validate_updating(mc); } else { /* There is room already in this leaf page. */ if (is_dupfix_leaf(mc->pg[mc->top])) { @@ -1415,7 +1415,7 @@ insert_node:; } } if (AUDIT_ENABLED()) - rc = cursor_check(mc); + rc = cursor_validate(mc); } return rc; @@ -1687,7 +1687,7 @@ del_key: cASSERT(mc, rc == MDBX_SUCCESS); if (AUDIT_ENABLED()) - rc = cursor_check(mc); + rc = cursor_validate(mc); return rc; fail: diff --git a/src/cursor.h b/src/cursor.h index c8854faf..f9d4ea82 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -233,7 +233,7 @@ enum cursor_checking { z_pagecheck = 0x80 /* perform page checking, see MDBX_VALIDATION */ }; -MDBX_INTERNAL int __must_check_result cursor_check(const MDBX_cursor *mc); +MDBX_INTERNAL int __must_check_result cursor_validate(const MDBX_cursor *mc); MDBX_MAYBE_UNUSED MDBX_NOTHROW_PURE_FUNCTION static inline size_t cursor_dbi(const MDBX_cursor *mc) { cASSERT(mc, mc->txn && mc->txn->signature == txn_signature); @@ -305,7 +305,7 @@ MDBX_INTERNAL int __must_check_result cursor_put_checklen(MDBX_cursor *mc, const MDBX_INTERNAL int __must_check_result cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsigned flags); -MDBX_INTERNAL int __must_check_result cursor_check_updating(MDBX_cursor *mc); +MDBX_INTERNAL int __must_check_result cursor_validate_updating(MDBX_cursor *mc); MDBX_INTERNAL int __must_check_result cursor_del(MDBX_cursor *mc, unsigned flags); diff --git a/src/tree-ops.c b/src/tree-ops.c index cb5c02b3..cc9acf48 100644 --- a/src/tree-ops.c +++ b/src/tree-ops.c @@ -880,7 +880,7 @@ retry: if (nkeys >= minkeys) { mc->ki[mc->top] = (indx_t)ki_top; if (AUDIT_ENABLED()) - return cursor_check_updating(mc); + return cursor_validate_updating(mc); return MDBX_SUCCESS; } @@ -920,7 +920,7 @@ int page_split(MDBX_cursor *mc, const MDBX_val *const newkey, MDBX_val *const ne const size_t newindx = mc->ki[mc->top]; size_t nkeys = page_numkeys(mp); if (AUDIT_ENABLED()) { - rc = cursor_check_updating(mc); + rc = cursor_validate_updating(mc); if (unlikely(rc != MDBX_SUCCESS)) return rc; } @@ -979,7 +979,7 @@ int page_split(MDBX_cursor *mc, const MDBX_val *const newkey, MDBX_val *const ne mc->top = 1; prev_top = 0; if (AUDIT_ENABLED()) { - rc = cursor_check_updating(mc); + rc = cursor_validate_updating(mc); if (unlikely(rc != MDBX_SUCCESS)) goto done; } @@ -1092,10 +1092,10 @@ int page_split(MDBX_cursor *mc, const MDBX_val *const newkey, MDBX_val *const ne } if (AUDIT_ENABLED()) { - rc = cursor_check_updating(mc); + rc = cursor_validate_updating(mc); if (unlikely(rc != MDBX_SUCCESS)) goto done; - rc = cursor_check_updating(mn); + rc = cursor_validate_updating(mn); if (unlikely(rc != MDBX_SUCCESS)) goto done; } @@ -1221,7 +1221,7 @@ int page_split(MDBX_cursor *mc, const MDBX_val *const newkey, MDBX_val *const ne goto done; cASSERT(mc, mc->top - top == mc->tree->height - height); if (AUDIT_ENABLED()) { - rc = cursor_check_updating(mc); + rc = cursor_validate_updating(mc); if (unlikely(rc != MDBX_SUCCESS)) goto done; } @@ -1474,7 +1474,7 @@ done: mc->txn->flags |= MDBX_TXN_ERROR; else { if (AUDIT_ENABLED()) - rc = cursor_check_updating(mc); + rc = cursor_validate_updating(mc); if (unlikely(naf & MDBX_RESERVE)) { node_t *node = page_node(mc->pg[mc->top], mc->ki[mc->top]); if (!(node_flags(node) & N_BIG)) @@ -1524,7 +1524,7 @@ int tree_propagate_key(MDBX_cursor *mc, const MDBX_val *key) { node_del(mc, 0); int err = page_split(mc, key, nullptr, pgno, MDBX_SPLIT_REPLACE); if (err == MDBX_SUCCESS && AUDIT_ENABLED()) - err = cursor_check_updating(mc); + err = cursor_validate_updating(mc); return err; } From 3e91500fac475947f5b58268d5edd3c9cc4f77f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 13 Mar 2025 20:48:26 +0300 Subject: [PATCH 088/181] =?UTF-8?q?mdbx:=20=D1=83=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B3=D0=BE=D0=BD=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=B2=20`tbl=5Fsetup(MDBX=5FDUPFIXED=20|=20MDBX=5FINTEGERDU?= =?UTF-8?q?P)`=20=D0=BF=D1=80=D0=B8=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B5?= =?UTF-8?q?=20=D0=B2=20=D1=80=D0=B0=D0=B7=D0=BD=D1=8B=D1=85=20=D0=BF=D0=BE?= =?UTF-8?q?=D1=82=D0=BE=D0=BA=D0=B0=D1=85.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проблема была в том, что в случаях фиксированного размера значений clc.lmin/clc.lmax устанавливались в env->kvs[], а затем корректировались по актуальному размеру данных в БД. Поэтому при конкурентном вызове из разных потоков, один поток мог выполнять инициализацию, а второй прочитать временные/промежуточные значения lmin/lmax. В результате, при конкурентном старте транзакций в разных потоках при использовании только-что открытого dbi-хендла, проверка допустимости длины значения могла заканчиваться ложной ошибкой MDBX_BAD_VALSIZE. --- src/cogs.h | 4 ++++ src/cursor.c | 6 ++---- src/proto.h | 2 +- src/table.c | 40 ++++++++++++++++++++++++++-------------- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/cogs.h b/src/cogs.h index 11d7fe1d..7e814e7b 100644 --- a/src/cogs.h +++ b/src/cogs.h @@ -200,6 +200,10 @@ static inline bool check_table_flags(unsigned flags) { } } +static inline int tbl_setup_ifneed(const MDBX_env *env, volatile kvx_t *const kvx, const tree_t *const db) { + return likely(kvx->clc.v.lmax) ? MDBX_SUCCESS : tbl_setup(env, kvx, db); +} + /*----------------------------------------------------------------------------*/ MDBX_NOTHROW_PURE_FUNCTION static inline size_t pgno2bytes(const MDBX_env *env, size_t pgno) { diff --git a/src/cursor.c b/src/cursor.c index 4281a0f3..43f192a2 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -295,10 +295,7 @@ static __always_inline int couple_init(cursor_couple_t *couple, const MDBX_txn * if (unlikely(*dbi_state & DBI_STALE)) return tbl_fetch(couple->outer.txn, cursor_dbi(&couple->outer)); - if (unlikely(kvx->clc.k.lmax == 0)) - return tbl_setup(txn->env, kvx, tree); - - return MDBX_SUCCESS; + return tbl_setup_ifneed(txn->env, kvx, tree); } __cold int cursor_init4walk(cursor_couple_t *couple, const MDBX_txn *const txn, tree_t *const tree, kvx_t *const kvx) { @@ -384,6 +381,7 @@ int cursor_dupsort_setup(MDBX_cursor *mc, const node_t *node, const page_t *mp) } mc->tree->dupfix_size = mx->nested_tree.dupfix_size; mc->clc->v.lmin = mc->clc->v.lmax = mx->nested_tree.dupfix_size; + cASSERT(mc, mc->clc->v.lmax >= mc->clc->v.lmin); } DEBUG("Sub-db dbi -%zu root page %" PRIaPGNO, cursor_dbi(&mx->cursor), mx->nested_tree.root); diff --git a/src/proto.h b/src/proto.h index c0e46d0a..e1886c5d 100644 --- a/src/proto.h +++ b/src/proto.h @@ -111,7 +111,7 @@ MDBX_INTERNAL void recalculate_subpage_thresholds(MDBX_env *env); /* table.c */ MDBX_INTERNAL int __must_check_result tbl_fetch(MDBX_txn *txn, size_t dbi); -MDBX_INTERNAL int __must_check_result tbl_setup(const MDBX_env *env, kvx_t *const kvx, const tree_t *const db); +MDBX_INTERNAL int __must_check_result tbl_setup(const MDBX_env *env, volatile kvx_t *const kvx, const tree_t *const db); /* coherency.c */ MDBX_INTERNAL bool coherency_check_meta(const MDBX_env *env, const volatile meta_t *meta, bool report); diff --git a/src/table.c b/src/table.c index faa44da1..5b3e441a 100644 --- a/src/table.c +++ b/src/table.c @@ -3,28 +3,37 @@ #include "internals.h" -int tbl_setup(const MDBX_env *env, kvx_t *const kvx, const tree_t *const db) { +int tbl_setup(const MDBX_env *env, volatile kvx_t *const kvx, const tree_t *const db) { + osal_memory_fence(mo_AcquireRelease, false); + if (unlikely(!check_table_flags(db->flags))) { ERROR("incompatible or invalid db.flags (0x%x) ", db->flags); return MDBX_INCOMPATIBLE; } - if (unlikely(!kvx->clc.k.cmp)) { - kvx->clc.k.cmp = builtin_keycmp(db->flags); - kvx->clc.v.cmp = builtin_datacmp(db->flags); + + size_t v_lmin = valsize_min(db->flags); + size_t v_lmax = env_valsize_max(env, db->flags); + if ((db->flags & (MDBX_DUPFIXED | MDBX_INTEGERDUP)) != 0 && db->dupfix_size) { + if (!MDBX_DISABLE_VALIDATION && unlikely(db->dupfix_size < v_lmin || db->dupfix_size > v_lmax)) { + ERROR("db.dupfix_size (%u) <> min/max value-length (%zu/%zu)", db->dupfix_size, v_lmin, v_lmax); + return MDBX_CORRUPTED; + } + v_lmin = v_lmax = db->dupfix_size; } kvx->clc.k.lmin = keysize_min(db->flags); kvx->clc.k.lmax = env_keysize_max(env, db->flags); - kvx->clc.v.lmin = valsize_min(db->flags); - kvx->clc.v.lmax = env_valsize_max(env, db->flags); - - if ((db->flags & (MDBX_DUPFIXED | MDBX_INTEGERDUP)) != 0 && db->dupfix_size) { - if (!MDBX_DISABLE_VALIDATION && unlikely(db->dupfix_size < kvx->clc.v.lmin || db->dupfix_size > kvx->clc.v.lmax)) { - ERROR("db.dupfix_size (%u) <> min/max value-length (%zu/%zu)", db->dupfix_size, kvx->clc.v.lmin, kvx->clc.v.lmax); - return MDBX_CORRUPTED; - } - kvx->clc.v.lmin = kvx->clc.v.lmax = db->dupfix_size; + if (unlikely(!kvx->clc.k.cmp)) { + kvx->clc.v.cmp = builtin_datacmp(db->flags); + kvx->clc.k.cmp = builtin_keycmp(db->flags); } + kvx->clc.v.lmin = v_lmin; + osal_memory_fence(mo_Relaxed, true); + kvx->clc.v.lmax = v_lmax; + osal_memory_fence(mo_AcquireRelease, true); + + eASSERT(env, kvx->clc.k.lmax >= kvx->clc.k.lmin); + eASSERT(env, kvx->clc.v.lmax >= kvx->clc.v.lmin); return MDBX_SUCCESS; } @@ -86,10 +95,13 @@ int tbl_fetch(MDBX_txn *txn, size_t dbi) { return MDBX_CORRUPTED; } #endif /* !MDBX_DISABLE_VALIDATION */ - rc = tbl_setup(txn->env, kvx, db); + rc = tbl_setup_ifneed(txn->env, kvx, db); if (unlikely(rc != MDBX_SUCCESS)) return rc; + if (unlikely(dbi_changed(txn, dbi))) + return MDBX_BAD_DBI; + txn->dbi_state[dbi] &= ~DBI_STALE; return MDBX_SUCCESS; } From 7a72d1b27391598698c2ba617cd8787a960a37fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 10 Mar 2025 23:13:23 +0300 Subject: [PATCH 089/181] =?UTF-8?q?mdbx:=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=BE=D0=BF?= =?UTF-8?q?=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D1=8F=20`MDBX=5FMVCC=5FRETARDED`?= =?UTF-8?q?=20=D0=B8=20=D1=81=D0=BE=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B5=D0=B3=D0=BE=20=D1=81=D0=BE?= =?UTF-8?q?=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BE=D0=B1=20?= =?UTF-8?q?=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 3 +-- src/api-misc.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/mdbx.h b/mdbx.h index 5a3552a8..ecaa3e18 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1972,8 +1972,7 @@ typedef enum MDBX_error { * recycling old MVCC snapshots. */ MDBX_OUSTED = -30411, - /** MVCC snapshot used by read transaction is outdated and could not be - * copied since corresponding meta-pages was overwritten. */ + /** MVCC snapshot used by parked transaction was bygone. */ MDBX_MVCC_RETARDED = -30410, /* The last of MDBX-added error codes */ diff --git a/src/api-misc.c b/src/api-misc.c index 7e54c51d..27e82a90 100644 --- a/src/api-misc.c +++ b/src/api-misc.c @@ -199,9 +199,7 @@ __cold const char *mdbx_liberr2str(int errnum) { return "MDBX_OUSTED: The parked read transaction was outed for the sake" " of recycling old MVCC snapshots"; case MDBX_MVCC_RETARDED: - return "MDBX_MVCC_RETARDED: MVCC snapshot used by read transaction" - " is outdated and could not be copied" - " since corresponding meta-pages was overwritten"; + return "MDBX_MVCC_RETARDED: MVCC snapshot used by parked transaction was bygone"; default: return nullptr; } From fa2c27fa08e62d33cfab0a99b44437db5aec6e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 14 Mar 2025 01:54:18 +0300 Subject: [PATCH 090/181] =?UTF-8?q?mdbx++:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`mdbx::cursor=5Fmanaged:?= =?UTF-8?q?:withdraw=5Fhandle()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mdbx.h++ b/mdbx.h++ index 3b6e6239..8ba9f102 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -4155,9 +4155,9 @@ public: class LIBMDBX_API_TYPE cursor { protected: MDBX_cursor *handle_{nullptr}; - MDBX_CXX11_CONSTEXPR cursor(MDBX_cursor *ptr) noexcept; public: + MDBX_CXX11_CONSTEXPR cursor(MDBX_cursor *ptr) noexcept; MDBX_CXX11_CONSTEXPR cursor() noexcept = default; cursor(const cursor &) noexcept = default; inline cursor &operator=(cursor &&other) noexcept; @@ -4561,6 +4561,12 @@ public: return *this; } + inline MDBX_cursor *withdraw_handle() noexcept { + MDBX_cursor *handle = handle_; + handle_ = nullptr; + return handle; + } + cursor_managed(const cursor_managed &) = delete; cursor_managed &operator=(const cursor_managed &) = delete; ~cursor_managed() noexcept { ::mdbx_cursor_close(handle_); } From 70adf71770ae9d87abbe3c98ca1fc4320ba73de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 13 Mar 2025 20:11:12 +0300 Subject: [PATCH 091/181] =?UTF-8?q?mdbx++:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`inplace=5Fstorage=5Fsiz?= =?UTF-8?q?e=5Frounding`=20=D0=B2=20`capacity=5Fpolicy`=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=B1=D1=83=D1=84=D0=B5=D1=80=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 111 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 45 deletions(-) diff --git a/mdbx.h++ b/mdbx.h++ index 8ba9f102..97120b3f 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -1162,7 +1162,12 @@ template struct swap_alloc { } // namespace allocation_aware_details struct default_capacity_policy { - enum : size_t { extra_inplace_storage = 0, pettiness_threshold = 64, max_reserve = 65536 }; + enum : size_t { + extra_inplace_storage = 0, + inplace_storage_size_rounding = 16, + pettiness_threshold = 64, + max_reserve = 65536 + }; static MDBX_CXX11_CONSTEXPR size_t round(const size_t value) { static_assert((pettiness_threshold & (pettiness_threshold - 1)) == 0, "pettiness_threshold must be a power of 2"); @@ -1486,6 +1491,10 @@ public: max_length = MDBX_MAXDATASIZE, max_capacity = (max_length / 3u * 4u + 1023u) & ~size_t(1023), extra_inplace_storage = reservation_policy::extra_inplace_storage, + inplace_storage_size_rounding = + (alignof(max_align_t) * 2 > size_t(reservation_policy::inplace_storage_size_rounding)) + ? alignof(max_align_t) * 2 + : size_t(reservation_policy::inplace_storage_size_rounding), pettiness_threshold = reservation_policy::pettiness_threshold }; @@ -1529,41 +1538,51 @@ private: #endif /* __cpp_lib_to_address */ } - union bin { - struct allocated { + union alignas(max_align_t) bin { + struct stub_allocated_holder /* используется только для вычисления (минимального необходимого) размера, + с учетом выравнивания */ + { allocator_pointer ptr_; - size_t capacity_bytes_; - constexpr allocated(allocator_pointer ptr, size_t bytes) noexcept : ptr_(ptr), capacity_bytes_(bytes) {} - constexpr allocated(const allocated &) noexcept = default; - constexpr allocated(allocated &&) noexcept = default; - MDBX_CXX17_CONSTEXPR allocated &operator=(const allocated &) noexcept = default; - MDBX_CXX17_CONSTEXPR allocated &operator=(allocated &&) noexcept = default; + size_t stub_capacity_bytes_; }; - allocated allocated_; - uint64_t align_hint_; - byte inplace_[(sizeof(allocated) + extra_inplace_storage + 7u) & ~size_t(7)]; - - static constexpr bool is_suitable_for_inplace(size_t capacity_bytes) noexcept { - static_assert(sizeof(bin) == sizeof(inplace_), "WTF?"); - return capacity_bytes < sizeof(bin); - } - - enum : byte { lastbyte_inplace_signature = byte(~byte(0)) }; + enum : byte { lastbyte_poison = 0, lastbyte_inplace_signature = byte(~byte(lastbyte_poison)) }; enum : size_t { inplace_signature_limit = size_t(lastbyte_inplace_signature) - << (sizeof(size_t /* allocated::capacity_bytes_ */) - 1) * CHAR_BIT + << (sizeof(size_t /* allocated::capacity_bytes_ */) - 1) * CHAR_BIT, + inplace_size_rounding = size_t(inplace_storage_size_rounding) - 1, + inplace_size = + (sizeof(stub_allocated_holder) + extra_inplace_storage + inplace_size_rounding) & ~inplace_size_rounding }; - constexpr byte inplace_lastbyte() const noexcept { return inplace_[sizeof(bin) - 1]; } - MDBX_CXX17_CONSTEXPR byte &inplace_lastbyte() noexcept { return inplace_[sizeof(bin) - 1]; } + struct capacity_holder { + byte pad_[inplace_size - sizeof(allocator_pointer)]; + size_t bytes_; + }; + + struct inplace_flag_holder { + byte buffer_[inplace_size - sizeof(byte)]; + byte lastbyte_; + }; + + allocator_pointer allocated_ptr_; + capacity_holder capacity_; + inplace_flag_holder inplace_; + + static constexpr bool is_suitable_for_inplace(size_t capacity_bytes) noexcept { + static_assert((size_t(reservation_policy::inplace_storage_size_rounding) & + (size_t(reservation_policy::inplace_storage_size_rounding) - 1)) == 0, + "CAPACITY_POLICY::inplace_storage_size_rounding must be power of 2"); + static_assert(sizeof(bin) == sizeof(inplace_) && sizeof(bin) == sizeof(capacity_), "WTF?"); + return capacity_bytes < sizeof(bin); + } constexpr bool is_inplace() const noexcept { static_assert(size_t(inplace_signature_limit) > size_t(max_capacity), "WTF?"); static_assert(std::numeric_limits::max() - (std::numeric_limits::max() >> CHAR_BIT) == inplace_signature_limit, "WTF?"); - return inplace_lastbyte() == lastbyte_inplace_signature; + return inplace_.lastbyte_ == lastbyte_inplace_signature; } constexpr bool is_allocated() const noexcept { return !is_inplace(); } @@ -1571,26 +1590,27 @@ private: if (destroy_ptr) { MDBX_CONSTEXPR_ASSERT(is_allocated()); /* properly destroy allocator::pointer */ - allocated_.~allocated(); + allocated_ptr_.~allocator_pointer(); } if (::std::is_trivial::value) /* workaround for "uninitialized" warning from some compilers */ - memset(&allocated_.ptr_, 0, sizeof(allocated_.ptr_)); - inplace_lastbyte() = lastbyte_inplace_signature; - MDBX_CONSTEXPR_ASSERT(is_inplace() && address() == inplace_ && is_suitable_for_inplace(capacity())); + memset(&allocated_ptr_, 0, sizeof(allocated_ptr_)); + inplace_.lastbyte_ = lastbyte_inplace_signature; + MDBX_CONSTEXPR_ASSERT(is_inplace() && address() == inplace_.buffer_ && is_suitable_for_inplace(capacity())); return address(); } template MDBX_CXX17_CONSTEXPR byte *make_allocated(allocator_pointer ptr, size_t capacity_bytes) noexcept { MDBX_CONSTEXPR_ASSERT(inplace_signature_limit > capacity_bytes); - if (construct_ptr) + if (construct_ptr) { /* properly construct allocator::pointer */ - new (&allocated_) allocated(ptr, capacity_bytes); - else { + new (&allocated_ptr_) allocator_pointer(ptr); + capacity_.bytes_ = capacity_bytes; + } else { MDBX_CONSTEXPR_ASSERT(is_allocated()); - allocated_.ptr_ = ptr; - allocated_.capacity_bytes_ = capacity_bytes; + allocated_ptr_ = ptr; + capacity_.bytes_ = capacity_bytes; } MDBX_CONSTEXPR_ASSERT(is_allocated() && address() == to_address(ptr) && capacity() == capacity_bytes); return address(); @@ -1608,16 +1628,17 @@ private: MDBX_CXX20_CONSTEXPR ~bin() { if (is_allocated()) /* properly destroy allocator::pointer */ - allocated_.~allocated(); + allocated_ptr_.~allocator_pointer(); } MDBX_CXX20_CONSTEXPR bin(bin &&ditto) noexcept { if (ditto.is_inplace()) { // micro-optimization: don't use make_inplace<> here // since memcpy() will copy the flag. - memcpy(inplace_, ditto.inplace_, sizeof(inplace_)); + memcpy(&inplace_, &ditto.inplace_, sizeof(inplace_)); MDBX_CONSTEXPR_ASSERT(is_inplace()); } else { - new (&allocated_) allocated(::std::move(ditto.allocated_)); + new (&allocated_ptr_) allocator_pointer(::std::move(ditto.allocated_ptr_)); + capacity_.bytes_ = ditto.capacity_.bytes_; ditto.make_inplace(); MDBX_CONSTEXPR_ASSERT(is_allocated()); } @@ -1629,13 +1650,13 @@ private: // since memcpy() will copy the flag. if (is_allocated()) /* properly destroy allocator::pointer */ - allocated_.~allocated(); - memcpy(inplace_, ditto.inplace_, sizeof(inplace_)); + allocated_ptr_.~allocator_pointer(); + memcpy(&inplace_, &ditto.inplace_, sizeof(inplace_)); MDBX_CONSTEXPR_ASSERT(is_inplace()); } else if (is_inplace()) - make_allocated(ditto.allocated_.ptr_, ditto.allocated_.capacity_bytes_); + make_allocated(ditto.allocated_ptr_, ditto.capacity_.bytes_); else - make_allocated(ditto.allocated_.ptr_, ditto.allocated_.capacity_bytes_); + make_allocated(ditto.allocated_ptr_, ditto.capacity_.bytes_); return *this; } @@ -1656,12 +1677,12 @@ private: } constexpr const byte *address() const noexcept { - return is_inplace() ? inplace_ : static_cast(to_address(allocated_.ptr_)); + return is_inplace() ? inplace_.buffer_ : static_cast(to_address(allocated_ptr_)); } MDBX_CXX17_CONSTEXPR byte *address() noexcept { - return is_inplace() ? inplace_ : static_cast(to_address(allocated_.ptr_)); + return is_inplace() ? inplace_.buffer_ : static_cast(to_address(allocated_ptr_)); } - constexpr size_t capacity() const noexcept { return is_inplace() ? sizeof(bin) - 1 : allocated_.capacity_bytes_; } + constexpr size_t capacity() const noexcept { return is_inplace() ? sizeof(bin) - 1 : capacity_.bytes_; } } bin_; MDBX_CXX20_CONSTEXPR void *init(size_t capacity) { @@ -1678,7 +1699,7 @@ private: MDBX_CXX20_CONSTEXPR void release() noexcept { if (bin_.is_allocated()) { - deallocate_storage(bin_.allocated_.ptr_, bin_.allocated_.capacity_bytes_); + deallocate_storage(bin_.allocated_ptr_, bin_.capacity_.bytes_); bin_.template make_inplace(); } } @@ -1709,7 +1730,7 @@ private: if (bin::is_suitable_for_inplace(new_capacity)) { assert(bin_.is_allocated()); - const auto old_allocated = ::std::move(bin_.allocated_.ptr_); + const auto old_allocated = ::std::move(bin_.allocated_ptr_); byte *const new_place = bin_.template make_inplace() + wanna_headroom; if (MDBX_LIKELY(length)) MDBX_CXX20_LIKELY memcpy(new_place, content, length); @@ -1727,7 +1748,7 @@ private: return new_place; } - const auto old_allocated = ::std::move(bin_.allocated_.ptr_); + const auto old_allocated = ::std::move(bin_.allocated_ptr_); if (external_content) deallocate_storage(old_allocated, old_capacity); const auto pair = allocate_storage(new_capacity); From ee6843062d362295aa04c34800e83acc4b6001dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 13 Mar 2025 20:13:07 +0300 Subject: [PATCH 092/181] =?UTF-8?q?mdbx++:=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D1=80=D0=B8=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=81=D0=B5=20=D1=82=D1=80=D0=B0=D0=BD=D0=B7?= =?UTF-8?q?=D0=B0=D0=BA=D1=86=D0=B8=D0=B8=20=D1=83=20=D0=BE=D1=82=D1=81?= =?UTF-8?q?=D0=BE=D0=B5=D0=B4=D0=B8=D0=BD=D1=91=D0=BD=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=BA=D1=83=D1=80=D1=81=D0=BE=D1=80=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 1 - 1 file changed, 1 deletion(-) diff --git a/mdbx.h++ b/mdbx.h++ index 97120b3f..e6186b1e 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -6206,7 +6206,6 @@ inline void cursor::unbind() { error::success_or_throw(::mdbx_cursor_unbind(hand inline txn cursor::txn() const { MDBX_txn *txn = ::mdbx_cursor_txn(handle_); - error::throw_on_nullptr(txn, MDBX_EINVAL); return ::mdbx::txn(txn); } From 438d185250927d6ac6589b5011d26a8affbf28de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 8 Mar 2025 23:40:02 +0300 Subject: [PATCH 093/181] =?UTF-8?q?mdbx++:=20=D0=BF=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B5=20(=D0=B2=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=BD=D0=BE)=20=D0=BD=D0=B5=D0=B8=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D1=83=D0=B5=D0=BC=D0=BE=D0=B3=D0=BE=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mdbx.c++ | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/mdbx.c++ b/src/mdbx.c++ index 63f56190..7b4d8aa1 100644 --- a/src/mdbx.c++ +++ b/src/mdbx.c++ @@ -63,8 +63,8 @@ class trouble_location { #endif public: - MDBX_CXX11_CONSTEXPR trouble_location(unsigned line, const char *condition, - const char *function, const char *filename) + MDBX_CXX11_CONSTEXPR trouble_location(unsigned line, const char *condition, const char *function, + const char *filename) : #if TROUBLE_PROVIDE_LINENO line_(line) @@ -133,7 +133,7 @@ public: //------------------------------------------------------------------------------ -__cold std::string format_va(const char *fmt, va_list ap) { +__cold std::string format_va(const char *fmt, va_list ap) { va_list ones; va_copy(ones, ap); #ifdef _MSC_VER @@ -146,15 +146,14 @@ __cold std::string format_va(const char *fmt, va_list ap) { result.reserve(size_t(needed + 1)); result.resize(size_t(needed), '\0'); assert(int(result.capacity()) > needed); - int actual = vsnprintf(const_cast(result.data()), result.capacity(), - fmt, ones); + int actual = vsnprintf(const_cast(result.data()), result.capacity(), fmt, ones); assert(actual == needed); (void)actual; va_end(ones); return result; } -__cold std::string format(const char *fmt, ...) { +__cold std::string format(const char *fmt, ...) { va_list ap; va_start(ap, fmt); std::string result = format_va(fmt, ap); @@ -175,17 +174,14 @@ public: virtual ~bug() noexcept; }; -__cold bug::bug(const trouble_location &location) noexcept - : std::runtime_error(format("mdbx.bug: %s.%s at %s:%u", location.function(), - location.condition(), location.filename(), - location.line())), +__cold bug::bug(const trouble_location &location) noexcept + : std::runtime_error(format("mdbx.bug: %s.%s at %s:%u", location.function(), location.condition(), + location.filename(), location.line())), location_(location) {} -__cold bug::~bug() noexcept {} +__cold bug::~bug() noexcept {} -[[noreturn]] __cold void raise_bug(const trouble_location &what_and_where) { - throw bug(what_and_where); -} +[[maybe_unused, noreturn]] __cold void raise_bug(const trouble_location &what_and_where) { throw bug(what_and_where); } #define RAISE_BUG(line, condition, function, file) \ do { \ @@ -193,6 +189,7 @@ __cold bug::~bug() noexcept {} raise_bug(bug); \ } while (0) +#undef ENSURE #define ENSURE(condition) \ do \ if (MDBX_UNLIKELY(!(condition))) \ From 6c8047a40240f670174168a8da7b37b90db061fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 10 Mar 2025 23:19:48 +0300 Subject: [PATCH 094/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=B5=D1=80=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20`mdbx=5Ftxn=5Frelease=5F?= =?UTF-8?q?all=5Fcursors=5Fex()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 26 ++++++++++-------------- src/api-cursor.c | 51 +++++++++++++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/mdbx.h b/mdbx.h index ecaa3e18..fdc9c6e5 100644 --- a/mdbx.h +++ b/mdbx.h @@ -5269,15 +5269,12 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); * \retval MDBX_EINVAL An invalid parameter was specified. */ LIBMDBX_API int mdbx_cursor_close2(MDBX_cursor *cursor); -/** \brief Unbind or closes all cursors of a given transaction. +/** \brief Unbind or closes all cursors of a given transaction and of all + * its parent transactions if ones are. * \ingroup c_cursors * - * Unbinds either closes all cursors associated (opened or renewed) with - * a given transaction in a bulk with minimal overhead. - * - * A transaction should not be nested, since in this case no way to restore - * state if this nested transaction will be aborted, nor impossible to define - * the expected behavior. + * Unbinds either closes all cursors associated (opened, renewed or binded) with + * the given transaction in a bulk with minimal overhead. * * \see mdbx_cursor_unbind() * \see mdbx_cursor_close() @@ -5292,19 +5289,16 @@ LIBMDBX_API int mdbx_cursor_close2(MDBX_cursor *cursor); * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. - * \retval MDBX_BAD_TXN Given transaction is invalid, nested or has + * \retval MDBX_BAD_TXN Given transaction is invalid or has * a child/nested transaction transaction. */ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count); -/** \brief Unbind or closes all cursors of a given transaction. +/** \brief Unbind or closes all cursors of a given transaction and of all + * its parent transactions if ones are. * \ingroup c_cursors * - * Unbinds either closes all cursors associated (opened or renewed) with - * a given transaction in a bulk with minimal overhead. - * - * A transaction should not be nested, since in this case no way to restore - * state if this nested transaction will be aborted, nor impossible to define - * the expected behavior. + * Unbinds either closes all cursors associated (opened, renewed or binded) with + * the given transaction in a bulk with minimal overhead. * * \see mdbx_cursor_unbind() * \see mdbx_cursor_close() @@ -5317,7 +5311,7 @@ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. - * \retval MDBX_BAD_TXN Given transaction is invalid, nested or has + * \retval MDBX_BAD_TXN Given transaction is invalid or has * a child/nested transaction transaction. */ LIBMDBX_INLINE_API(int, mdbx_txn_release_all_cursors, (const MDBX_txn *txn, bool unbind)) { return mdbx_txn_release_all_cursors_ex(txn, unbind, NULL); diff --git a/src/api-cursor.c b/src/api-cursor.c index b930f36c..d4ce3beb 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -234,28 +234,43 @@ int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *co int rc = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(txn->parent)) { - rc = MDBX_BAD_TXN; - ERROR("%s, err %d", "must not unbind or close cursors for a nested txn", rc); - return rc; - } size_t n = 0; - TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) { - while (txn->cursors[i]) { - ++n; - MDBX_cursor *mc = txn->cursors[i]; - ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup); - txn->cursors[i] = mc->next; - mc->next = mc; - mc->signature = cur_signature_ready4dispose; - cursor_drown((cursor_couple_t *)mc); - if (!unbind) { - mc->signature = 0; - osal_free(mc); + do { + TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) { + MDBX_cursor *mc = txn->cursors[i], *next = nullptr; + if (mc) { + txn->cursors[i] = nullptr; + do { + next = mc->next; + if (mc->signature == cur_signature_live) { + mc->signature = cur_signature_wait4eot; + cursor_drown((cursor_couple_t *)mc); + } else + ENSURE(nullptr, mc->signature == cur_signature_wait4eot); + if (mc->backup) { + MDBX_cursor *bk = mc->backup; + mc->next = bk->next; + mc->backup = bk->backup; + mc->backup = nullptr; + bk->signature = 0; + bk = bk->next; + osal_free(bk); + } else { + mc->signature = cur_signature_ready4dispose; + mc->next = mc; + ++n; + if (!unbind) { + mc->signature = 0; + osal_free(mc); + } + } + } while ((mc = next) != nullptr); } } - } + txn = txn->parent; + } while (txn); + if (count) *count = n; return MDBX_SUCCESS; From aeac971f0b36b4521dbae902e98439fb3b2c8665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 15 Mar 2025 22:00:36 +0300 Subject: [PATCH 095/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=B5=D1=80=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D0=B8=20=D0=BA=D1=83=D1=80=D1=81=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=BD=D0=B0=20=D0=B2=D1=85=D0=BE=D0=B4=D0=B5=20?= =?UTF-8?q?API-=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B9=20=D1=81=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=D0=BC=20`cursor=5Fcheck()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cold.c | 2 +- src/api-cursor.c | 155 ++++++++++++--------------------------- src/api-range-estimate.c | 34 ++++----- src/api-txn-data.c | 57 ++++++-------- src/api-txn.c | 12 ++- src/cogs.h | 14 +--- src/cursor.c | 30 ++++++++ src/cursor.h | 15 ++++ src/txn.c | 5 +- 9 files changed, 149 insertions(+), 175 deletions(-) diff --git a/src/api-cold.c b/src/api-cold.c index 8a8c8588..57e1d667 100644 --- a/src/api-cold.c +++ b/src/api-cold.c @@ -141,7 +141,7 @@ __cold int mdbx_env_warmup(const MDBX_env *env, const MDBX_txn *txn, MDBX_warmup return LOG_IFERR(MDBX_EINVAL); if (txn) { - int err = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR); + int err = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_ERROR); if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); } diff --git a/src/api-cursor.c b/src/api-cursor.c index d4ce3beb..d5a71e5a 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -27,18 +27,12 @@ int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) { } int mdbx_cursor_reset(MDBX_cursor *mc) { - if (unlikely(!mc)) - return LOG_IFERR(MDBX_EINVAL); + int rc = cursor_check(mc, MDBX_TXN_FINISHED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); - if (likely(mc->signature == cur_signature_live)) { - cursor_reset((cursor_couple_t *)mc); - return MDBX_SUCCESS; - } - - if (likely(mc->signature == cur_signature_ready4dispose)) - return MDBX_SUCCESS; - - return LOG_IFERR(MDBX_EBADSIGN); + cursor_reset((cursor_couple_t *)mc); + return MDBX_SUCCESS; } int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { @@ -50,17 +44,17 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { return LOG_IFERR(rc); } - int rc = check_txn(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - - rc = dbi_check(txn, dbi); + int rc = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); if (unlikely(dbi == FREE_DBI && !(txn->flags & MDBX_TXN_RDONLY))) return LOG_IFERR(MDBX_EACCESS); + rc = dbi_check(txn, dbi); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + if (unlikely(mc->backup)) /* Cursor from parent transaction */ LOG_IFERR(MDBX_EINVAL); @@ -200,12 +194,11 @@ int mdbx_cursor_close2(MDBX_cursor *mc) { } int mdbx_cursor_copy(const MDBX_cursor *src, MDBX_cursor *dest) { - if (unlikely(!src)) - return LOG_IFERR(MDBX_EINVAL); - if (unlikely(src->signature != cur_signature_live)) - return LOG_IFERR((src->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check(src, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); - int rc = mdbx_cursor_bind(src->txn, dest, cursor_dbi(src)); + rc = mdbx_cursor_bind(src->txn, dest, cursor_dbi(src)); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -278,15 +271,16 @@ int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *co int mdbx_cursor_compare(const MDBX_cursor *l, const MDBX_cursor *r, bool ignore_multival) { const int incomparable = INT16_MAX + 1; + if (unlikely(!l)) return r ? -incomparable * 9 : 0; else if (unlikely(!r)) return incomparable * 9; - if (unlikely(l->signature != cur_signature_live)) - return (r->signature == cur_signature_live) ? -incomparable * 8 : 0; - if (unlikely(r->signature != cur_signature_live)) - return (l->signature == cur_signature_live) ? incomparable * 8 : 0; + if (unlikely(cursor_check_pure(l) != MDBX_SUCCESS)) + return (cursor_check_pure(r) == MDBX_SUCCESS) ? -incomparable * 8 : 0; + if (unlikely(cursor_check_pure(r) != MDBX_SUCCESS)) + return (cursor_check_pure(l) == MDBX_SUCCESS) ? incomparable * 8 : 0; if (unlikely(l->clc != r->clc)) { if (l->txn->env != r->txn->env) @@ -352,13 +346,7 @@ int mdbx_cursor_compare(const MDBX_cursor *l, const MDBX_cursor *r, bool ignore_ } int mdbx_cursor_count_ex(const MDBX_cursor *mc, size_t *count, MDBX_stat *ns, size_t bytes) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_ro(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); @@ -408,11 +396,9 @@ int mdbx_cursor_count(const MDBX_cursor *mc, size_t *count) { } int mdbx_cursor_on_first(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); for (intptr_t i = 0; i <= mc->top; ++i) { if (mc->ki[i]) @@ -423,11 +409,9 @@ int mdbx_cursor_on_first(const MDBX_cursor *mc) { } int mdbx_cursor_on_first_dup(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); if (is_filled(mc) && mc->subcur) { mc = &mc->subcur->cursor; @@ -441,11 +425,9 @@ int mdbx_cursor_on_first_dup(const MDBX_cursor *mc) { } int mdbx_cursor_on_last(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); for (intptr_t i = 0; i <= mc->top; ++i) { size_t nkeys = page_numkeys(mc->pg[i]); @@ -457,11 +439,9 @@ int mdbx_cursor_on_last(const MDBX_cursor *mc) { } int mdbx_cursor_on_last_dup(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); if (is_filled(mc) && mc->subcur) { mc = &mc->subcur->cursor; @@ -476,29 +456,18 @@ int mdbx_cursor_on_last_dup(const MDBX_cursor *mc) { } int mdbx_cursor_eof(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); return is_eof(mc) ? MDBX_RESULT_TRUE : MDBX_RESULT_FALSE; } int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, MDBX_cursor_op op) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_ro(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(cursor_dbi_changed(mc))) - return LOG_IFERR(MDBX_BAD_DBI); - return LOG_IFERR(cursor_ops(mc, key, data, op)); } @@ -623,19 +592,13 @@ int mdbx_cursor_get_batch(MDBX_cursor *mc, size_t *count, MDBX_val *pairs, size_ return LOG_IFERR(MDBX_EINVAL); *count = 0; - if (unlikely(mc == nullptr || limit < 4 || limit > INTPTR_MAX - 2)) + if (unlikely(limit < 4 || limit > INTPTR_MAX - 2)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_ro(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(cursor_dbi_changed(mc))) - return LOG_IFERR(MDBX_BAD_DBI); - if (unlikely(mc->subcur)) return LOG_IFERR(MDBX_INCOMPATIBLE) /* must be a non-dupsort table */; @@ -704,11 +667,9 @@ bailout: /*----------------------------------------------------------------------------*/ int mdbx_cursor_set_userctx(MDBX_cursor *mc, void *ctx) { - if (unlikely(!mc)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_ready4dispose && mc->signature != cur_signature_live)) - return LOG_IFERR(MDBX_EBADSIGN); + int rc = cursor_check(mc, 0); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); cursor_couple_t *couple = container_of(mc, cursor_couple_t, outer); couple->userctx = ctx; @@ -746,21 +707,13 @@ MDBX_dbi mdbx_cursor_dbi(const MDBX_cursor *mc) { /*----------------------------------------------------------------------------*/ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, MDBX_put_flags_t flags) { - if (unlikely(mc == nullptr || key == nullptr || data == nullptr)) + if (unlikely(key == nullptr || data == nullptr)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn_rw(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_rw(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(cursor_dbi_changed(mc))) - return LOG_IFERR(MDBX_BAD_DBI); - - cASSERT(mc, cursor_is_tracked(mc)); - /* Check this first so counter will always be zero on any early failures. */ if (unlikely(flags & MDBX_MULTIPLE)) { if (unlikely(flags & MDBX_RESERVE)) @@ -785,35 +738,21 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, MDBX_p data->iov_base = nullptr; } - if (unlikely(mc->txn->flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED))) - return LOG_IFERR((mc->txn->flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN); - return LOG_IFERR(cursor_put_checklen(mc, key, data, flags)); } int mdbx_cursor_del(MDBX_cursor *mc, MDBX_put_flags_t flags) { - if (unlikely(!mc)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn_rw(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_rw(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(cursor_dbi_changed(mc))) - return LOG_IFERR(MDBX_BAD_DBI); - return LOG_IFERR(cursor_del(mc, flags)); } __cold int mdbx_cursor_ignord(MDBX_cursor *mc) { - if (unlikely(!mc)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check(mc, 0); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); mc->checking |= z_ignord; if (mc->subcur) diff --git a/src/api-range-estimate.c b/src/api-range-estimate.c index 5356d4da..56564da0 100644 --- a/src/api-range-estimate.c +++ b/src/api-range-estimate.c @@ -16,12 +16,6 @@ __hot static int cursor_diff(const MDBX_cursor *const __restrict x, const MDBX_c r->level = 0; r->root_nkeys = 0; - if (unlikely(x->signature != cur_signature_live)) - return (x->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN; - - if (unlikely(y->signature != cur_signature_live)) - return (y->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN; - int rc = check_txn(x->txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -146,12 +140,20 @@ __hot static ptrdiff_t estimate(const tree_t *tree, diff_t *const __restrict dr) * Range-Estimation API */ __hot int mdbx_estimate_distance(const MDBX_cursor *first, const MDBX_cursor *last, ptrdiff_t *distance_items) { - if (unlikely(first == nullptr || last == nullptr || distance_items == nullptr)) + if (unlikely(!distance_items)) return LOG_IFERR(MDBX_EINVAL); + int rc = cursor_check_pure(first); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + + rc = cursor_check_pure(last); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + *distance_items = 0; diff_t dr; - int rc = cursor_diff(last, first, &dr); + rc = cursor_diff(last, first, &dr); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); @@ -172,14 +174,10 @@ __hot int mdbx_estimate_distance(const MDBX_cursor *first, const MDBX_cursor *la __hot int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data, MDBX_cursor_op move_op, ptrdiff_t *distance_items) { - if (unlikely(cursor == nullptr || distance_items == nullptr || move_op == MDBX_GET_CURRENT || - move_op == MDBX_GET_MULTIPLE)) + if (unlikely(!distance_items || move_op == MDBX_GET_CURRENT || move_op == MDBX_GET_MULTIPLE)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(cursor->signature != cur_signature_live)) - return LOG_IFERR((cursor->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn(cursor->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_ro(cursor); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); @@ -232,10 +230,6 @@ __hot int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val __hot 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 *size_items) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!size_items)) return LOG_IFERR(MDBX_EINVAL); @@ -248,6 +242,10 @@ __hot int mdbx_estimate_range(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val if (unlikely(begin_key == MDBX_EPSILON && end_key == MDBX_EPSILON)) return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + cursor_couple_t begin; /* LY: first, initialize cursor to refresh a DB in case it have DB_STALE */ rc = cursor_init(&begin.outer, txn, dbi); diff --git a/src/api-txn-data.c b/src/api-txn-data.c index 76bdf32a..2be54df8 100644 --- a/src/api-txn-data.c +++ b/src/api-txn-data.c @@ -51,15 +51,15 @@ __cold int mdbx_dbi_dupsort_depthmask(const MDBX_txn *txn, MDBX_dbi dbi, uint32_ } int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); + if (unlikely(canary == nullptr)) + return LOG_IFERR(MDBX_EINVAL); + + int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); if (unlikely(rc != MDBX_SUCCESS)) { memset(canary, 0, sizeof(*canary)); return LOG_IFERR(rc); } - if (unlikely(canary == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - *canary = txn->canary; return MDBX_SUCCESS; } @@ -68,13 +68,13 @@ int mdbx_get(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *d DKBUF_DEBUG; DEBUG("===> get db %u key [%s]", dbi, DKEY_DEBUG(key)); + if (unlikely(!key || !data)) + return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn(txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(!key || !data)) - return LOG_IFERR(MDBX_EINVAL); - cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) @@ -84,15 +84,12 @@ int mdbx_get(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *d } int mdbx_get_equal_or_great(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!key || !data)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(txn->flags & MDBX_TXN_BLOCKED)) - return LOG_IFERR(MDBX_BAD_TXN); + int rc = check_txn(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); @@ -106,13 +103,13 @@ int mdbx_get_ex(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data DKBUF_DEBUG; DEBUG("===> get db %u key [%s]", dbi, DKEY_DEBUG(key)); + if (unlikely(!key || !data)) + return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn(txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(!key || !data)) - return LOG_IFERR(MDBX_EINVAL); - cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) @@ -179,7 +176,7 @@ int mdbx_canary_put(MDBX_txn *txn, const MDBX_canary *canary) { * расположен в той-же странице памяти, в том числе для многостраничных * P_LARGE страниц с длинными данными. */ int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); + int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); @@ -215,18 +212,15 @@ int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) { } int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, const MDBX_val *data) { - int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!key)) return LOG_IFERR(MDBX_EINVAL); if (unlikely(dbi <= FREE_DBI)) return LOG_IFERR(MDBX_BAD_DBI); - if (unlikely(txn->flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED))) - return LOG_IFERR((txn->flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN); + int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); @@ -254,10 +248,6 @@ int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, const MDBX_val *d } int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, MDBX_put_flags_t flags) { - int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!key || !data)) return LOG_IFERR(MDBX_EINVAL); @@ -268,8 +258,9 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, M MDBX_APPENDDUP | MDBX_CURRENT | MDBX_MULTIPLE))) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(txn->flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED))) - return LOG_IFERR((txn->flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN); + int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); @@ -330,10 +321,6 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, M 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 LOG_IFERR(rc); - if (unlikely(!key || !old_data || old_data == new_data)) return LOG_IFERR(MDBX_EINVAL); @@ -350,6 +337,10 @@ int mdbx_replace_ex(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val * MDBX_APPENDDUP | MDBX_CURRENT))) return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) diff --git a/src/api-txn.c b/src/api-txn.c index d38c5b0e..04feabea 100644 --- a/src/api-txn.c +++ b/src/api-txn.c @@ -9,7 +9,7 @@ __attribute__((__no_sanitize_thread__, __noinline__)) #endif int mdbx_txn_straggler(const MDBX_txn *txn, int *percent) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); + int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); if (likely(rc == MDBX_SUCCESS)) rc = check_env(txn->env, true); if (unlikely(rc != MDBX_SUCCESS)) @@ -217,9 +217,13 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, M MDBX_txn *txn = nullptr; if (parent) { /* Nested transactions: Max 1 child, write txns only, no writemap */ - rc = check_txn_rw(parent, MDBX_TXN_RDONLY | MDBX_WRITEMAP | MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) { - if (rc == MDBX_BAD_TXN && (parent->flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)) == 0) { + rc = check_txn(parent, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + + if (unlikely(parent->flags & (MDBX_TXN_RDONLY | MDBX_WRITEMAP))) { + rc = MDBX_BAD_TXN; + if ((parent->flags & MDBX_TXN_RDONLY) == 0) { ERROR("%s mode is incompatible with nested transactions", "MDBX_WRITEMAP"); rc = MDBX_INCOMPATIBLE; } diff --git a/src/cogs.h b/src/cogs.h index 7e814e7b..498e92b7 100644 --- a/src/cogs.h +++ b/src/cogs.h @@ -416,10 +416,11 @@ static __always_inline int check_txn(const MDBX_txn *txn, int bad_bits) { return MDBX_EPERM; if (unlikely(txn->flags & bad_bits)) { + if ((bad_bits & MDBX_TXN_RDONLY) && unlikely(txn->flags & MDBX_TXN_RDONLY)) + return MDBX_EACCESS; if ((bad_bits & MDBX_TXN_PARKED) == 0) return MDBX_BAD_TXN; - else - return txn_check_badbits_parked(txn, bad_bits); + return txn_check_badbits_parked(txn, bad_bits); } } @@ -437,14 +438,7 @@ static __always_inline int check_txn(const MDBX_txn *txn, int bad_bits) { } static inline int check_txn_rw(const MDBX_txn *txn, int bad_bits) { - int err = check_txn(txn, bad_bits & ~MDBX_TXN_PARKED); - if (unlikely(err)) - return err; - - if (unlikely(txn->flags & MDBX_TXN_RDONLY)) - return MDBX_EACCESS; - - return MDBX_SUCCESS; + return check_txn(txn, (bad_bits | MDBX_TXN_RDONLY) & ~MDBX_TXN_PARKED); } /*----------------------------------------------------------------------------*/ diff --git a/src/cursor.c b/src/cursor.c index 43f192a2..99139572 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -2331,3 +2331,33 @@ __hot int cursor_ops(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, const MDBX_ return MDBX_EINVAL; } } + +int cursor_check(const MDBX_cursor *mc, int txn_bad_bits) { + if (unlikely(mc == nullptr)) + return MDBX_EINVAL; + + if (unlikely(mc->signature != cur_signature_live)) { + if (mc->signature != cur_signature_ready4dispose) + return MDBX_EBADSIGN; + return (txn_bad_bits > MDBX_TXN_FINISHED) ? MDBX_EINVAL : MDBX_SUCCESS; + } + + /* проверяем что курсор в связном списке для отслеживания, исключение допускается только для read-only операций для + * служебных/временных курсоров на стеке. */ + MDBX_MAYBE_UNUSED char stack_top[sizeof(void *)]; + cASSERT(mc, cursor_is_tracked(mc) || (!(txn_bad_bits & MDBX_TXN_RDONLY) && stack_top < (char *)mc && + (char *)mc - stack_top < (ptrdiff_t)globals.sys_pagesize * 4)); + + if (txn_bad_bits) { + int rc = check_txn(mc->txn, txn_bad_bits); + if (unlikely(rc != MDBX_SUCCESS)) { + cASSERT(mc, rc != MDBX_RESULT_TRUE); + return rc; + } + + if (unlikely(cursor_dbi_changed(mc))) + return MDBX_BAD_DBI; + } + + return MDBX_SUCCESS; +} diff --git a/src/cursor.h b/src/cursor.h index f9d4ea82..d8100999 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -292,6 +292,21 @@ MDBX_NOTHROW_PURE_FUNCTION static inline bool check_leaf_type(const MDBX_cursor return (((page_type(mp) ^ mc->checking) & (z_branch | z_leaf | z_largepage | z_dupfix)) == 0); } +MDBX_INTERNAL int cursor_check(const MDBX_cursor *mc, int txn_bad_bits); + +/* без необходимости доступа к данным, без активации припаркованных транзакций. */ +static inline int cursor_check_pure(const MDBX_cursor *mc) { + return cursor_check(mc, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); +} + +/* для чтения данных, с активацией припаркованных транзакций. */ +static inline int cursor_check_ro(const MDBX_cursor *mc) { return cursor_check(mc, MDBX_TXN_BLOCKED); } + +/* для записи данных. */ +static inline int cursor_check_rw(const MDBX_cursor *mc) { + return cursor_check(mc, (MDBX_TXN_BLOCKED - MDBX_TXN_PARKED) | MDBX_TXN_RDONLY); +} + MDBX_INTERNAL MDBX_cursor *cursor_eot(MDBX_cursor *cursor, MDBX_txn *txn); MDBX_INTERNAL int cursor_shadow(MDBX_cursor *cursor, MDBX_txn *nested, const size_t dbi); diff --git a/src/txn.c b/src/txn.c index 09c4a3d0..e2cc53f3 100644 --- a/src/txn.c +++ b/src/txn.c @@ -388,7 +388,10 @@ int txn_check_badbits_parked(const MDBX_txn *txn, int bad_bits) { * - но при распарковке поломанные транзакции завершаются. * - получается что транзакцию можно припарковать, потом поломать вызвав * mdbx_txn_break(), но далее любое её использование приведет к завершению - * при распарковке. */ + * при распарковке. + * + * Поэтому для припаркованных транзакций возвращается ошибка если не-включена + * авто-распарковка, либо есть другие плохие биты. */ if ((txn->flags & (bad_bits | MDBX_TXN_AUTOUNPARK)) != (MDBX_TXN_PARKED | MDBX_TXN_AUTOUNPARK)) return LOG_IFERR(MDBX_BAD_TXN); From dcf35e530604114e8f1512679408defc4efc8128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 15 Mar 2025 22:12:42 +0300 Subject: [PATCH 096/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B7=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BA=D1=83=D1=80=D1=81=D0=BE?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=20=D0=B2=D0=BE=20=D0=B2=D0=BB=D0=BE=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D1=8B=D1=85=20=D1=82=D1=80=D0=B0=D0=BD=D0=B7?= =?UTF-8?q?=D0=B0=D0=BA=D1=86=D0=B8=D1=8F=D1=85.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cursor.c | 6 ++---- src/cursor.c | 13 ++++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/api-cursor.c b/src/api-cursor.c index d5a71e5a..4489a64f 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -691,11 +691,9 @@ MDBX_txn *mdbx_cursor_txn(const MDBX_cursor *mc) { if (unlikely(!mc || mc->signature != cur_signature_live)) return nullptr; MDBX_txn *txn = mc->txn; - if (unlikely(!txn || txn->signature != txn_signature)) + if (unlikely(!txn || txn->signature != txn_signature || (txn->flags & MDBX_TXN_FINISHED))) return nullptr; - if (unlikely(txn->flags & MDBX_TXN_FINISHED)) - return nullptr; - return txn; + return (txn->flags & MDBX_TXN_HAS_CHILD) ? txn->env->txn : txn; } MDBX_dbi mdbx_cursor_dbi(const MDBX_cursor *mc) { diff --git a/src/cursor.c b/src/cursor.c index 99139572..ddee3df7 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -2349,14 +2349,21 @@ int cursor_check(const MDBX_cursor *mc, int txn_bad_bits) { (char *)mc - stack_top < (ptrdiff_t)globals.sys_pagesize * 4)); if (txn_bad_bits) { - int rc = check_txn(mc->txn, txn_bad_bits); + int rc = check_txn(mc->txn, txn_bad_bits & ~MDBX_TXN_HAS_CHILD); if (unlikely(rc != MDBX_SUCCESS)) { cASSERT(mc, rc != MDBX_RESULT_TRUE); return rc; } - if (unlikely(cursor_dbi_changed(mc))) - return MDBX_BAD_DBI; + if (likely((mc->txn->flags & MDBX_TXN_HAS_CHILD) == 0)) + return likely(!cursor_dbi_changed(mc)) ? MDBX_SUCCESS : MDBX_BAD_DBI; + + cASSERT(mc, (mc->txn->flags & MDBX_TXN_RDONLY) == 0 && mc->txn != mc->txn->env->txn && mc->txn->env->txn); + rc = dbi_check(mc->txn->env->txn, cursor_dbi(mc)); + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + + cASSERT(mc, (mc->txn->flags & MDBX_TXN_RDONLY) == 0 && mc->txn == mc->txn->env->txn); } return MDBX_SUCCESS; From 8ebedde181ad2010eca33585913c02ed4a797d08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 14 Mar 2025 20:07:11 +0300 Subject: [PATCH 097/181] =?UTF-8?q?mdbx++:=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D0=B0=20`=5F=5Fcpp=5Fconcepts=20>=3D=2020200?= =?UTF-8?q?2`=20=D0=B4=D0=BB=D1=8F=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D1=86=D0=B5=D0=BF=D1=82=D0=BE=D0=B2=20C++.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mdbx.h++ b/mdbx.h++ index e6186b1e..55bfc8e9 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -243,7 +243,7 @@ #endif /* MDBX_CXX20_UNLIKELY */ #ifndef MDBX_HAVE_CXX20_CONCEPTS -#if defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L +#if defined(__cpp_concepts) && __cpp_concepts >= 202002L && defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L #include #define MDBX_HAVE_CXX20_CONCEPTS 1 #elif defined(DOXYGEN) From 08d10ad0a19050d3ef07cad8da8c67814bf21ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 9 Mar 2025 17:24:16 +0300 Subject: [PATCH 098/181] =?UTF-8?q?mdbx-tests:=20=D0=B4=D0=BE=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20extra/txn.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/txn.c++ | 539 ++++++++++++++++++++++++--------------------- 1 file changed, 287 insertions(+), 252 deletions(-) diff --git a/test/extra/txn.c++ b/test/extra/txn.c++ index 3a616015..e1abb1e6 100644 --- a/test/extra/txn.c++ +++ b/test/extra/txn.c++ @@ -1,4 +1,5 @@ #include "mdbx.h++" +#include MDBX_CONFIG_H #include @@ -25,267 +26,301 @@ static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int li fprintf(stdout, "%s:%u %s", function, line, msg); } +bool case0(const mdbx::path &path) { + mdbx::env_managed::create_parameters createParameters; + createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, 84 * mdbx::env::geometry::MiB); + + mdbx::env::operate_parameters operateParameters(100, 10); + operateParameters.options.no_sticky_threads = false; + mdbx::env_managed env(path, createParameters, operateParameters); + auto txn = env.start_write(false); + /* mdbx::map_handle testHandle = */ txn.create_map("xyz", mdbx::key_mode::usual, mdbx::value_mode::single); + txn.commit(); + + //------------------------------------- + txn = env.start_write(); + MDBX_txn *c_txn = txn; + int err = mdbx_txn_reset(txn); + assert(err == MDBX_EINVAL); + bool ok = err == MDBX_EINVAL; + + err = mdbx_txn_break(txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + + err = mdbx_txn_commit(txn); + assert(err == MDBX_RESULT_TRUE); + ok = ok && err == MDBX_RESULT_TRUE; + + //------------------------------------- + err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + assert(c_txn == (const MDBX_txn *)txn); + + err = mdbx_txn_break(txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + + err = mdbx_txn_reset(txn); + assert(err == MDBX_EINVAL); + ok = ok && err == MDBX_EINVAL; + + err = mdbx_txn_commit(txn); + assert(err == MDBX_RESULT_TRUE); + ok = ok && err == MDBX_RESULT_TRUE; + + err = mdbx_txn_abort(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + //------------------------------------- + err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + assert(c_txn == (const MDBX_txn *)txn); + txn.commit(); + + err = mdbx_txn_reset(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + err = mdbx_txn_break(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + err = mdbx_txn_abort(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + + //===================================== + + txn = env.start_read(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + txn.make_broken(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + txn.reset_reading(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + txn.abort(); + + //------------------------------------- + + txn = env.start_read(); + txn.reset_reading(); + txn.make_broken(); + txn.abort(); + + //===================================== + + std::latch s(1); + txn = env.start_read(); + c_txn = txn; + + std::thread t([&]() { + s.wait(); +#if MDBX_TXN_CHECKOWNER + err = mdbx_txn_reset(c_txn); + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; + err = mdbx_txn_break(c_txn); + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; + err = mdbx_txn_commit(c_txn); + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; + err = mdbx_txn_abort(c_txn); + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; +#endif /* MDBX_TXN_CHECKOWNER */ + + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); +#if MDBX_TXN_CHECKOWNER + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; +#else + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; +#endif /* MDBX_TXN_CHECKOWNER */ + }); + + s.count_down(); + t.join(); + + return ok; +} + +bool case1(const mdbx::path &path) { + mdbx::env::operate_parameters operateParameters(100, 10); + operateParameters.options.no_sticky_threads = true; + operateParameters.options.nested_write_transactions = true; + mdbx::env_managed env(path, operateParameters); + + //------------------------------------- + auto txn = env.start_write(); + MDBX_txn *c_txn = txn; + int err = mdbx_txn_reset(txn); + assert(err == MDBX_EINVAL); + bool ok = err == MDBX_EINVAL; + + err = mdbx_txn_break(txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + + err = mdbx_txn_commit(txn); + assert(err == MDBX_RESULT_TRUE); + ok = ok && err == MDBX_RESULT_TRUE; + + //------------------------------------- + err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + assert(c_txn == (const MDBX_txn *)txn); + + err = mdbx_txn_break(txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + + err = mdbx_txn_reset(txn); + assert(err == MDBX_EINVAL); + ok = ok && err == MDBX_EINVAL; + + err = mdbx_txn_commit(txn); + assert(err == MDBX_RESULT_TRUE); + ok = ok && err == MDBX_RESULT_TRUE; + + err = mdbx_txn_abort(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + //------------------------------------- + err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + assert(c_txn == (const MDBX_txn *)txn); + txn.commit(); + + err = mdbx_txn_reset(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + err = mdbx_txn_break(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + err = mdbx_txn_abort(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + + //===================================== + + txn = env.start_read(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + txn.make_broken(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + txn.reset_reading(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + txn.abort(); + + //------------------------------------- + + txn = env.start_read(); + txn.reset_reading(); + txn.make_broken(); + txn.abort(); + + //===================================== + + std::latch s1(1), s2(1), s3(1); + txn = env.start_read(); + c_txn = txn; + + std::thread t([&]() { + s1.wait(); + err = mdbx_txn_break(c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + err = mdbx_txn_reset(c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + txn.renew_reading(); + s2.count_down(); + + s3.wait(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + err = mdbx_txn_commit(c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + c_txn = txn; + err = mdbx_txn_commit(c_txn); + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; + err = mdbx_txn_abort(c_txn); + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; + err = mdbx_txn_break(c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + err = mdbx_txn_reset(c_txn); + assert(err == MDBX_EINVAL); + ok = ok && err == MDBX_EINVAL; + }); + + s1.count_down(); + s2.wait(); + txn.commit(); + txn = env.start_write(); + s3.count_down(); + + t.join(); + txn.abort(); + + return ok; +} + +bool case2(const mdbx::path &path, bool no_sticky_threads) { + mdbx::env::operate_parameters operateParameters(100, 10); + operateParameters.options.no_sticky_threads = no_sticky_threads; + mdbx::env_managed env(path, operateParameters); + + std::latch s(1); + std::vector l; + for (size_t n = 0; n < 8; ++n) + l.push_back(std::thread([&]() { + s.wait(); + for (size_t i = 0; i < 1000000; ++i) { + auto txn = env.start_read(); + txn.abort(); + } + })); + + s.count_down(); + for (auto &t : l) + t.join(); + + return true; +} + int main(int argc, const char *argv[]) { (void)argc; (void)argv; - bool ok = true; - int err; mdbx_setup_debug_nofmt(MDBX_LOG_VERBOSE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); mdbx::path path = "test-txn"; mdbx::env::remove(path); - mdbx::env::operate_parameters operateParameters(100, 10); - { - mdbx::env_managed::create_parameters createParameters; - createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, 84 * mdbx::env::geometry::MiB); - - operateParameters.options.no_sticky_threads = false; - mdbx::env_managed env(path, createParameters, operateParameters); - auto txn = env.start_write(false); - /* mdbx::map_handle testHandle = */ txn.create_map("xyz", mdbx::key_mode::usual, mdbx::value_mode::single); - txn.commit(); - - //------------------------------------- - txn = env.start_write(); - MDBX_txn *c_txn = txn; - err = mdbx_txn_reset(txn); - assert(err == MDBX_EINVAL); - ok = ok && err == MDBX_EINVAL; - - err = mdbx_txn_break(txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - - err = mdbx_txn_commit(txn); - assert(err == MDBX_RESULT_TRUE); - ok = ok && err == MDBX_RESULT_TRUE; - - //------------------------------------- - err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - assert(c_txn == (const MDBX_txn *)txn); - - err = mdbx_txn_break(txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - - err = mdbx_txn_reset(txn); - assert(err == MDBX_EINVAL); - ok = ok && err == MDBX_EINVAL; - - err = mdbx_txn_commit(txn); - assert(err == MDBX_RESULT_TRUE); - ok = ok && err == MDBX_RESULT_TRUE; - - err = mdbx_txn_abort(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - //------------------------------------- - err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - assert(c_txn == (const MDBX_txn *)txn); - txn.commit(); - - err = mdbx_txn_reset(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - err = mdbx_txn_break(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - err = mdbx_txn_abort(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - - //===================================== - - txn = env.start_read(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - txn.make_broken(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - txn.reset_reading(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - txn.abort(); - - //------------------------------------- - - txn = env.start_read(); - txn.reset_reading(); - txn.make_broken(); - txn.abort(); - - //===================================== - - std::latch s(1); - txn = env.start_read(); - c_txn = txn; - - std::thread t([&]() { - s.wait(); -#if MDBX_TXN_CHECKOWNER - err = mdbx_txn_reset(c_txn); - assert(err == MDBX_THREAD_MISMATCH); - ok = ok && err == MDBX_THREAD_MISMATCH; - err = mdbx_txn_break(c_txn); - assert(err == MDBX_THREAD_MISMATCH); - ok = ok && err == MDBX_THREAD_MISMATCH; - err = mdbx_txn_commit(c_txn); - assert(err == MDBX_THREAD_MISMATCH); - ok = ok && err == MDBX_THREAD_MISMATCH; - err = mdbx_txn_abort(c_txn); - assert(err == MDBX_THREAD_MISMATCH); - ok = ok && err == MDBX_THREAD_MISMATCH; -#endif /* MDBX_TXN_CHECKOWNER */ - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - }); - - s.count_down(); - t.join(); - } - - //===================================== - //===================================== - - { - operateParameters.options.no_sticky_threads = true; - operateParameters.options.nested_write_transactions = true; - mdbx::env_managed env(path, operateParameters); - - //------------------------------------- - auto txn = env.start_write(); - MDBX_txn *c_txn = txn; - err = mdbx_txn_reset(txn); - assert(err == MDBX_EINVAL); - ok = ok && err == MDBX_EINVAL; - - err = mdbx_txn_break(txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - - err = mdbx_txn_commit(txn); - assert(err == MDBX_RESULT_TRUE); - ok = ok && err == MDBX_RESULT_TRUE; - - //------------------------------------- - err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - assert(c_txn == (const MDBX_txn *)txn); - - err = mdbx_txn_break(txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - - err = mdbx_txn_reset(txn); - assert(err == MDBX_EINVAL); - ok = ok && err == MDBX_EINVAL; - - err = mdbx_txn_commit(txn); - assert(err == MDBX_RESULT_TRUE); - ok = ok && err == MDBX_RESULT_TRUE; - - err = mdbx_txn_abort(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - //------------------------------------- - err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - assert(c_txn == (const MDBX_txn *)txn); - txn.commit(); - - err = mdbx_txn_reset(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - err = mdbx_txn_break(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - err = mdbx_txn_abort(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - - //===================================== - - txn = env.start_read(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - txn.make_broken(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - txn.reset_reading(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - txn.abort(); - - //------------------------------------- - - txn = env.start_read(); - txn.reset_reading(); - txn.make_broken(); - txn.abort(); - - //===================================== - - std::latch s1(1), s2(1), s3(1); - txn = env.start_read(); - c_txn = txn; - - std::thread t([&]() { - s1.wait(); - err = mdbx_txn_break(c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - err = mdbx_txn_reset(c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - txn.renew_reading(); - s2.count_down(); - - s3.wait(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - err = mdbx_txn_commit(c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - c_txn = txn; - err = mdbx_txn_commit(c_txn); - assert(err == MDBX_THREAD_MISMATCH); - ok = ok && err == MDBX_THREAD_MISMATCH; - err = mdbx_txn_abort(c_txn); - assert(err == MDBX_THREAD_MISMATCH); - ok = ok && err == MDBX_THREAD_MISMATCH; - err = mdbx_txn_break(c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - err = mdbx_txn_reset(c_txn); - assert(err == MDBX_EINVAL); - ok = ok && err == MDBX_EINVAL; - }); - - s1.count_down(); - s2.wait(); - txn.commit(); - txn = env.start_write(); - s3.count_down(); - - t.join(); - txn.abort(); - } + bool ok = case0(path); + ok = case1(path) && ok; + ok = case2(path, false) && ok; + ok = case2(path, true) && ok; std::cout << (ok ? "OK\n" : "FAIL\n"); return ok ? EXIT_SUCCESS : EXIT_FAILURE; From dfd265d46f85c44052e28a13ab31a6a28156c391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 15 Mar 2025 12:21:50 +0300 Subject: [PATCH 099/181] =?UTF-8?q?mdbx-tests:=20=D1=81=D1=83=D1=89=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B2=D0=B5=D0=BD=D0=BD=D0=BE=D0=B5=20=D1=80=D0=B0?= =?UTF-8?q?=D1=81=D1=88=D0=B8=D1=80=D0=B5=D0=BD=D0=B8=D0=B5=20`extra/curso?= =?UTF-8?q?r-closing`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/cursor_closing.c++ | 341 +++++++++++++++++++++++++++++++--- 1 file changed, 313 insertions(+), 28 deletions(-) diff --git a/test/extra/cursor_closing.c++ b/test/extra/cursor_closing.c++ index 045b7677..60749dbd 100644 --- a/test/extra/cursor_closing.c++ +++ b/test/extra/cursor_closing.c++ @@ -1,6 +1,13 @@ #include "mdbx.h++" +#include +#include #include +#include +#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L +#include +#include +#endif static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg, unsigned length) noexcept { @@ -11,6 +18,304 @@ static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int li static char log_buffer[1024]; +//-------------------------------------------------------------------------------------------- + +bool case0(mdbx::env env) { + auto txn = env.start_write(); + auto table = txn.create_map("case0", mdbx::key_mode::usual, mdbx::value_mode::single); + auto cursor_1 = txn.open_cursor(table); + auto cursor_2 = cursor_1.clone(); + + auto nested = env.start_write(txn); + auto nested_cursor_1 = nested.open_cursor(table); + auto nested_cursor_2 = nested_cursor_1.clone(); + auto nested_cursor_3 = cursor_1.clone(); + + auto deep = env.start_write(nested); + auto deep_cursor_1 = deep.open_cursor(table); + auto deep_cursor_2 = nested_cursor_1.clone(); + auto deep_cursor_3 = cursor_1.clone(); + deep_cursor_1.close(); + deep.commit(); + deep_cursor_2.close(); + + nested_cursor_1.close(); + nested.abort(); + nested_cursor_2.close(); + + cursor_1.close(); + txn.commit(); + cursor_2.close(); + return true; +} + +//-------------------------------------------------------------------------------------------- + +/* Сценарий: + * + * 0. Создаём N таблиц, курсор для каждой таблицы и заполняем (1000 ключей, от 1 до 1000 значений в каждом ключе). + * 1. Запускаем N-1 фоновых потоков и используем текущий/основной. + * 2. В каждом потоке 100500 раз повторяем последовательность действий: + * - 100500 раз запускаем читающую транзакцию и выполняем "читающий цикл": + * - в читающей транзакции создаем 0..3 курсоров, потом подключаем заранее созданный курсор, + * потом еще 0..3 курсоров; + * - выполняем по паре поисков через каждый курсор; + * - отключаем заранее созданный курсор; + * - снова выполняем несколько поисков по каждому курсору; + * - псевдослучайно закрываем один из курсоров и один отключаем; + * - псевдослучайно выполняем один из путей: + * - закрываем все курсоры посредством mdbx_txn_release_all_cursors(); + * - отсоединяем все курсоры посредством mdbx_txn_release_all_cursors(); + * - псевдослучайно закрываем один из курсоров и один отключаем; + * - ничего не делаем; + * - завершаем читающую транзакцию псевдослучайно выбирая между commit и abort; + * - закрываем оставшиеся курсоры. + * 3. Выполняем "пишущий цикл": + * - запускаем пишущую или вложенную транзакцию; + * - из оставшихся с предыдущих итераций курсоров половину закрываем, + * половину подключаем к транзакции; + * - для каждой таблицы с вероятностью 1/2 выполняем "читающий цикл"; + * - для каждой таблицы с вероятностью 1/2 выполняем "модифицирующий" цикл: + * - подключаем курсор, либо создаем при отсутствии подходящих; + * - 100 раз выполняем поиск случайных пар ключ/значение; + * - при успешном поиске удаляем значение, иначе вставляем; + * - с вероятностью 1/2 повторяем "читающий цикл"; + * - с вероятностью 7/16 запускаем вложенную транзакцию: + * - действуем рекурсивно как с пишущей транзакцией; + * - в "читающих циклах" немного меняем поведение: + * - игнорируем ожидаемые ошибки mdbx_cursor_unbind(); + * - в 2-3 раза уменьшаем вероятность использования mdbx_txn_release_all_cursors(); + * - завершаем вложенную транзакцию псевдослучайно выбирая между commit и abort; + * - для каждой таблицы с вероятностью 1/2 выполняем "читающий цикл"; + * - завершаем транзакцию псевдослучайно выбирая между commit и abort; + * 4. Ждем завершения фоновых потоков. + * 5. Закрываем оставшиеся курсоры и закрываем БД. */ + +thread_local size_t salt; + +static size_t prng() { + salt = salt * 134775813 + 1; + return salt ^ ((salt >> 11) * 1822226723); +} + +static inline bool flipcoin() { return prng() & 1; } + +static inline size_t prng(size_t range) { return prng() % range; } + +void case1_shuffle_pool(std::vector &pool) { + for (size_t n = 1; n < pool.size(); ++n) { + const auto i = prng(n); + if (i != n) + std::swap(pool[n], pool[i]); + } +} + +void case1_read_pool(std::vector &pool) { + for (auto c : pool) + if (flipcoin()) + mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(1000)), mdbx::slice::wrap(prng(1000)), false); + for (auto c : pool) + if (flipcoin()) + mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(1000)), mdbx::slice::wrap(prng(1000)), false); +} + +MDBX_cursor *case1_try_unbind(MDBX_cursor *cursor) { + if (cursor) { + auto err = mdbx::error(static_cast(mdbx_cursor_unbind(cursor))); + if (err.code() != MDBX_EINVAL) + err.success_or_throw(); + } + return cursor; +} + +MDBX_cursor *case1_pool_remove(std::vector &pool) { + switch (pool.size()) { + case 0: + return nullptr; + case 1: + if (flipcoin()) { + const auto c = pool[0]; + pool.pop_back(); + return c; + } + return nullptr; + default: + const auto i = prng(pool.size()); + const auto c = pool[i]; + pool.erase(pool.begin() + i); + return c; + } +} + +mdbx::map_handle case1_cycle_dbi(std::deque &dbi) { + const auto h = dbi.front(); + dbi.pop_front(); + dbi.push_back(h); + return h; +} + +void case1_read_cycle(mdbx::txn txn, std::deque &dbi, std::vector &pool, + mdbx::cursor pre, bool nested = false) { + for (auto c : pool) + mdbx::cursor(c).bind(txn, case1_cycle_dbi(dbi)); + pre.bind(txn, case1_cycle_dbi(dbi)); + + for (auto n = prng(3 + dbi.size()); n > 0; --n) { + auto c = txn.open_cursor(dbi[prng(dbi.size())]); + pool.push_back(c.withdraw_handle()); + } + case1_shuffle_pool(pool); + case1_read_pool(pool); + + pool.push_back(pre); + case1_read_pool(pool); + pool.pop_back(); + + for (auto n = prng(3 + dbi.size()); n > 0; --n) { + auto c = txn.open_cursor(dbi[prng(dbi.size())]); + pool.push_back(c.withdraw_handle()); + } + pool.push_back(pre); + case1_read_pool(pool); + pool.pop_back(); + + case1_try_unbind(pre); + case1_shuffle_pool(pool); + case1_read_pool(pool); + + if (flipcoin()) { + mdbx_cursor_close(case1_pool_remove(pool)); + auto u = case1_try_unbind(case1_pool_remove(pool)); + case1_read_pool(pool); + if (u) + pool.push_back(u); + } else { + auto u = case1_try_unbind(case1_pool_remove(pool)); + mdbx_cursor_close(case1_pool_remove(pool)); + case1_read_pool(pool); + if (u) + pool.push_back(u); + } + + switch (prng(nested ? 7 : 3)) { + case 0: + for (auto i = pool.begin(); i != pool.end();) + if (mdbx_cursor_txn(*i)) + i = pool.erase(i); + else + ++i; + txn.close_all_cursors(); + break; + case 1: + txn.unbind_all_cursors(); + break; + } +} + +void case1_write_cycle(mdbx::txn_managed txn, std::deque &dbi, std::vector &pool, + mdbx::cursor pre, bool nested = false) { + if (flipcoin()) + case1_cycle_dbi(dbi); + if (flipcoin()) + case1_shuffle_pool(pool); + + for (auto n = prng(dbi.size() + 1); n > 1; n -= 2) { + if (!nested) + pre.unbind(); + if (!pre.txn()) + pre.bind(txn, dbi[prng(dbi.size())]); + for (auto i = 0; i < 1000; ++i) { + auto k = mdbx::default_buffer::wrap(prng(1000)); + auto v = mdbx::default_buffer::wrap(prng(1000)); + if (pre.find_multivalue(k, v, false)) + pre.erase(); + else + pre.upsert(k, v); + } + } + + if (prng(16) > 8) + case1_write_cycle(txn.start_nested(), dbi, pool, pre, true); + + if (flipcoin()) + txn.commit(); + else + txn.abort(); +} + +bool case1_thread(mdbx::env env, std::deque dbi, mdbx::cursor pre) { + salt = size_t(std::chrono::high_resolution_clock::now().time_since_epoch().count()); + std::vector pool; + for (auto loop = 0; loop < 333; ++loop) { + for (auto read = 0; read < 333; ++read) { + auto txn = env.start_read(); + case1_read_cycle(txn, dbi, pool, pre); + if (flipcoin()) + txn.commit(); + else + txn.abort(); + } + + case1_write_cycle(env.start_write(), dbi, pool, pre); + + for (auto c : pool) + mdbx_cursor_close(c); + pool.clear(); + } + + pre.unbind(); + return true; +} + +bool case1(mdbx::env env) { + bool ok = true; + std::deque dbi; + std::vector cursors; +#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L + static const auto N = 10; +#else + static const auto N = 3; +#endif + for (auto t = 0; t < N; ++t) { + auto txn = env.start_write(); + auto table = txn.create_map(std::to_string(t), mdbx::key_mode::ordinal, mdbx::value_mode::multi_samelength); + auto cursor = txn.open_cursor(table); + for (size_t i = 0; i < 10000; ++i) + cursor.upsert(mdbx::default_buffer::wrap(prng(1000)), mdbx::default_buffer::wrap(prng(1000))); + txn.commit(); + + cursors.push_back(std::move(cursor)); + dbi.push_back(table); + } + +#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L + std::latch s(1); + std::vector threads; + for (auto t = 1; t < N; ++t) { + case1_cycle_dbi(dbi); + threads.push_back(std::thread([&, t]() { + s.wait(); + if (!case1_thread(env, dbi, cursors[t])) + ok = false; + })); + } + case1_cycle_dbi(dbi); + s.count_down(); +#endif + + if (!case1_thread(env, dbi, cursors[0])) + ok = false; + +#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L + for (auto &t : threads) + t.join(); +#endif + + return ok; +} + +//-------------------------------------------------------------------------------------------- + int main(int argc, const char *argv[]) { (void)argc; (void)argv; @@ -23,34 +328,14 @@ int main(int argc, const char *argv[]) { mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters(42, 0, mdbx::env::nested_transactions)); - { - auto txn = env.start_write(); - auto table = txn.create_map("dummy", mdbx::key_mode::usual, mdbx::value_mode::single); - auto cursor_1 = txn.open_cursor(table); - auto cursor_2 = cursor_1.clone(); + bool ok = case0(env); + ok = case1(env) && ok; - auto nested = env.start_write(txn); - auto nested_cursor_1 = nested.open_cursor(table); - auto nested_cursor_2 = nested_cursor_1.clone(); - auto nested_cursor_3 = cursor_1.clone(); - - auto deep = env.start_write(nested); - auto deep_cursor_1 = deep.open_cursor(table); - auto deep_cursor_2 = nested_cursor_1.clone(); - auto deep_cursor_3 = cursor_1.clone(); - deep_cursor_1.close(); - deep.commit(); - deep_cursor_2.close(); - - nested_cursor_1.close(); - nested.abort(); - nested_cursor_2.close(); - - cursor_1.close(); - txn.commit(); - cursor_2.close(); + if (ok) { + std::cout << "OK\n"; + return EXIT_SUCCESS; + } else { + std::cout << "FAIL!\n"; + return EXIT_FAILURE; } - - std::cout << "OK\n"; - return EXIT_SUCCESS; } From 83e42d03bb76a0d64a18d5b52abd0430bb4997ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 15 Mar 2025 21:03:13 +0300 Subject: [PATCH 100/181] =?UTF-8?q?mdbx:=20=D0=BA=D0=BE=D1=81=D1=82=D1=8B?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=B4=D0=BB=D1=8F=20CLANG=20<=2020=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D0=B8=20`[[=D0=B0=D1=82=D1=82=D1=80?= =?UTF-8?q?=D0=B8=D0=B1=D1=83=D1=82=D0=BE=D0=B2]]`=20C23.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mdbx.h b/mdbx.h index fdc9c6e5..fac194de 100644 --- a/mdbx.h +++ b/mdbx.h @@ -204,7 +204,7 @@ typedef mode_t mdbx_mode_t; #ifndef __has_cpp_attribute #define __has_cpp_attribute(x) 0 #define __has_cpp_attribute_qualified(x) 0 -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) || (__clang__ && __clang__ < 14) /* MSVC don't support `namespace::attr` syntax */ #define __has_cpp_attribute_qualified(x) 0 #else @@ -318,7 +318,7 @@ typedef mode_t mdbx_mode_t; #ifndef MDBX_DEPRECATED #ifdef __deprecated #define MDBX_DEPRECATED __deprecated -#elif defined(DOXYGEN) || ((!defined(__GNUC__) || defined(__clang__) || __GNUC__ > 5) && \ +#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))) @@ -504,7 +504,7 @@ typedef mode_t mdbx_mode_t; #if defined(DOXYGEN) || \ (defined(__cplusplus) && __cplusplus >= 201603L && __has_cpp_attribute(maybe_unused) && \ - __has_cpp_attribute(maybe_unused) >= 201603L) || \ + __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__) From 2e6d9fd4d4ab7824fa5367f0097b5fe7a9bdd465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 16 Mar 2025 01:44:29 +0300 Subject: [PATCH 101/181] =?UTF-8?q?mdbx++:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`mdbx::cursor::seek=5Fmu?= =?UTF-8?q?ltiple=5Fsamelength()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/mdbx.h++ b/mdbx.h++ index 55bfc8e9..ba403bca 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -4265,9 +4265,14 @@ public: batch_samelength = MDBX_GET_MULTIPLE, batch_samelength_next = MDBX_NEXT_MULTIPLE, - batch_samelength_previous = MDBX_PREV_MULTIPLE + batch_samelength_previous = MDBX_PREV_MULTIPLE, + seek_and_batch_samelength = MDBX_SEEK_AND_GET_MULTIPLE }; + // TODO: добавить легковесный proxy-класс для замещения параметра throw_notfound более сложным набором опций, + // в том числе с explicit-конструктором из bool, чтобы защититься от неявной конвертации ключей поиска + // и других параметров в bool-throw_notfound. + struct move_result : public pair_result { inline move_result(const cursor &cursor, bool throw_notfound); move_result(cursor &cursor, move_operation operation, bool throw_notfound) @@ -4465,8 +4470,8 @@ public: inline move_result lower_bound_multivalue(const slice &key, const slice &value, bool throw_notfound = false); inline move_result upper_bound_multivalue(const slice &key, const slice &value, bool throw_notfound = false); - inline move_result get_multiple_samelength(const slice &key, bool throw_notfound = true) { - return move(batch_samelength, key, throw_notfound); + inline move_result seek_multiple_samelength(const slice &key, bool throw_notfound = true) { + return move(seek_and_batch_samelength, key, throw_notfound); } inline move_result get_multiple_samelength(bool throw_notfound = false) { From ef9fd1f3fba954977614a931151bfc1bf111ac26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 16 Mar 2025 02:40:27 +0300 Subject: [PATCH 102/181] =?UTF-8?q?mdbx-tests:=20=D1=83=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=8C=D1=88=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BB-?= =?UTF-8?q?=D0=B2=D0=B0=20=D0=B8=D1=82=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B9?= =?UTF-8?q?=20=D0=B2=20extra/crunched-delete=20=D0=B4=D0=BB=D1=8F=2032-?= =?UTF-8?q?=D0=B1=D0=B8=D1=82=D0=BD=D1=8B=D1=85=20=D1=81=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=B2=D0=BE=20=D0=B8=D0=B7=D0=B1=D0=B5=D0=B6?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F=20`MDBX=5FMAP=5FFULL`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/crunched_delete.c++ | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/extra/crunched_delete.c++ b/test/extra/crunched_delete.c++ index 5655fd8a..134dbafe 100644 --- a/test/extra/crunched_delete.c++ +++ b/test/extra/crunched_delete.c++ @@ -7,8 +7,10 @@ #if MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) #define NN 1024 -#else +#elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul #define NN 4096 +#else +#define NN 2048 #endif std::string format_va(const char *fmt, va_list ap) { From db44f4ed712b558166072348ac96fb26a6ccfbfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 16 Mar 2025 20:02:26 +0300 Subject: [PATCH 103/181] =?UTF-8?q?mdbx-tools:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D1=86=D0=B8?= =?UTF-8?q?=D0=B8=20`-c`=20(concise)=20=D0=B2=20`mdbx=5Fdump`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/man1/mdbx_dump.1 | 5 ++++ src/tools/dump.c | 69 ++++++++++++++++++++------------------------ src/tools/load.c | 13 +++++++-- 3 files changed, 48 insertions(+), 39 deletions(-) diff --git a/src/man1/mdbx_dump.1 b/src/man1/mdbx_dump.1 index 6b04c0af..39e917ce 100644 --- a/src/man1/mdbx_dump.1 +++ b/src/man1/mdbx_dump.1 @@ -12,6 +12,8 @@ mdbx_dump \- MDBX environment export tool [\c .BR \-q ] [\c +.BR \-c ] +[\c .BI \-f \ file\fR] [\c .BR \-l ] @@ -41,6 +43,9 @@ Write the library version number to the standard output, and exit. .BR \-q Be quiet. .TP +.BR \-c +Concise mode without repeating keys in a dump, but incompatible with Berkeley DB and LMDB. +.TP .BR \-f \ file Write to the specified file instead of to the standard output. .TP diff --git a/src/tools/dump.c b/src/tools/dump.c index c09b2b17..95d9c72b 100644 --- a/src/tools/dump.c +++ b/src/tools/dump.c @@ -20,6 +20,7 @@ #define PRINT 1 #define GLOBAL 2 +#define CONCISE 4 static int mode = GLOBAL; typedef struct flagbit { @@ -55,42 +56,23 @@ static void signal_handler(int sig) { #endif /* !WINDOWS */ -static const char hexc[] = "0123456789abcdef"; - -static void dumpbyte(unsigned char c) { - putchar(hexc[c >> 4]); - putchar(hexc[c & 15]); -} - -static void text(MDBX_val *v) { - unsigned char *c, *end; - +static void dumpval(const MDBX_val *v) { + static const char digits[] = "0123456789abcdef"; putchar(' '); - c = v->iov_base; - end = c + v->iov_len; - while (c < end) { - if (isprint(*c) && *c != '\\') { - putchar(*c); - } else { - putchar('\\'); - dumpbyte(*c); + for (const unsigned char *c = v->iov_base, *end = c + v->iov_len; c < end; ++c) { + if (mode & PRINT) { + if (isprint(*c) && *c != '\\') { + putchar(*c); + continue; + } else + putchar('\\'); } - c++; + putchar(digits[*c >> 4]); + putchar(digits[*c & 15]); } putchar('\n'); } -static void dumpval(MDBX_val *v) { - unsigned char *c, *end; - - putchar(' '); - c = v->iov_base; - end = c + v->iov_len; - while (c < end) - dumpbyte(*c++); - putchar('\n'); -} - bool quiet = false, rescue = false; const char *prog; static void error(const char *func, int rc) { @@ -185,12 +167,19 @@ static int dump_tbl(MDBX_txn *txn, MDBX_dbi dbi, char *name) { rc = MDBX_EINTR; break; } - if (mode & PRINT) { - text(&key); - text(&data); - } else { - dumpval(&key); - dumpval(&data); + dumpval(&key); + dumpval(&data); + if ((flags & MDBX_DUPSORT) && (mode & CONCISE)) { + while ((rc = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT_DUP)) == MDBX_SUCCESS) { + if (user_break) { + rc = MDBX_EINTR; + break; + } + putchar(' '); + dumpval(&data); + } + if (rc != MDBX_NOTFOUND) + break; } } printf("DATA=END\n"); @@ -206,10 +195,12 @@ static int dump_tbl(MDBX_txn *txn, MDBX_dbi dbi, char *name) { static void usage(void) { fprintf(stderr, "usage: %s " - "[-V] [-q] [-f file] [-l] [-p] [-r] [-a|-s table] [-u|U] " + "[-V] [-q] [-c] [-f file] [-l] [-p] [-r] [-a|-s table] [-u|U] " "dbpath\n" " -V\t\tprint version and exit\n" " -q\t\tbe quiet\n" + " -c\t\tconcise mode without repeating keys,\n" + " \t\tbut incompatible with Berkeley DB and LMDB\n" " -f\t\twrite to file instead of stdout\n" " -l\t\tlist tables and exit\n" " -p\t\tuse printable characters\n" @@ -268,6 +259,7 @@ int main(int argc, char *argv[]) { "s:" "V" "r" + "c" "q")) != EOF) { switch (i) { case 'V': @@ -298,6 +290,9 @@ int main(int argc, char *argv[]) { break; case 'n': break; + case 'c': + mode |= CONCISE; + break; case 'p': mode |= PRINT; break; diff --git a/src/tools/load.c b/src/tools/load.c index 0220ce22..6cb35c60 100644 --- a/src/tools/load.c +++ b/src/tools/load.c @@ -380,7 +380,16 @@ __hot static int readline(MDBX_val *out, MDBX_val *buf) { return badend(); } } - if (fgets(buf->iov_base, (int)buf->iov_len, stdin) == nullptr) + + /* modern concise mode, where space in second position mean the same (previously) value */ + c = fgetc(stdin); + if (c == EOF) + return errno ? errno : EOF; + if (c == ' ') + return (ungetc(c, stdin) == c) ? MDBX_SUCCESS : (errno ? errno : EOF); + + *(char *)buf->iov_base = c; + if (fgets((char *)buf->iov_base + 1, (int)buf->iov_len - 1, stdin) == nullptr) return errno ? errno : EOF; lineno++; @@ -721,8 +730,8 @@ int main(int argc, char *argv[]) { } int batch = 0; + MDBX_val key = {.iov_base = nullptr, .iov_len = 0}, data = {.iov_base = nullptr, .iov_len = 0}; while (err == MDBX_SUCCESS) { - MDBX_val key, data; err = readline(&key, &kbuf); if (err == EOF) break; From 23a417fe19614481c6546845995d6dc845baf797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 17 Mar 2025 02:03:09 +0300 Subject: [PATCH 104/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B5=D0=B3=D1=80?= =?UTF-8?q?=D0=B5=D1=81=D1=81=D0=B0=20=D0=B2=20=D0=BF=D1=83=D1=82=D0=B8=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8=20`MDBX?= =?UTF-8?q?=5FMULTIPLE`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Пакетная вставка значений посредством операции `MDBX_MULTIPLE` могла приводить к падениям и повреждению структуры БД. Ошибка оставалось не замеченной из-за специфических условий проявления, которые не реализовались в тестах. Проблема присутствовала во всех выпусках начиная с v0.13.1, но соответствующая ошибка не связана с конкретным коммита в истории, а является следствием нескольких доработок (шагов рефакторинга), которые суммарно привели к регрессу. Технически ошибка обусловлена не-обнулением переменной, которая не обнулялась в некотором пути выполнения и исходно не требовала обнуления, но такое обнуление потребовалось после ряда этапов оптимизации кода и рефакторинга. Основным условием проявления является пакетная вставка multi-значений в dupsort-таблицу с фиксированным размером значений, при котором набор значений соответствующий обновляемом ключу, перестаёт помещаться на вложенной странице и преобразуется/выносится во вложенное дерево страниц. Если такой вынос/преобразование происходило до исчерпания переданного набора значений, то при следующей итерации повторно производились действия соответствующие выносу данных в отдельное дерево страниц. Что могла приводить как к разыменованию неверных указателей (повреждению содержимого памяти) и/или к повреждению содержимого страниц образующих структуру БД. Исправление свелось к добавлению одной строчки кода, но также были расширены тесты для покрытия соответствующих сценариев. --- src/cursor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cursor.c b/src/cursor.c index ddee3df7..cbe6ed7c 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -1409,6 +1409,7 @@ insert_node:; data[0].iov_base = ptr_disp(data[0].iov_base, data[0].iov_len); insert_key = insert_data = false; old_singledup.iov_base = nullptr; + sub_root = nullptr; goto more; } } From 5c1745a7cd5445f52b053265ac5fc64329b80a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 16 Mar 2025 20:08:54 +0300 Subject: [PATCH 105/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B3=D0=B8=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D1=8B=20=D0=BA=D0=BE=D0=BB=D0=B8?= =?UTF-8?q?=D1=87=D0=B5=D1=81=D1=82=D0=B2=D0=B0=20multi-=D0=B7=D0=BD=D0=B0?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B9/=D0=B4=D1=83=D0=B1=D0=BB=D0=B8?= =?UTF-8?q?=D0=BA=D0=B0=D1=82=D0=BE=D0=B2=20=D0=B2=20chk.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 2 ++ src/chk.c | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/mdbx.h b/mdbx.h index fac194de..c43c0c46 100644 --- a/mdbx.h +++ b/mdbx.h @@ -6541,6 +6541,8 @@ typedef struct MDBX_chk_table { struct MDBX_chk_histogram key_len; /// Values length histogram struct MDBX_chk_histogram val_len; + /// Number of multi-values (aka duplicates) histogram + struct MDBX_chk_histogram multival; } histogram; } MDBX_chk_table_t; diff --git a/src/chk.c b/src/chk.c index 9c83795c..7ea451c7 100644 --- a/src/chk.c +++ b/src/chk.c @@ -1139,6 +1139,7 @@ __cold static int chk_db(MDBX_chk_scope_t *const scope, MDBX_dbi dbi, MDBX_chk_t const size_t maxkeysize = mdbx_env_get_maxkeysize_ex(env, tbl->flags); MDBX_val prev_key = {nullptr, 0}, prev_data = {nullptr, 0}; MDBX_val key, data; + size_t dups_count = 0; err = mdbx_cursor_get(cursor, &key, &data, MDBX_FIRST); while (err == MDBX_SUCCESS) { err = chk_check_break(scope); @@ -1162,6 +1163,12 @@ __cold static int chk_db(MDBX_chk_scope_t *const scope, MDBX_dbi dbi, MDBX_chk_t } if (prev_key.iov_base) { + if (key.iov_base == prev_key.iov_base) + dups_count += 1; + else { + histogram_acc(dups_count, &tbl->histogram.multival); + dups_count = 0; + } if (prev_data.iov_base && !bad_data && (tbl->flags & MDBX_DUPFIXED) && prev_data.iov_len != data.iov_len) { chk_object_issue(scope, "entry", record_count, "different data length", "%" PRIuPTR " != %" PRIuPTR, prev_data.iov_len, data.iov_len); @@ -1248,17 +1255,27 @@ __cold static int chk_db(MDBX_chk_scope_t *const scope, MDBX_dbi dbi, MDBX_chk_t err = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT); } + if (prev_key.iov_base) + histogram_acc(dups_count, &tbl->histogram.multival); + err = (err != MDBX_NOTFOUND) ? chk_error_rc(scope, err, "mdbx_cursor_get") : MDBX_SUCCESS; if (err == MDBX_SUCCESS && record_count != db->items) chk_scope_issue(scope, "different number of entries %" PRIuSIZE " != %" PRIu64, record_count, db->items); bailout: if (cursor) { if (handler) { - if (tbl->histogram.key_len.count) { + if (record_count) { MDBX_chk_line_t *line = chk_line_begin(scope, MDBX_chk_info); line = histogram_dist(line, &tbl->histogram.key_len, "key length density", "0/1", false); chk_line_feed(line); line = histogram_dist(line, &tbl->histogram.val_len, "value length density", "0/1", false); + if (tbl->histogram.multival.amount) { + chk_line_feed(line); + line = histogram_dist(line, &tbl->histogram.multival, "number of multi-values density", "single", false); + chk_line_feed(line); + line = chk_print(line, "number of keys %" PRIuSIZE ", average values per key %.1f", + tbl->histogram.multival.count, record_count / (double)tbl->histogram.multival.count); + } chk_line_end(line); } if (scope->stage == MDBX_chk_maindb) From 7ae11e0fdb7b98ee43b864cdcdccba3b8a214753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 17 Mar 2025 19:01:33 +0300 Subject: [PATCH 106/181] =?UTF-8?q?mdbx++:=20=D1=8F=D0=B2=D0=BD=D0=BE?= =?UTF-8?q?=D0=B5=20=D0=BE=D0=BF=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20external-=D0=B8=D0=BD=D1=81=D1=82=D0=B0=D0=BD?= =?UTF-8?q?=D1=86=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20`mdbx:?= =?UTF-8?q?:buffer<>`=20c=20API-=D0=B0=D1=82=D1=80=D0=B8=D0=B1=D1=83=D1=82?= =?UTF-8?q?=D0=B0=D0=BC=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 23 +++++++++++++++++++++-- src/mdbx.c++ | 24 ++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/mdbx.h++ b/mdbx.h++ index ba403bca..6426f3fa 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -107,6 +107,16 @@ #include #endif +#if !defined(_MSC_VER) || defined(__clang__) +/* adequate compilers */ +#define MDBX_EXTERN_API_TEMPLATE(API_ATTRIBUTES, API_TYPENAME) extern template class API_ATTRIBUTES API_TYPENAME +#define MDBX_INSTALL_API_TEMPLATE(API_ATTRIBUTES, API_TYPENAME) template class API_TYPENAME +#else +/* stupid microsoft showing off */ +#define MDBX_EXTERN_API_TEMPLATE(API_ATTRIBUTES, API_TYPENAME) extern template class API_TYPENAME +#define MDBX_INSTALL_API_TEMPLATE(API_ATTRIBUTES, API_TYPENAME) template class API_ATTRIBUTES API_TYPENAME +#endif + #if __cplusplus >= 201103L #include #include @@ -1500,8 +1510,7 @@ public: private: friend class txn; - struct silo; - using swap_alloc = allocation_aware_details::swap_alloc; + using swap_alloc = allocation_aware_details::swap_alloc; struct silo /* Empty Base Class Optimization */ : public allocator_type { MDBX_CXX20_CONSTEXPR const allocator_type &get_allocator() const noexcept { return *this; } MDBX_CXX20_CONSTEXPR allocator_type &get_allocator() noexcept { return *this; } @@ -2729,6 +2738,12 @@ inline string make_string(const PRODUCER &producer, const ALLOCATOR & return result; } +MDBX_EXTERN_API_TEMPLATE(LIBMDBX_API_TYPE, buffer); + +#if defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L && _GLIBCXX_USE_CXX11_ABI +MDBX_EXTERN_API_TEMPLATE(LIBMDBX_API_TYPE, buffer); +#endif /* __cpp_lib_memory_resource >= 201603L */ + /// \brief Combines data slice with boolean flag to represent result of certain /// operations. struct value_result { @@ -2854,9 +2869,13 @@ template struct buffer_pair_spec operator pair() const noexcept { return pair(key, value); } }; +/// \brief Combines pair of buffers for key and value to hold an operands for certain operations. template using buffer_pair = buffer_pair_spec; +/// \brief Default pair of buffers. +using default_buffer_pair = buffer_pair; + /// end of cxx_data @} //------------------------------------------------------------------------------ diff --git a/src/mdbx.c++ b/src/mdbx.c++ index 7b4d8aa1..565c79e9 100644 --- a/src/mdbx.c++ +++ b/src/mdbx.c++ @@ -1162,12 +1162,32 @@ bool from_base64::is_erroneous() const noexcept { //------------------------------------------------------------------------------ -template class LIBMDBX_API_TYPE buffer; +#if defined(_MSC_VER) +#pragma warning(push) +/* warning C4251: 'mdbx::buffer<...>::silo_': + * struct 'mdbx::buffer<..>::silo' needs to have dll-interface to be used by clients of class 'mdbx::buffer<...>' + * + * Microsoft не хочет признавать ошибки и пересматривать приятные решения, поэтому MSVC продолжает кошмарить + * и стращать разработчиков предупреждениями, тем самым перекладывая ответственность на их плечи. + * + * В данном случае предупреждение выдаётся из-за инстанцирования std::string::allocator_type::pointer и + * std::pmr::string::allocator_type::pointer внутри mdbx::buffer<..>::silo. А так как эти типы являются частью + * стандартной библиотеки C++ они всегда будут доступны и без необходимости их инстанцирования и экспорта из libmdbx. + * + * Поэтому нет других вариантов как заглушить это предупреждение и еще раз плюнуть в сторону microsoft. */ +#pragma warning(disable : 4251) +#endif /* MSVC */ + +MDBX_INSTALL_API_TEMPLATE(LIBMDBX_API_TYPE, buffer); #if defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L && _GLIBCXX_USE_CXX11_ABI -template class LIBMDBX_API_TYPE buffer; +MDBX_INSTALL_API_TEMPLATE(LIBMDBX_API_TYPE, buffer); #endif /* __cpp_lib_memory_resource >= 201603L */ +#if defined(_MSC_VER) +#pragma warning(pop) +#endif /* MSVC */ + //------------------------------------------------------------------------------ static inline MDBX_env_flags_t mode2flags(env::mode mode) { From 8008afc6e13f2a3c9a718668e52ffb424271d178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 16 Mar 2025 20:23:20 +0300 Subject: [PATCH 107/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B6=D0=BA=D0=B0=20`MDBX=5FMULTIPLE`=20=D1=81=20=D0=BD?= =?UTF-8?q?=D1=83=D0=BB=D0=B5=D0=B2=D1=8B=D0=BC=20=D1=80=D0=B0=D0=B7=D0=BC?= =?UTF-8?q?=D0=B5=D1=80=D0=BE=D0=BC=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cursor.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/cursor.c b/src/cursor.c index cbe6ed7c..9da14343 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -728,8 +728,17 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig if (mc->clc->k.cmp(key, ¤t_key) != 0) return MDBX_EKEYMISMATCH; - if (unlikely((flags & MDBX_MULTIPLE))) - goto drop_current; + if (unlikely((flags & MDBX_MULTIPLE))) { + if (unlikely(!mc->subcur)) + return MDBX_EINVAL; + err = cursor_del(mc, flags & MDBX_ALLDUPS); + if (unlikely(err != MDBX_SUCCESS)) + return err; + if (unlikely(data[1].iov_len == 0)) + return MDBX_SUCCESS; + flags -= MDBX_CURRENT; + goto skip_check_samedata; + } if (mc->subcur) { node_t *node = page_node(mc->pg[mc->top], mc->ki[mc->top]); @@ -739,7 +748,6 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig * отличается, то вместо обновления требуется удаление и * последующая вставка. */ if (mc->subcur->nested_tree.items > 1 || current_data.iov_len != data->iov_len) { - drop_current: err = cursor_del(mc, flags & MDBX_ALLDUPS); if (unlikely(err != MDBX_SUCCESS)) return err; @@ -830,7 +838,7 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig return csr.err; } } - } else if ((flags & MDBX_RESERVE) == 0) { + } else if (!(flags & (MDBX_RESERVE | MDBX_MULTIPLE))) { if (unlikely(eq_fast(data, &old_data))) { cASSERT(mc, mc->clc->v.cmp(data, &old_data) == 0); /* the same data, nothing to update */ @@ -847,6 +855,8 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig size_t *batch_dupfix_done = nullptr, batch_dupfix_given = 0; if (unlikely(flags & MDBX_MULTIPLE)) { batch_dupfix_given = data[1].iov_len; + if (unlikely(data[1].iov_len == 0)) + return /* nothing todo */ MDBX_SUCCESS; batch_dupfix_done = &data[1].iov_len; *batch_dupfix_done = 0; } From 7a923b3d41f54c17c8e9f2a44eaa18269947bd7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 17 Mar 2025 11:56:36 +0300 Subject: [PATCH 108/181] =?UTF-8?q?mdbx:=20=D1=80=D0=B5=D1=84=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BE=D0=BA=20=D1=81=20=D0=B2=D1=8B=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D0=BE=D0=BC=20=D0=B2=20`cursor=5Fcheck=5Fmultiple()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cursor.c | 18 +++--------------- src/api-txn-data.c | 13 +++++++++++++ src/cursor.c | 15 +++++++++++++++ src/cursor.h | 3 +++ 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/api-cursor.c b/src/api-cursor.c index 4489a64f..4a506b41 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -712,22 +712,10 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, MDBX_p if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - /* Check this first so counter will always be zero on any early failures. */ if (unlikely(flags & MDBX_MULTIPLE)) { - if (unlikely(flags & MDBX_RESERVE)) - return LOG_IFERR(MDBX_EINVAL); - if (unlikely(!(mc->tree->flags & MDBX_DUPFIXED))) - return LOG_IFERR(MDBX_INCOMPATIBLE); - const size_t dcount = data[1].iov_len; - if (unlikely(dcount < 2 || data->iov_len == 0)) - return LOG_IFERR(MDBX_BAD_VALSIZE); - if (unlikely(mc->tree->dupfix_size != data->iov_len) && mc->tree->dupfix_size) - return LOG_IFERR(MDBX_BAD_VALSIZE); - if (unlikely(dcount > MAX_MAPSIZE / 2 / (BRANCH_NODE_MAX(MDBX_MAX_PAGESIZE) - NODESIZE))) { - /* checking for multiplication overflow */ - if (unlikely(dcount > MAX_MAPSIZE / 2 / data->iov_len)) - return LOG_IFERR(MDBX_TOO_LARGE); - } + rc = cursor_check_multiple(mc, key, data, flags); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); } if (flags & MDBX_RESERVE) { diff --git a/src/api-txn-data.c b/src/api-txn-data.c index 2be54df8..cc0891cb 100644 --- a/src/api-txn-data.c +++ b/src/api-txn-data.c @@ -266,6 +266,19 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, M rc = cursor_init(&cx.outer, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); + + if (unlikely(flags & MDBX_MULTIPLE)) { + rc = cursor_check_multiple(&cx.outer, key, data, flags); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + } + + if (flags & MDBX_RESERVE) { + if (unlikely(cx.outer.tree->flags & (MDBX_DUPSORT | MDBX_REVERSEDUP | MDBX_INTEGERDUP | MDBX_DUPFIXED))) + return LOG_IFERR(MDBX_INCOMPATIBLE); + data->iov_base = nullptr; + } + cx.outer.next = txn->cursors[dbi]; txn->cursors[dbi] = &cx.outer; diff --git a/src/cursor.c b/src/cursor.c index 9da14343..233c2246 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -1439,6 +1439,21 @@ insert_node:; return rc; } +int cursor_check_multiple(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsigned flags) { + (void)key; + if (unlikely(flags & MDBX_RESERVE)) + return MDBX_EINVAL; + if (unlikely(!(mc->tree->flags & MDBX_DUPFIXED))) + return MDBX_INCOMPATIBLE; + const size_t number = data[1].iov_len; + if (unlikely(number > MAX_MAPSIZE / 2 / (BRANCH_NODE_MAX(MDBX_MAX_PAGESIZE) - NODESIZE))) { + /* checking for multiplication overflow */ + if (unlikely(number > MAX_MAPSIZE / 2 / data->iov_len)) + return MDBX_TOO_LARGE; + } + return MDBX_SUCCESS; +} + __hot int cursor_put_checklen(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsigned flags) { cASSERT(mc, (mc->flags & z_inner) == 0); if (unlikely(key->iov_len > mc->clc->k.lmax || key->iov_len < mc->clc->k.lmin)) { diff --git a/src/cursor.h b/src/cursor.h index d8100999..d07be856 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -315,6 +315,9 @@ MDBX_INTERNAL MDBX_cursor *cursor_cpstk(const MDBX_cursor *csrc, MDBX_cursor *cd MDBX_INTERNAL int __must_check_result cursor_ops(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, const MDBX_cursor_op op); +MDBX_INTERNAL int __must_check_result cursor_check_multiple(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, + unsigned flags); + MDBX_INTERNAL int __must_check_result cursor_put_checklen(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsigned flags); From 71d95d1a5f1e7b3aa26abe8d0bf268320bb086cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 17 Mar 2025 11:53:14 +0300 Subject: [PATCH 109/181] =?UTF-8?q?mdbx++:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`mdbx::cursor::put=5Fmul?= =?UTF-8?q?tiple=5Fsamelength()`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/mdbx.h++ b/mdbx.h++ index 6426f3fa..ff4d0dba 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -4100,8 +4100,9 @@ public: return append(map, kv.key, kv.value, multivalue_order_preserved); } - size_t put_multiple_samelength(map_handle map, const slice &key, const size_t value_length, const void *values_array, - size_t values_count, put_mode mode, bool allow_partial = false); + inline size_t put_multiple_samelength(map_handle map, const slice &key, const size_t value_length, + const void *values_array, size_t values_count, put_mode mode, + bool allow_partial = false); template size_t put_multiple_samelength(map_handle map, const slice &key, const VALUE *values_array, size_t values_count, put_mode mode, bool allow_partial = false) { @@ -4567,6 +4568,21 @@ public: /// \brief Seeks and removes the particular multi-value entry of the key. /// \return `True` if the given key-value pair is found and removed. inline bool erase(const slice &key, const slice &value); + + inline size_t put_multiple_samelength(const slice &key, const size_t value_length, const void *values_array, + size_t values_count, put_mode mode, bool allow_partial = false); + template + size_t put_multiple_samelength(const slice &key, const VALUE *values_array, size_t values_count, put_mode mode, + bool allow_partial = false) { + static_assert(::std::is_standard_layout::value && !::std::is_pointer::value && + !::std::is_array::value, + "Must be a standard layout type!"); + return put_multiple_samelength(key, sizeof(VALUE), values_array, values_count, mode, allow_partial); + } + template + void put_multiple_samelength(const slice &key, const ::std::vector &vector, put_mode mode) { + put_multiple_samelength(key, vector.data(), vector.size(), mode); + } }; /// \brief Managed cursor. @@ -6354,6 +6370,24 @@ inline bool cursor::erase(const slice &key, const slice &value) { return data.done && erase(); } +inline size_t cursor::put_multiple_samelength(const slice &key, const size_t value_length, const void *values_array, + size_t values_count, put_mode mode, bool allow_partial) { + MDBX_val args[2] = {{const_cast(values_array), value_length}, {nullptr, values_count}}; + const int err = ::mdbx_cursor_put(handle_, const_cast(&key), args, MDBX_put_flags_t(mode) | MDBX_MULTIPLE); + switch (err) { + case MDBX_SUCCESS: + MDBX_CXX20_LIKELY break; + case MDBX_KEYEXIST: + if (allow_partial) + break; + mdbx_txn_break(txn()); + MDBX_CXX17_FALLTHROUGH /* fallthrough */; + default: + MDBX_CXX20_UNLIKELY error::throw_exception(err); + } + return args[1].iov_len /* done item count */; +} + /// end cxx_api @} } // namespace mdbx From c0b1ab1466e50e85e0e86fa0be5a0a75b43379f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 17 Mar 2025 12:40:00 +0300 Subject: [PATCH 110/181] =?UTF-8?q?mdbx-tests:=20=D1=80=D0=B0=D1=81=D1=88?= =?UTF-8?q?=D0=B8=D1=80=D0=B5=D0=BD=D0=B8=D0=B5=20extra/dupfix-multiple.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/dupfix_multiple.c++ | 168 ++++++++++++++++++++++----------- 1 file changed, 111 insertions(+), 57 deletions(-) diff --git a/test/extra/dupfix_multiple.c++ b/test/extra/dupfix_multiple.c++ index a212984b..ecc02bc7 100644 --- a/test/extra/dupfix_multiple.c++ +++ b/test/extra/dupfix_multiple.c++ @@ -2,15 +2,12 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 #include "mdbx.h++" -#include +#include #include -int doit() { - mdbx::path db_filename = "test-dupfix-multiple"; - mdbx::env_managed::remove(db_filename); - mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters()); +using buffer = mdbx::default_buffer; - using buffer = mdbx::buffer; +bool case1_ordering(mdbx::env env) { auto txn = env.start_write(); auto map = txn.create_map(nullptr, mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal); @@ -30,10 +27,9 @@ int doit() { cursor.to_next().value.as_uint64() != 17 || cursor.to_next().value.as_uint64() != 16 || cursor.to_next().value.as_uint64() != 15 || cursor.to_next().value.as_uint64() != 14 || cursor.to_next().value.as_uint64() != 13 || cursor.to_next().value.as_uint64() != 12 || - cursor.to_next(false).done || !cursor.eof()) { - std::cerr << "Fail\n"; - return EXIT_FAILURE; - } + cursor.to_next(false).done || !cursor.eof()) + return false; + txn.abort(); const uint64_t array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 42, 17, 99, 0, 33, 333}; @@ -87,10 +83,9 @@ int doit() { /* key = 24 */ cursor.to_next().value.as_uint64() != 15 || /* key = 25 */ cursor.to_next().value.as_uint64() != 14 || /* key = 26 */ cursor.to_next().value.as_uint64() != 13 || - /* key = 27 */ cursor.to_next().value.as_uint64() != 12 || cursor.to_next(false).done || !cursor.eof()) { - std::cerr << "Fail\n"; - return EXIT_FAILURE; - } + /* key = 27 */ cursor.to_next().value.as_uint64() != 12 || cursor.to_next(false).done || !cursor.eof()) + return false; + txn.abort(); txn = env.start_write(); @@ -163,40 +158,24 @@ int doit() { cursor.to_next().value.as_uint64() != 0 || cursor.to_next().value.as_uint64() != 33 || cursor.to_next().value.as_uint64() != 333 || - cursor.to_next(false).done || !cursor.eof()) { - std::cerr << "Fail\n"; - return EXIT_FAILURE; - } + cursor.to_next(false).done || !cursor.eof()) + return false; + txn.abort(); - //---------------------------------------------------------------------------- - - // let dir = tempdir().unwrap(); - // let db = Database::open(&dir).unwrap(); - - // let txn = db.begin_rw_txn().unwrap(); - // let table = txn - // .create_table(None, TableFlags::DUP_SORT | TableFlags::DUP_FIXED) - // .unwrap(); - // for (k, v) in [ - // (b"key1", b"val1"), - // (b"key1", b"val2"), - // (b"key1", b"val3"), - // (b"key2", b"val1"), - // (b"key2", b"val2"), - // (b"key2", b"val3"), - // ] { - // txn.put(&table, k, v, WriteFlags::empty()).unwrap(); - // } - - // let mut cursor = txn.cursor(&table).unwrap(); - // assert_eq!(cursor.first().unwrap(), Some((*b"key1", *b"val1"))); - // assert_eq!(cursor.get_multiple().unwrap(), Some(*b"val1val2val3")); - // assert_eq!(cursor.next_multiple::<(), ()>().unwrap(), None); - txn = env.start_write(); txn.clear_map(map); - map = txn.create_map(nullptr, mdbx::key_mode::usual, mdbx::value_mode::multi_samelength); + txn.commit(); + + return true; +} + +//-------------------------------------------------------------------------------------------- + +bool case2_batch_read(mdbx::env env) { + + auto txn = env.start_write(); + auto map = txn.create_map(nullptr, mdbx::key_mode::usual, mdbx::value_mode::multi_samelength); txn.upsert(map, mdbx::slice("key1"), mdbx::slice("val1")); txn.upsert(map, mdbx::pair("key1", "val2")); txn.upsert(map, mdbx::pair("key1", "val3")); @@ -205,30 +184,105 @@ int doit() { txn.upsert(map, mdbx::pair("key2", "val3")); // cursor.close(); - cursor = txn.open_cursor(map); + auto cursor = txn.open_cursor(map); const auto t1 = cursor.to_first(); if (!t1 || t1.key != "key1" || t1.value != "val1") { std::cerr << "Fail-t1\n"; - return EXIT_FAILURE; + return false; } const auto t2 = cursor.get_multiple_samelength(); if (!t2 || t2.key != "key1" || t2.value != "val1val2val3") { std::cerr << "Fail-t2\n"; - return EXIT_FAILURE; + return false; } - // const auto t3 = cursor.get_multiple_samelength("key2"); - // if (!t3 || t3.key != "key2" || t3.value != "val1val2val3") { - // std::cerr << "Fail-t3\n"; - // return EXIT_FAILURE; - // } - const auto t4 = cursor.next_multiple_samelength(); - if (t4) { + const auto t3 = cursor.next_multiple_samelength(); + if (t3) { + std::cerr << "Fail-t3\n"; + return false; + } + const auto t4 = cursor.seek_multiple_samelength("key2"); + if (!t4 || t4.key != "key2" || t4.value != "val1val2val3") { std::cerr << "Fail-t4\n"; - return EXIT_FAILURE; + return false; } - std::cout << "OK\n"; - return EXIT_SUCCESS; + txn.clear_map(map); + txn.commit(); + + return true; +} + +//-------------------------------------------------------------------------------------------- + +size_t salt; + +static size_t prng() { + salt = salt * 134775813 + 1; + return salt ^ ((salt >> 11) * 1822226723); +} + +static inline size_t prng(size_t range) { return prng() % range; } + +static mdbx::default_buffer_pair prng_kv(size_t n, size_t space) { + space = (space + !space) * 1024 * 32; + const size_t w = (n ^ 1455614549) * 1664525 + 1013904223; + const size_t k = (prng(42 + w % space) ^ 1725278851) * 433750991; + const size_t v = prng(); + return mdbx::default_buffer_pair(mdbx::slice::wrap(k), mdbx::slice::wrap(v)); +} + +bool case3_put_a_lot(mdbx::env env) { + salt = size_t(std::chrono::high_resolution_clock::now().time_since_epoch().count()); + auto txn = env.start_write(); + auto map = txn.create_map("case3", mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal); + for (size_t n = 0; n < 5555555; ++n) + txn.upsert(map, prng_kv(n, 1)); + txn.commit(); + + for (size_t t = 0; t < 555; ++t) { + txn = env.start_write(); + auto cursor = txn.open_cursor(map); + for (size_t n = 0; n < 111; ++n) { + auto v = std::vector(); + const auto r = 1 + prng(3); + if (r & 1) { + const auto k = prng_kv(n + t, 2).key; + for (size_t i = prng(42 + prng(111) * prng(111)); i > 0; --i) + v.push_back(prng()); + txn.put_multiple_samelength(map, k, v, mdbx::upsert); + } + if (r & 2) { + const auto k = prng_kv(n + t, 2).key; + if (cursor.seek(k)) { + v.clear(); + for (size_t i = prng(42 + prng(111) * prng(111)); i > 0; --i) + v.push_back(prng()); + cursor.put_multiple_samelength(k, v, mdbx::upsert); + } + } + } + txn.commit(); + } + + return true; +} + +int doit() { + mdbx::path db_filename = "test-dupfix-multiple"; + mdbx::env_managed::remove(db_filename); + mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters(1)); + + bool ok = case1_ordering(env); + ok = case2_batch_read(env) && ok; + ok = case3_put_a_lot(env) && ok; + + if (ok) { + std::cout << "OK\n"; + return EXIT_SUCCESS; + } else { + std::cerr << "Fail\n"; + return EXIT_FAILURE; + } } int main(int argc, const char *argv[]) { From e6891b295b3c40b19d81a9f0d26adc1ca0b64a7d Mon Sep 17 00:00:00 2001 From: Leo Yuriev Date: Mon, 17 Mar 2025 13:53:36 +0300 Subject: [PATCH 111/181] mdbx++: minor reflow Doxygen comments. --- mdbx.h++ | 205 ++++++++++++++++++------------------------------------- 1 file changed, 68 insertions(+), 137 deletions(-) diff --git a/mdbx.h++ b/mdbx.h++ index ff4d0dba..2d5f62b1 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -158,8 +158,7 @@ #endif #endif /* Byte Order */ -/** Workaround for old compilers without properly support for `C++17 constexpr`. - */ +/** Workaround for old compilers without properly support for `C++17 constexpr` */ #if defined(DOXYGEN) #define MDBX_CXX17_CONSTEXPR constexpr #elif defined(__cpp_constexpr) && __cpp_constexpr >= 201603L && \ @@ -170,8 +169,7 @@ #define MDBX_CXX17_CONSTEXPR inline #endif /* MDBX_CXX17_CONSTEXPR */ -/** Workaround for old compilers without properly support for C++20 `constexpr`. - */ +/** Workaround for old compilers without properly support for C++20 `constexpr`. */ #if defined(DOXYGEN) #define MDBX_CXX20_CONSTEXPR constexpr #elif defined(__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L && \ @@ -195,8 +193,7 @@ #define MDBX_CXX20_CONSTEXPR_ENUM inline #endif /* CONSTEXPR_ENUM_FLAGS_OPERATIONS */ -/** Workaround for old compilers without support assertion inside `constexpr` - * functions. */ +/** Workaround for old compilers without support assertion inside `constexpr` functions. */ #if defined(CONSTEXPR_ASSERT) #define MDBX_CONSTEXPR_ASSERT(expr) CONSTEXPR_ASSERT(expr) #elif defined NDEBUG @@ -221,8 +218,7 @@ #endif #endif /* MDBX_UNLIKELY */ -/** Workaround for old compilers without properly support for C++20 `if - * constexpr`. */ +/** Workaround for old compilers without properly support for C++20 `if constexpr`. */ #if defined(DOXYGEN) #define MDBX_IF_CONSTEXPR constexpr #elif defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L @@ -398,8 +394,7 @@ namespace filesystem = ::std::experimental::filesystem; namespace filesystem = ::std::filesystem; /// \brief Defined if `mdbx::filesystem::path` is available. /// \details If defined, it is always `mdbx::filesystem::path`, -/// which in turn can be refs to `std::filesystem::path` -/// or `std::experimental::filesystem::path`. +/// which in turn can be refs to `std::filesystem::path` or `std::experimental::filesystem::path`. /// Nonetheless `MDBX_STD_FILESYSTEM_PATH` not defined if the `::mdbx::path` /// is fallbacked to c `std::string` or `std::wstring`. #define MDBX_STD_FILESYSTEM_PATH ::mdbx::filesystem::path @@ -499,9 +494,7 @@ public: static inline void success_or_panic(int error_code, const char *context_where, const char *func_who) noexcept; }; -/// \brief Base class for all libmdbx's exceptions that are corresponds -/// to libmdbx errors. -/// +/// \brief Base class for all libmdbx's exceptions that are corresponds to libmdbx errors. /// \see MDBX_error_t class LIBMDBX_API_TYPE exception : public ::std::runtime_error { using base = ::std::runtime_error; @@ -517,8 +510,7 @@ public: const ::mdbx::error error() const noexcept { return error_; } }; -/// \brief Fatal exception that lead termination anyway -/// in dangerous unrecoverable cases. +/// \brief Fatal exception that lead termination anyway in dangerous unrecoverable cases. class LIBMDBX_API_TYPE fatal : public exception { using base = exception; @@ -654,8 +646,7 @@ struct LIBMDBX_API_TYPE slice : public ::MDBX_val { /// \brief Create an empty slice. MDBX_CXX11_CONSTEXPR slice() noexcept; - /// \brief Create a slice that refers to [0,bytes-1] of memory bytes pointed - /// by ptr. + /// \brief Create a slice that refers to [0,bytes-1] of memory bytes pointed by ptr. MDBX_CXX14_CONSTEXPR slice(const void *ptr, size_t bytes); /// \brief Create a slice that refers to [begin,end] of memory bytes. @@ -1010,8 +1001,7 @@ struct LIBMDBX_API_TYPE slice : public ::MDBX_val { /// \brief Checks the slice is not refers to null address or has zero length. MDBX_CXX11_CONSTEXPR bool is_valid() const noexcept { return !(iov_base == nullptr && iov_len != 0); } - /// \brief Build an invalid slice which non-zero length and refers to null - /// address. + /// \brief Build an invalid slice which non-zero length and refers to null address. MDBX_CXX14_CONSTEXPR static slice invalid() noexcept { return slice(size_t(-1)); } template MDBX_CXX14_CONSTEXPR POD as_pod() const { @@ -1239,8 +1229,7 @@ struct LIBMDBX_API to_hex { char *write_bytes(char *dest, size_t dest_size) const; /// \brief Output hexadecimal dump of passed slice to the std::ostream. - /// \throws std::ios_base::failure corresponding to std::ostream::write() - /// behaviour. + /// \throws std::ios_base::failure corresponding to std::ostream::write() behaviour. ::std::ostream &output(::std::ostream &out) const; /// \brief Checks whether a passed slice is empty, @@ -1283,23 +1272,18 @@ struct LIBMDBX_API to_base58 { return wrap_width ? bytes + bytes / wrap_width : bytes; } - /// \brief Fills the buffer by [Base58](https://en.wikipedia.org/wiki/Base58) - /// dump of passed slice. + /// \brief Fills the buffer by [Base58](https://en.wikipedia.org/wiki/Base58) dump of passed slice. /// \throws std::length_error if given buffer is too small. char *write_bytes(char *dest, size_t dest_size) const; - /// \brief Output [Base58](https://en.wikipedia.org/wiki/Base58) - /// dump of passed slice to the std::ostream. - /// \throws std::ios_base::failure corresponding to std::ostream::write() - /// behaviour. + /// \brief Output [Base58](https://en.wikipedia.org/wiki/Base58) dump of passed slice to the std::ostream. + /// \throws std::ios_base::failure corresponding to std::ostream::write() behaviour. ::std::ostream &output(::std::ostream &out) const; - /// \brief Checks whether a passed slice is empty, - /// and therefore there will be no output bytes. + /// \brief Checks whether a passed slice is empty, and therefore there will be no output bytes. bool is_empty() const noexcept { return source.empty(); } - /// \brief Checks whether the content of a passed slice is a valid data - /// and could be encoded or unexpectedly not. + /// \brief Checks whether the content of a passed slice is a valid data and could be encoded or unexpectedly not. bool is_erroneous() const noexcept { return false; } }; @@ -1341,8 +1325,7 @@ struct LIBMDBX_API to_base64 { /// \brief Output [Base64](https://en.wikipedia.org/wiki/Base64) /// dump of passed slice to the std::ostream. - /// \throws std::ios_base::failure corresponding to std::ostream::write() - /// behaviour. + /// \throws std::ios_base::failure corresponding to std::ostream::write() behaviour. ::std::ostream &output(::std::ostream &out) const; /// \brief Checks whether a passed slice is empty, @@ -1383,13 +1366,11 @@ struct LIBMDBX_API from_hex { /// hexadecimal dump from a passed slice to decoded data. MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept { return source.length() >> 1; } - /// \brief Fills the destination with data decoded from hexadecimal dump - /// from a passed slice. + /// \brief Fills the destination with data decoded from hexadecimal dump from a passed slice. /// \throws std::length_error if given buffer is too small. char *write_bytes(char *dest, size_t dest_size) const; - /// \brief Checks whether a passed slice is empty, - /// and therefore there will be no output bytes. + /// \brief Checks whether a passed slice is empty, and therefore there will be no output bytes. bool is_empty() const noexcept { return source.empty(); } /// \brief Checks whether the content of a passed slice is a valid hexadecimal @@ -1422,8 +1403,7 @@ struct LIBMDBX_API from_base58 { } /// \brief Returns the number of bytes needed for conversion - /// [Base58](https://en.wikipedia.org/wiki/Base58) dump from a passed slice to - /// decoded data. + /// [Base58](https://en.wikipedia.org/wiki/Base58) dump from a passed slice to decoded data. MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept { return source.length() /* могут быть все нули кодируемые один-к-одному */; } @@ -1433,13 +1413,11 @@ struct LIBMDBX_API from_base58 { /// \throws std::length_error if given buffer is too small. char *write_bytes(char *dest, size_t dest_size) const; - /// \brief Checks whether a passed slice is empty, - /// and therefore there will be no output bytes. + /// \brief Checks whether a passed slice is empty, and therefore there will be no output bytes. bool is_empty() const noexcept { return source.empty(); } /// \brief Checks whether the content of a passed slice is a valid - /// [Base58](https://en.wikipedia.org/wiki/Base58) dump, and therefore there - /// could be decoded or not. + /// [Base58](https://en.wikipedia.org/wiki/Base58) dump, and therefore there could be decoded or not. bool is_erroneous() const noexcept; }; @@ -1468,8 +1446,7 @@ struct LIBMDBX_API from_base64 { } /// \brief Returns the number of bytes needed for conversion - /// [Base64](https://en.wikipedia.org/wiki/Base64) dump from a passed slice to - /// decoded data. + /// [Base64](https://en.wikipedia.org/wiki/Base64) dump from a passed slice to decoded data. MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept { return (source.length() + 3) / 4 * 3; } /// \brief Fills the destination with data decoded from @@ -1936,8 +1913,7 @@ public: /// the buffer, rather than stores it. MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR bool is_reference() const noexcept { return !is_freestanding(); } - /// \brief Returns the number of bytes that can be held in currently allocated - /// storage. + /// \brief Returns the number of bytes that can be held in currently allocated storage. MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR size_t capacity() const noexcept { return is_freestanding() ? silo_.capacity() : 0; } @@ -1961,16 +1937,14 @@ public: MDBX_CXX11_CONSTEXPR const byte *end_byte_ptr() const noexcept { return slice_.end_byte_ptr(); } /// \brief Returns casted to pointer to byte an address of data. - /// \pre REQUIRES: The buffer should store data chunk, but not referenced to - /// an external one. + /// \pre REQUIRES: The buffer should store data chunk, but not referenced to an external one. MDBX_CXX11_CONSTEXPR byte *byte_ptr() noexcept { MDBX_CONSTEXPR_ASSERT(is_freestanding()); return const_cast(slice_.byte_ptr()); } /// \brief Returns casted to pointer to byte an end of data. - /// \pre REQUIRES: The buffer should store data chunk, but not referenced to - /// an external one. + /// \pre REQUIRES: The buffer should store data chunk, but not referenced to an external one. MDBX_CXX11_CONSTEXPR byte *end_byte_ptr() noexcept { MDBX_CONSTEXPR_ASSERT(is_freestanding()); return const_cast(slice_.end_byte_ptr()); @@ -1983,16 +1957,14 @@ public: MDBX_CXX11_CONSTEXPR const char *end_char_ptr() const noexcept { return slice_.end_char_ptr(); } /// \brief Returns casted to pointer to char an address of data. - /// \pre REQUIRES: The buffer should store data chunk, but not referenced to - /// an external one. + /// \pre REQUIRES: The buffer should store data chunk, but not referenced to an external one. MDBX_CXX11_CONSTEXPR char *char_ptr() noexcept { MDBX_CONSTEXPR_ASSERT(is_freestanding()); return const_cast(slice_.char_ptr()); } /// \brief Returns casted to pointer to char an end of data. - /// \pre REQUIRES: The buffer should store data chunk, but not referenced to - /// an external one. + /// \pre REQUIRES: The buffer should store data chunk, but not referenced to an external one. MDBX_CXX11_CONSTEXPR char *end_char_ptr() noexcept { MDBX_CONSTEXPR_ASSERT(is_freestanding()); return const_cast(slice_.end_char_ptr()); @@ -2005,16 +1977,14 @@ public: MDBX_CXX11_CONSTEXPR const void *end() const noexcept { return slice_.end(); } /// \brief Return a pointer to the beginning of the referenced data. - /// \pre REQUIRES: The buffer should store data chunk, but not referenced to - /// an external one. + /// \pre REQUIRES: The buffer should store data chunk, but not referenced to an external one. MDBX_CXX11_CONSTEXPR void *data() noexcept { MDBX_CONSTEXPR_ASSERT(is_freestanding()); return const_cast(slice_.data()); } /// \brief Return a pointer to the end of the referenced data. - /// \pre REQUIRES: The buffer should store data chunk, but not referenced to - /// an external one. + /// \pre REQUIRES: The buffer should store data chunk, but not referenced to an external one. MDBX_CXX11_CONSTEXPR void *end() noexcept { MDBX_CONSTEXPR_ASSERT(is_freestanding()); return const_cast(slice_.end()); @@ -2744,8 +2714,7 @@ MDBX_EXTERN_API_TEMPLATE(LIBMDBX_API_TYPE, buffer); MDBX_EXTERN_API_TEMPLATE(LIBMDBX_API_TYPE, buffer); #endif /* __cpp_lib_memory_resource >= 201603L */ -/// \brief Combines data slice with boolean flag to represent result of certain -/// operations. +/// \brief Combines data slice with boolean flag to represent result of certain operations. struct value_result { slice value; bool done; @@ -2758,8 +2727,7 @@ struct value_result { } }; -/// \brief Combines pair of slices for key and value to represent result of -/// certain operations. +/// \brief Combines pair of slices for key and value to represent result of certain operations. struct pair { using stl_pair = std::pair; slice key, value; @@ -2919,8 +2887,7 @@ MDBX_CXX01_CONSTEXPR_ENUM bool is_reverse(key_mode mode) noexcept { MDBX_CXX01_CONSTEXPR_ENUM bool is_msgpack(key_mode mode) noexcept { return mode == key_mode::msgpack; } -/// \brief Kind of the values and sorted multi-values with corresponding -/// comparison. +/// \brief Kind of the values and sorted multi-values with corresponding comparison. enum class value_mode { single = MDBX_DB_DEFAULTS, ///< Usual single value for each key. In terms of ///< keys, they are unique. @@ -3000,8 +2967,7 @@ MDBX_CXX01_CONSTEXPR_ENUM bool is_reverse(value_mode mode) noexcept { MDBX_CXX01_CONSTEXPR_ENUM bool is_msgpack(value_mode mode) noexcept { return mode == value_mode::msgpack; } -/// \brief A handle for an individual table (aka key-value space, maps or -/// sub-database) in the environment. +/// \brief A handle for an individual table (aka key-value space, maps or sub-database) in the environment. /// \see txn::open_map() \see txn::create_map() /// \see txn::clear_map() \see txn::drop_map() /// \see txn::get_handle_info() \see txn::get_map_stat() @@ -3130,12 +3096,10 @@ public: /// environment). intptr_t size_upper{default_value}; - /// \brief The growth step in bytes, must be greater than zero to allow the - /// database to grow. + /// \brief The growth step in bytes, must be greater than zero to allow the database to grow. intptr_t growth_step{default_value}; - /// \brief The shrink threshold in bytes, must be greater than zero to allow - /// the database to shrink. + /// \brief The shrink threshold in bytes, must be greater than zero to allow the database to shrink. intptr_t shrink_threshold{default_value}; /// \brief The database page size for new database creation @@ -3270,47 +3234,34 @@ public: static inline size_t pagesize_min() noexcept; /// \brief Returns the maximal database page size in bytes. static inline size_t pagesize_max() noexcept; - /// \brief Returns the minimal database size in bytes for specified page - /// size. + /// \brief Returns the minimal database size in bytes for specified page size. static inline size_t dbsize_min(intptr_t pagesize); - /// \brief Returns the maximal database size in bytes for specified page - /// size. + /// \brief Returns the maximal database size in bytes for specified page size. static inline size_t dbsize_max(intptr_t pagesize); - /// \brief Returns the minimal key size in bytes for specified table - /// flags. + /// \brief Returns the minimal key size in bytes for specified table flags. static inline size_t key_min(MDBX_db_flags_t flags) noexcept; /// \brief Returns the minimal key size in bytes for specified keys mode. static inline size_t key_min(key_mode mode) noexcept; - /// \brief Returns the maximal key size in bytes for specified page size and - /// table flags. + /// \brief Returns the maximal key size in bytes for specified page size and table flags. static inline size_t key_max(intptr_t pagesize, MDBX_db_flags_t flags); - /// \brief Returns the maximal key size in bytes for specified page size and - /// keys mode. + /// \brief Returns the maximal key size in bytes for specified page size and keys mode. static inline size_t key_max(intptr_t pagesize, key_mode mode); - /// \brief Returns the maximal key size in bytes for given environment and - /// table flags. + /// \brief Returns the maximal key size in bytes for given environment and table flags. static inline size_t key_max(const env &, MDBX_db_flags_t flags); - /// \brief Returns the maximal key size in bytes for given environment and - /// keys mode. + /// \brief Returns the maximal key size in bytes for given environment and keys mode. static inline size_t key_max(const env &, key_mode mode); - /// \brief Returns the minimal values size in bytes for specified table - /// flags. + /// \brief Returns the minimal values size in bytes for specified table flags. static inline size_t value_min(MDBX_db_flags_t flags) noexcept; - /// \brief Returns the minimal values size in bytes for specified values - /// mode. + /// \brief Returns the minimal values size in bytes for specified values mode. static inline size_t value_min(value_mode) noexcept; - /// \brief Returns the maximal value size in bytes for specified page size - /// and table flags. + /// \brief Returns the maximal value size in bytes for specified page size and table flags. static inline size_t value_max(intptr_t pagesize, MDBX_db_flags_t flags); - /// \brief Returns the maximal value size in bytes for specified page size - /// and values mode. + /// \brief Returns the maximal value size in bytes for specified page size and values mode. static inline size_t value_max(intptr_t pagesize, value_mode); - /// \brief Returns the maximal value size in bytes for given environment and - /// table flags. + /// \brief Returns the maximal value size in bytes for given environment and table flags. static inline size_t value_max(const env &, MDBX_db_flags_t flags); - /// \brief Returns the maximal value size in bytes for specified page size - /// and values mode. + /// \brief Returns the maximal value size in bytes for specified page size and values mode. static inline size_t value_max(const env &, value_mode); /// \brief Returns maximal size of key-value pair to fit in a single page @@ -3390,13 +3341,11 @@ public: /// \brief Make sure that the environment is not being used by other /// processes, or return an error otherwise. ensure_unused = MDBX_ENV_ENSURE_UNUSED, - /// \brief Wait until other processes closes the environment before - /// deletion. + /// \brief Wait until other processes closes the environment before deletion. wait_for_unused = MDBX_ENV_WAIT_FOR_UNUSED }; - /// \brief Removes the environment's files in a proper and multiprocess-safe - /// way. + /// \brief Removes the environment's files in a proper and multiprocess-safe way. #ifdef MDBX_STD_FILESYSTEM_PATH static bool remove(const MDBX_STD_FILESYSTEM_PATH &pathname, const remove_mode mode = just_remove); #endif /* MDBX_STD_FILESYSTEM_PATH */ @@ -3422,12 +3371,10 @@ public: /// \brief Return snapshot information about the MDBX environment. inline info get_info() const; - /// \brief Return statistics about the MDBX environment accordingly to the - /// specified transaction. + /// \brief Return statistics about the MDBX environment accordingly to the specified transaction. inline stat get_stat(const txn &) const; - /// \brief Return information about the MDBX environment accordingly to the - /// specified transaction. + /// \brief Return information about the MDBX environment accordingly to the specified transaction. inline info get_info(const txn &) const; /// \brief Returns the file descriptor for the DXB file of MDBX environment. @@ -3439,8 +3386,7 @@ public: /// Returns environment flags. inline MDBX_env_flags_t get_flags() const; - /// \brief Returns the maximum number of threads/reader slots for the - /// environment. + /// \brief Returns the maximum number of threads/reader slots for the environment. /// \see extra_runtime_option::max_readers inline unsigned max_readers() const; @@ -3824,8 +3770,7 @@ public: /// volume of dirty pages) in bytes. size_t size_max() const { return env().transaction_size_max(); } - /// \brief Returns current write transaction size (i.e.summary volume of dirty - /// pages) in bytes. + /// \brief Returns current write transaction size (i.e.summary volume of dirty pages) in bytes. size_t size_current() const { assert(is_readwrite()); return size_t(get_info().txn_space_dirty); @@ -3984,42 +3929,32 @@ public: inline map_handle::info get_handle_info(map_handle map) const; using canary = ::MDBX_canary; - /// \brief Set integers markers (aka "canary") associated with the - /// environment. + /// \brief Set integers markers (aka "canary") associated with the environment. inline txn &put_canary(const canary &); - /// \brief Returns fours integers markers (aka "canary") associated with the - /// environment. + /// \brief Returns fours integers markers (aka "canary") associated with the environment. inline canary get_canary() const; - /// Reads sequence generator associated with a key-value map (aka - /// table). + /// Reads sequence generator associated with a key-value map (aka table). inline uint64_t sequence(map_handle map) const; - /// \brief Reads and increment sequence generator associated with a key-value - /// map (aka table). + /// \brief Reads and increment sequence generator associated with a key-value map (aka table). inline uint64_t sequence(map_handle map, uint64_t increment); - /// \brief Compare two keys according to a particular key-value map (aka - /// table). + /// \brief Compare two keys according to a particular key-value map (aka table). inline int compare_keys(map_handle map, const slice &a, const slice &b) const noexcept; - /// \brief Compare two values according to a particular key-value map (aka - /// table). + /// \brief Compare two values according to a particular key-value map (aka table). inline int compare_values(map_handle map, const slice &a, const slice &b) const noexcept; - /// \brief Compare keys of two pairs according to a particular key-value map - /// (aka table). + /// \brief Compare keys of two pairs according to a particular key-value map (aka table). inline int compare_keys(map_handle map, const pair &a, const pair &b) const noexcept; - /// \brief Compare values of two pairs according to a particular key-value map - /// (aka table). + /// \brief Compare values of two pairs according to a particular key-value map(aka table). inline int compare_values(map_handle map, const pair &a, const pair &b) const noexcept; /// \brief Get value by key from a key-value map (aka table). inline slice get(map_handle map, const slice &key) const; - /// \brief Get first of multi-value and values count by key from a key-value - /// multimap (aka table). + /// \brief Get first of multi-value and values count by key from a key-value multimap (aka table). inline slice get(map_handle map, slice key, size_t &values_count) const; /// \brief Get value by key from a key-value map (aka table). inline slice get(map_handle map, const slice &key, const slice &value_at_absence) const; - /// \brief Get first of multi-value and values count by key from a key-value - /// multimap (aka table). + /// \brief Get first of multi-value and values count by key from a key-value multimap (aka table). inline slice get(map_handle map, slice key, size_t &values_count, const slice &value_at_absence) const; /// \brief Get value for equal or great key from a table. /// \return Bundle of key-value pair and boolean flag, @@ -4518,12 +4453,10 @@ public: //---------------------------------------------------------------------------- - /// \brief Renew/bind a cursor with a new transaction and previously used - /// key-value map handle. + /// \brief Renew/bind a cursor with a new transaction and previously used key-value map handle. inline void renew(::mdbx::txn &txn); - /// \brief Bind/renew a cursor with a new transaction and specified key-value - /// map handle. + /// \brief Bind/renew a cursor with a new transaction and specified key-value map handle. inline void bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle); /// \brief Unbind cursor from a transaction. @@ -4556,12 +4489,10 @@ public: value_result try_insert(const pair &kv) { return try_insert(kv.key, kv.value); } void upsert(const pair &kv) { return upsert(kv.key, kv.value); } - /// \brief Removes single key-value pair or all multi-values at the current - /// cursor position. + /// \brief Removes single key-value pair or all multi-values at the current cursor position. inline bool erase(bool whole_multivalue = false); - /// \brief Seeks and removes first value or whole multi-value of the given - /// key. + /// \brief Seeks and removes first value or whole multi-value of the given key. /// \return `True` if the key is found and a value(s) is removed. inline bool erase(const slice &key, bool whole_multivalue = true); From 2aa47f20c34671ffa0b79b359e5b67d2cb689606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 17 Mar 2025 18:38:10 +0300 Subject: [PATCH 112/181] =?UTF-8?q?mdbx-tests:=20=D0=BF=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D1=85=D0=B2=D0=B0=D1=82=20=D0=B8=20=D0=BB=D0=BE=D0=B3=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B8=D1=81=D0=BA?= =?UTF-8?q?=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=B2=20extra-C++?= =?UTF-8?q?=20=D1=82=D0=B5=D1=81=D1=82=D0=B0=D1=85.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/crunched_delete.c++ | 19 +++++++++++++------ test/extra/cursor_closing.c++ | 19 +++++++++++++------ test/extra/dbi.c++ | 19 +++++++++++++------ test/extra/doubtless_positioning.c++ | 16 ++++++++++++---- test/extra/dupfix_addodd.c | 2 +- test/extra/dupfix_multiple.c++ | 7 +++---- test/extra/early_close_dbi.c++ | 17 +++++++++++++---- test/extra/hex_base64_base58.c++ | 16 ++++++++++++---- test/extra/maindb_ordinal.c++ | 18 +++++++++++++----- test/extra/open.c++ | 19 +++++++++++++------ test/extra/txn.c++ | 19 +++++++++++++------ 11 files changed, 119 insertions(+), 52 deletions(-) diff --git a/test/extra/crunched_delete.c++ b/test/extra/crunched_delete.c++ index 134dbafe..af2e6fad 100644 --- a/test/extra/crunched_delete.c++ +++ b/test/extra/crunched_delete.c++ @@ -349,12 +349,7 @@ bool simple(mdbx::env env) { return true; } -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - - mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); - +int doit() { mdbx::path db_filename = "test-crunched-del"; mdbx::env::remove(db_filename); @@ -392,3 +387,15 @@ int main(int argc, const char *argv[]) { std::cout << "OK\n"; return EXIT_SUCCESS; } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/cursor_closing.c++ b/test/extra/cursor_closing.c++ index 60749dbd..5f575c89 100644 --- a/test/extra/cursor_closing.c++ +++ b/test/extra/cursor_closing.c++ @@ -316,12 +316,7 @@ bool case1(mdbx::env env) { //-------------------------------------------------------------------------------------------- -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - - mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); - +int doit() { mdbx::path db_filename = "test-cursor-closing"; mdbx::env::remove(db_filename); @@ -339,3 +334,15 @@ int main(int argc, const char *argv[]) { return EXIT_FAILURE; } } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/dbi.c++ b/test/extra/dbi.c++ index fe238415..9aca25a5 100644 --- a/test/extra/dbi.c++ +++ b/test/extra/dbi.c++ @@ -11,12 +11,7 @@ static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int li fprintf(stdout, "%s:%u %s", function, line, msg); } -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - - mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); - +int doit() { mdbx::path db_filename = "test-dbi"; mdbx::env::remove(db_filename); @@ -71,3 +66,15 @@ int main(int argc, const char *argv[]) { std::cout << "OK\n"; return EXIT_SUCCESS; } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/doubtless_positioning.c++ b/test/extra/doubtless_positioning.c++ index ecc24daa..a7a50e41 100644 --- a/test/extra/doubtless_positioning.c++ +++ b/test/extra/doubtless_positioning.c++ @@ -211,10 +211,7 @@ static bool test(mdbx::txn txn, mdbx::map_handle dbi) { return ok; } -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - +int doit() { mdbx::path db_filename = "test-posi"; mdbx::env_managed::remove(db_filename); mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters(3)); @@ -243,3 +240,14 @@ int main(int argc, const char *argv[]) { std::cout << "OK\n"; return EXIT_SUCCESS; } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/dupfix_addodd.c b/test/extra/dupfix_addodd.c index 7d976f9b..4d79b27e 100644 --- a/test/extra/dupfix_addodd.c +++ b/test/extra/dupfix_addodd.c @@ -25,7 +25,7 @@ int main() { MDBX_val key, data; MDBX_txn *txn = NULL; - const char *db_filename = "./example-db"; + const char *db_filename = "./test-dupfix-addodd"; mdbx_env_delete(db_filename, MDBX_ENV_JUST_DELETE); rc = mdbx_env_create(&env); diff --git a/test/extra/dupfix_multiple.c++ b/test/extra/dupfix_multiple.c++ index ecc02bc7..f4aa94be 100644 --- a/test/extra/dupfix_multiple.c++ +++ b/test/extra/dupfix_multiple.c++ @@ -9,7 +9,7 @@ using buffer = mdbx::default_buffer; bool case1_ordering(mdbx::env env) { auto txn = env.start_write(); - auto map = txn.create_map(nullptr, mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal); + auto map = txn.create_map("case1", mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal); txn.insert(map, buffer::key_from_u64(21), buffer::key_from_u64(18)); txn.insert(map, buffer::key_from_u64(7), buffer::key_from_u64(19)); @@ -175,7 +175,7 @@ bool case1_ordering(mdbx::env env) { bool case2_batch_read(mdbx::env env) { auto txn = env.start_write(); - auto map = txn.create_map(nullptr, mdbx::key_mode::usual, mdbx::value_mode::multi_samelength); + auto map = txn.create_map("case2", mdbx::key_mode::usual, mdbx::value_mode::multi_samelength); txn.upsert(map, mdbx::slice("key1"), mdbx::slice("val1")); txn.upsert(map, mdbx::pair("key1", "val2")); txn.upsert(map, mdbx::pair("key1", "val3")); @@ -270,7 +270,7 @@ bool case3_put_a_lot(mdbx::env env) { int doit() { mdbx::path db_filename = "test-dupfix-multiple"; mdbx::env_managed::remove(db_filename); - mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters(1)); + mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters(3)); bool ok = case1_ordering(env); ok = case2_batch_read(env) && ok; @@ -288,7 +288,6 @@ int doit() { int main(int argc, const char *argv[]) { (void)argc; (void)argv; - try { return doit(); } catch (const std::exception &ex) { diff --git a/test/extra/early_close_dbi.c++ b/test/extra/early_close_dbi.c++ index 3eeea42c..cb5d1b6d 100644 --- a/test/extra/early_close_dbi.c++ +++ b/test/extra/early_close_dbi.c++ @@ -1,13 +1,11 @@ #include "mdbx.h++" #include +#include static const char *const testkey = "testkey"; static uint64_t testval = 11; -int main(int argc, char *argv[]) { - (void)argc; - (void)argv; - +int doit() { mdbx::path db_filename = "test-early_close_dbi"; mdbx::env_managed::remove(db_filename); @@ -126,3 +124,14 @@ int main(int argc, char *argv[]) { return 0; } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/hex_base64_base58.c++ b/test/extra/hex_base64_base58.c++ index 972673e9..6196d348 100644 --- a/test/extra/hex_base64_base58.c++ +++ b/test/extra/hex_base64_base58.c++ @@ -75,10 +75,7 @@ static bool basic() { return ok; } -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - +int doit() { auto ok = basic(); for (size_t n = 0; n < 1000; ++n) { for (size_t length = 0; ok && length < 111; ++length) { @@ -108,3 +105,14 @@ int main(int argc, const char *argv[]) { std::cout << "OK\n"; return EXIT_SUCCESS; } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/maindb_ordinal.c++ b/test/extra/maindb_ordinal.c++ index 9e6bd7ef..359cff89 100644 --- a/test/extra/maindb_ordinal.c++ +++ b/test/extra/maindb_ordinal.c++ @@ -4,11 +4,8 @@ #include "mdbx.h++" #include -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - - mdbx::path db_filename = "test-dupfix-multiple"; +static int doit() { + mdbx::path db_filename = "test-maindb-ordinal"; mdbx::env_managed::remove(db_filename); mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters()); @@ -51,3 +48,14 @@ int main(int argc, const char *argv[]) { return EXIT_SUCCESS; #endif /* __cpp_lib_string_view >= 201606L */ } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/open.c++ b/test/extra/open.c++ index 459ca708..353b848e 100644 --- a/test/extra/open.c++ +++ b/test/extra/open.c++ @@ -25,12 +25,7 @@ static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int li fprintf(stdout, "%s:%u %s", function, line, msg); } -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - - mdbx_setup_debug_nofmt(MDBX_LOG_VERBOSE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); - +int doit() { mdbx::path path = "test-open"; mdbx::env::remove(path); @@ -86,4 +81,16 @@ int main(int argc, const char *argv[]) { return EXIT_SUCCESS; } +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + mdbx_setup_debug_nofmt(MDBX_LOG_VERBOSE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} + #endif /* __cpp_lib_latch */ diff --git a/test/extra/txn.c++ b/test/extra/txn.c++ index e1abb1e6..583328cf 100644 --- a/test/extra/txn.c++ +++ b/test/extra/txn.c++ @@ -308,12 +308,7 @@ bool case2(const mdbx::path &path, bool no_sticky_threads) { return true; } -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - - mdbx_setup_debug_nofmt(MDBX_LOG_VERBOSE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); - +int doit() { mdbx::path path = "test-txn"; mdbx::env::remove(path); @@ -326,4 +321,16 @@ int main(int argc, const char *argv[]) { return ok ? EXIT_SUCCESS : EXIT_FAILURE; } +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + mdbx_setup_debug_nofmt(MDBX_LOG_VERBOSE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} + #endif /* __cpp_lib_latch */ From 694626727ff71619a4457ab03740b9a0fb3e8434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 18 Mar 2025 10:44:08 +0300 Subject: [PATCH 113/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20`cmp=5Flenfa?= =?UTF-8?q?st()`=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20`cmp=5Flenfast()?= =?UTF-8?q?`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-txn-data.c | 2 +- src/cursor.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api-txn-data.c b/src/api-txn-data.c index cc0891cb..d5efe74a 100644 --- a/src/api-txn-data.c +++ b/src/api-txn-data.c @@ -411,7 +411,7 @@ int mdbx_replace_ex(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val * } if (is_modifable(txn, page)) { - if (new_data && cmp_lenfast(&present_data, new_data) == 0) { + if (new_data && eq_fast(&present_data, new_data)) { /* если данные совпадают, то ничего делать не надо */ *old_data = *new_data; goto bailout; diff --git a/src/cursor.c b/src/cursor.c index 233c2246..9cc24f59 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -766,7 +766,7 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig goto skip_check_samedata; } } - if (!(flags & MDBX_RESERVE) && unlikely(cmp_lenfast(¤t_data, data) == 0)) + if (!(flags & MDBX_RESERVE) && unlikely(eq_fast(¤t_data, data))) return MDBX_SUCCESS /* the same data, nothing to update */; skip_check_samedata:; } From 2fd1772503c84bf9fd297993c51d5d45cb5ba079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 18 Mar 2025 13:14:47 +0300 Subject: [PATCH 114/181] =?UTF-8?q?mdbx-tests:=20=D1=83=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B5=D0=B2=D1=8B?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BD=D0=B5=D0=BD=D0=BD=D0=BE=D0=B3=D0=BE=20?= =?UTF-8?q?=D0=B4=D0=BE=D1=81=D1=82=D1=83=D0=BF=D0=B0=20=D0=B2=20extra/clo?= =?UTF-8?q?se-dbi=20=D0=B4=D0=BB=D1=8F=20UBSAN.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/early_close_dbi.c++ | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/extra/early_close_dbi.c++ b/test/extra/early_close_dbi.c++ index cb5d1b6d..0ed94fb6 100644 --- a/test/extra/early_close_dbi.c++ +++ b/test/extra/early_close_dbi.c++ @@ -65,13 +65,13 @@ int doit() { assert(err == MDBX_SUCCESS); err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval); assert(err == MDBX_SUCCESS); - assert(testval == *reinterpret_cast(mdbxval.iov_base)); + assert(testval == mdbx::slice(mdbxval).as_uint64()); err = mdbx_put(transaction, textindex, &mdbxkey, &mdbxput, MDBX_NOOVERWRITE); assert(err == MDBX_KEYEXIST); err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval); assert(err == MDBX_SUCCESS); - assert(testval == *reinterpret_cast(mdbxval.iov_base)); + assert(testval == mdbx::slice(mdbxval).as_uint64()); err = mdbx_dbi_flags_ex(transaction, textindex, &dbi_flags, &dbi_state); assert(err == MDBX_SUCCESS); @@ -87,7 +87,7 @@ int doit() { assert(err == MDBX_SUCCESS); err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval); assert(err == MDBX_SUCCESS); - assert(testval == *reinterpret_cast(mdbxval.iov_base)); + assert(testval == mdbx::slice(mdbxval).as_uint64()); err = mdbx_dbi_close(environment, textindex); assert(err == MDBX_SUCCESS); From 917e2827f53ab0cc2c7d154502f1d88ccfb4e70b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Wed, 19 Mar 2025 02:51:28 +0300 Subject: [PATCH 115/181] =?UTF-8?q?mdbx-tests:=20=D0=BA=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D0=BD=D0=BE=D0=B5=20=D1=81=D0=BE=D0=BA=D1=80=D0=B0=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B8=D1=82=D0=B5=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B9=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=20=D0=B2=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=81=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D0=B8=20?= =?UTF-8?q?=D0=BE=D1=82=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=D1=83=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8=20Valgrind/Debug/CI.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/CMakeLists.txt | 4 ++-- test/extra/crunched_delete.c++ | 18 +++++++++++++----- test/extra/cursor_closing.c++ | 34 +++++++++++++++++++++++++--------- test/extra/dupfix_multiple.c++ | 24 +++++++++++++++++++----- test/extra/txn.c++ | 16 +++++++++++++++- 5 files changed, 74 insertions(+), 22 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d4dfc086..dda4a909 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -300,10 +300,10 @@ else() endif() if(MDBX_BUILD_CXX) if(NOT WIN32 OR NOT MDBX_CXX_STANDARD LESS 17) - add_extra_test(cursor_closing) + add_extra_test(cursor_closing TIMEOUT 10800) add_extra_test(early_close_dbi) add_extra_test(maindb_ordinal) - add_extra_test(dupfix_multiple) + add_extra_test(dupfix_multiple TIMEOUT 10800) add_extra_test(doubtless_positioning TIMEOUT 10800) add_extra_test(crunched_delete TIMEOUT 10800) add_extra_test(dbi) diff --git a/test/extra/crunched_delete.c++ b/test/extra/crunched_delete.c++ index af2e6fad..4b740664 100644 --- a/test/extra/crunched_delete.c++ +++ b/test/extra/crunched_delete.c++ @@ -5,13 +5,21 @@ #include #include -#if MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) -#define NN 1024 -#elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul -#define NN 4096 +#if defined(ENABLE_MEMCHECK) || defined(MDBX_CI) +#if MDBX_DEBUG || !defined(NDEBUG) +#define RELIEF_FACTOR 16 #else -#define NN 2048 +#define RELIEF_FACTOR 8 #endif +#elif MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) +#define RELIEF_FACTOR 4 +#elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul +#define RELIEF_FACTOR 2 +#else +#define RELIEF_FACTOR 1 +#endif + +#define NN (2048 / RELIEF_FACTOR) std::string format_va(const char *fmt, va_list ap) { va_list ones; diff --git a/test/extra/cursor_closing.c++ b/test/extra/cursor_closing.c++ index 5f575c89..24633560 100644 --- a/test/extra/cursor_closing.c++ +++ b/test/extra/cursor_closing.c++ @@ -9,6 +9,22 @@ #include #endif +#if defined(ENABLE_MEMCHECK) || defined(MDBX_CI) +#if MDBX_DEBUG || !defined(NDEBUG) +#define RELIEF_FACTOR 16 +#else +#define RELIEF_FACTOR 8 +#endif +#elif MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) +#define RELIEF_FACTOR 4 +#elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul +#define RELIEF_FACTOR 2 +#else +#define RELIEF_FACTOR 1 +#endif + +#define NN (1000 / RELIEF_FACTOR) + static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg, unsigned length) noexcept { (void)length; @@ -113,10 +129,10 @@ void case1_shuffle_pool(std::vector &pool) { void case1_read_pool(std::vector &pool) { for (auto c : pool) if (flipcoin()) - mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(1000)), mdbx::slice::wrap(prng(1000)), false); + mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(NN)), mdbx::slice::wrap(prng(NN)), false); for (auto c : pool) if (flipcoin()) - mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(1000)), mdbx::slice::wrap(prng(1000)), false); + mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(NN)), mdbx::slice::wrap(prng(NN)), false); } MDBX_cursor *case1_try_unbind(MDBX_cursor *cursor) { @@ -224,9 +240,9 @@ void case1_write_cycle(mdbx::txn_managed txn, std::deque &dbi, pre.unbind(); if (!pre.txn()) pre.bind(txn, dbi[prng(dbi.size())]); - for (auto i = 0; i < 1000; ++i) { - auto k = mdbx::default_buffer::wrap(prng(1000)); - auto v = mdbx::default_buffer::wrap(prng(1000)); + for (auto i = 0; i < NN; ++i) { + auto k = mdbx::default_buffer::wrap(prng(NN)); + auto v = mdbx::default_buffer::wrap(prng(NN)); if (pre.find_multivalue(k, v, false)) pre.erase(); else @@ -246,8 +262,8 @@ void case1_write_cycle(mdbx::txn_managed txn, std::deque &dbi, bool case1_thread(mdbx::env env, std::deque dbi, mdbx::cursor pre) { salt = size_t(std::chrono::high_resolution_clock::now().time_since_epoch().count()); std::vector pool; - for (auto loop = 0; loop < 333; ++loop) { - for (auto read = 0; read < 333; ++read) { + for (auto loop = 0; loop < 333 / RELIEF_FACTOR; ++loop) { + for (auto read = 0; read < 333 / RELIEF_FACTOR; ++read) { auto txn = env.start_read(); case1_read_cycle(txn, dbi, pool, pre); if (flipcoin()) @@ -280,8 +296,8 @@ bool case1(mdbx::env env) { auto txn = env.start_write(); auto table = txn.create_map(std::to_string(t), mdbx::key_mode::ordinal, mdbx::value_mode::multi_samelength); auto cursor = txn.open_cursor(table); - for (size_t i = 0; i < 10000; ++i) - cursor.upsert(mdbx::default_buffer::wrap(prng(1000)), mdbx::default_buffer::wrap(prng(1000))); + for (size_t i = 0; i < NN * 11; ++i) + cursor.upsert(mdbx::default_buffer::wrap(prng(NN)), mdbx::default_buffer::wrap(prng(NN))); txn.commit(); cursors.push_back(std::move(cursor)); diff --git a/test/extra/dupfix_multiple.c++ b/test/extra/dupfix_multiple.c++ index f4aa94be..a18ebfc8 100644 --- a/test/extra/dupfix_multiple.c++ +++ b/test/extra/dupfix_multiple.c++ @@ -5,6 +5,20 @@ #include #include +#if defined(ENABLE_MEMCHECK) || defined(MDBX_CI) +#if MDBX_DEBUG || !defined(NDEBUG) +#define RELIEF_FACTOR 16 +#else +#define RELIEF_FACTOR 8 +#endif +#elif MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) +#define RELIEF_FACTOR 4 +#elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul +#define RELIEF_FACTOR 2 +#else +#define RELIEF_FACTOR 1 +#endif + using buffer = mdbx::default_buffer; bool case1_ordering(mdbx::env env) { @@ -224,7 +238,7 @@ static size_t prng() { static inline size_t prng(size_t range) { return prng() % range; } static mdbx::default_buffer_pair prng_kv(size_t n, size_t space) { - space = (space + !space) * 1024 * 32; + space = (space + !space) * 1024 * 32 / RELIEF_FACTOR; const size_t w = (n ^ 1455614549) * 1664525 + 1013904223; const size_t k = (prng(42 + w % space) ^ 1725278851) * 433750991; const size_t v = prng(); @@ -235,11 +249,11 @@ bool case3_put_a_lot(mdbx::env env) { salt = size_t(std::chrono::high_resolution_clock::now().time_since_epoch().count()); auto txn = env.start_write(); auto map = txn.create_map("case3", mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal); - for (size_t n = 0; n < 5555555; ++n) + for (size_t n = 0; n < 5555555 / RELIEF_FACTOR; ++n) txn.upsert(map, prng_kv(n, 1)); txn.commit(); - for (size_t t = 0; t < 555; ++t) { + for (size_t t = 0; t < 555 / RELIEF_FACTOR; ++t) { txn = env.start_write(); auto cursor = txn.open_cursor(map); for (size_t n = 0; n < 111; ++n) { @@ -247,7 +261,7 @@ bool case3_put_a_lot(mdbx::env env) { const auto r = 1 + prng(3); if (r & 1) { const auto k = prng_kv(n + t, 2).key; - for (size_t i = prng(42 + prng(111) * prng(111)); i > 0; --i) + for (size_t i = prng(42 + prng(111) * prng(111 / RELIEF_FACTOR)); i > 0; --i) v.push_back(prng()); txn.put_multiple_samelength(map, k, v, mdbx::upsert); } @@ -255,7 +269,7 @@ bool case3_put_a_lot(mdbx::env env) { const auto k = prng_kv(n + t, 2).key; if (cursor.seek(k)) { v.clear(); - for (size_t i = prng(42 + prng(111) * prng(111)); i > 0; --i) + for (size_t i = prng(42 + prng(111) * prng(111 / RELIEF_FACTOR)); i > 0; --i) v.push_back(prng()); cursor.put_multiple_samelength(k, v, mdbx::upsert); } diff --git a/test/extra/txn.c++ b/test/extra/txn.c++ index 583328cf..40f9ab0b 100644 --- a/test/extra/txn.c++ +++ b/test/extra/txn.c++ @@ -3,6 +3,20 @@ #include +#if defined(ENABLE_MEMCHECK) || defined(MDBX_CI) +#if MDBX_DEBUG || !defined(NDEBUG) +#define RELIEF_FACTOR 16 +#else +#define RELIEF_FACTOR 8 +#endif +#elif MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) +#define RELIEF_FACTOR 4 +#elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul +#define RELIEF_FACTOR 2 +#else +#define RELIEF_FACTOR 1 +#endif + #if !defined(__cpp_lib_latch) && __cpp_lib_latch < 201907L int main(int argc, const char *argv[]) { @@ -295,7 +309,7 @@ bool case2(const mdbx::path &path, bool no_sticky_threads) { for (size_t n = 0; n < 8; ++n) l.push_back(std::thread([&]() { s.wait(); - for (size_t i = 0; i < 1000000; ++i) { + for (size_t i = 0; i < 1000000 / RELIEF_FACTOR; ++i) { auto txn = env.start_read(); txn.abort(); } From e37194affe340455359c08d84c68cc0002c4bc31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Wed, 19 Mar 2025 23:50:29 +0300 Subject: [PATCH 116/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 02007336..141b0b65 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -11,7 +11,8 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx Благодарности: - [Erigon](https://docs.erigon.tech/) за спонсорство. - - [Alain Picard](https://github.com/castortech) for support [Java bindings](https://github.com/castortech/mdbxjni) and MacOS universal binaries patch for CMake build scenario. + - [Alain Picard](https://github.com/castortech) for support [Java bindings](https://github.com/castortech/mdbxjni) and MacOS universal binaries patch for CMake build scenario, + also for bug reporting (put-`MDBX_MULTIPLE` regression). Big thank for assistance with debugging and testing. - [Alex Sharov](https://github.com/AskAlexSharov) за сообщение об ошибках и тестирование. - [Виктору Логунову](https://t.me/vl_username) за сообщение об опечатки в имени переменной в Conan-рецепте. - [Илье Михееву](https://t.me/IlyaMkhv) за сообщение о лишнем/ненужном предупреждении несоответствия файла БД новому размеру. @@ -32,6 +33,23 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - Для закрытия или отсоединения всех курсоров с получением их количества в API добавлена функция `mdbx_txn_release_all_cursors_ex()`. + - Добавлена операция `MDBX_SEEK_AND_GET_MULTIPLE` в API курсора, позволяющая за одну операцию выполнить позиционирование + курсора на конкретное значение и начать чтение multi-значений в пакетном режиме. + + - Добавлены методы `mdbx::cursor::put_multiple_samelength()`, `mdbx::cursor::seek_multiple_samelength()`, `mdbx::cursor_managed::withdraw_handle()`. + + - В политику управления выделением для `mdbx::buffer` добавлен параметр `inplace_storage_size_rounding`. + Одновременно с этим переработан внутренний union-тип `mdbx::buffer::silo::bin` для возможности увеличения без пенальти встроенного в экземпляр буфера места под данные. + + - Добавлена опция `-c` (concise) для включения компактного режима в `mdbx_dump`, также поддержка таких дампов в `mdbx_load`. + В таких дампах значение ключей сохраняются однократно (не повторяются), что может существенно уменьшать результирующий объём для таблиц с multi-значениями (aka dupsort). + Однако, компактные дампы не совместимы с форматом ожидаемым/поддерживаемым в Berkeley Database и LMDB. + + - В API добавлена функция `mdbx_cursor_close2()` возвращающая код ошибки. + + - В chk-функционал добавлена гистограмма количества multi-значений/дубликатов. + При использовании утилиты `mdbx_chk`, для получения соответствующей (и массы другой) информации, достаточно увеличить детализацию несколько раз использовав опцию `-v`. + Изменение поведения: - Теперь при вставке данных в dupsort-таблицу CoW копирование целевых страниц выполняется после проверки отсутствия добавляемого значения среди уже присутствующих multi-значений (aka дубликатов). @@ -43,6 +61,20 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - Функция `mdbx_txn_release_all_cursors()` возвращает только код ошибки, не смешивая его с количеством обработанных/закрытых курсоров. Для аналогичных действий с получением количества закрытых курсоров в API добавлена функция `mdbx_txn_release_all_cursors_ex()`. + - Поддержка пустого набора данных в put-операции `MDBX_MULTIPLE` ради упрощения пользовательского кода, какой-либо модификации данных в БД при этом не происходит. + + - Для основных вариантов использования шаблона `mdbx::buffer<>` теперь явно инстанцируются внутри библиотеки, + одновременно соответствующие специализации шаблона помечены как `external` для предотвращения повторного инстанцирования в пользовательском коде. + + - Запрещена отвязка/открепление курсоров во вложенных транзакциях, т.е. вызовы `mdbx_cursor_unbind()` и + `mdbx_txn_release_all_cursors(unbind=true)` для курсоров открытых в одной из родительских транзакций. + Причина в том, что в случае отмены вложенной транзакции возникает неконструктивная неопределенность + — следует ли восстанавливать состояние курсоров. Если не восстанавливать, то получается что вложенная транзакция может + поломать родительскую, сделав её продолжение невозможным. Если восстанавливать, то также следует «воскрешать» закрытые + курсоры, что неизбежно приведет к путанице, утечкам памяти и использованию после освобождения. + + - В C++ API отменён вброс исключения при запросе транзакции у отсоединённого курсора посредством вывоза `mdbx::cursor::txn()`. + Исправления: - Устранён регресс допускающий SIGSEGV в операциях обновления после вытеснения/spilling страниц в больших транзакциях. @@ -72,6 +104,32 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - Устранена причина попыток рекурсивного захвата мьютекса при работе `mdbx_chk -w` в сборах с поддержкой Valring/ASAN и под управлением этих инструментов. + - Устранена вероятность ситуации гонки в `tbl_setup(MDBX_DUPFIXED | MDBX_INTEGERDUP)` при работе в разных потоках. + В реальных сценариях вероятность проявления проблемы была близка к нулю. + Для подробностей смотрите комментарий коммита `3e91500fac475947f5b58268d5edd3c9cc4f77f6`. + + - Устранён регресс затенения курсоров во вложенных транзакциях. + При реализации отложенной/ленивой инициализации dbi-дескрипторов также было реализовано отложенное затенение курсоров (создание копии состояния для отката при прерывании транзакции), + что существенно уменьшало накладные расходы при старте и завершении вложенных транзакций в сценариях с большим количеством курсоров. + Однако, была допущена логическая ошибка, вследствие которой отложенная инициализация и затенение выполнялись при использовании dbi-дескрипторов, но не курсора открытого в родительской транзакции. + В результате, родительские курсоры во вложенных транзакциях могли не затеняться, что приводило к неконсистентному состоянию в случае + прерывания/откате вложенной транзакции и в соответствующей таблицы были изменения в рамках прерванной вложенной транзакции. + Проблема не реализовывалась в тестовых сценариях и не была замечена при эксплуатации, но была обнаружена при расширении тестов. + Ошибка присутствует в версиях 0.13.x и последующих, начиная с коммита `e6af7d7c53428ca2892bcbf7eec1c2acee06fd44` от 2023-11-05. + + - Устранён регресс в пути обработки операции `MDBX_MULTIPLE`. + Пакетная вставка значений посредством `MDBX_MULTIPLE` могла приводить к падениям и повреждению структуры БД. Ошибка оставалось не + замеченной из-за специфических условий проявления, которые не реализовались в тестах. + Проблема присутствовала во всех выпусках начиная с v0.13.1, но соответствующая ошибка не связана с конкретным коммита в истории, а + является следствием нескольких доработок (шагов рефакторинга), которые суммарно привели к регрессу. + Технически ошибка обусловлена не-обнулением переменной, чего не происходило в некотором пути выполнения, так как исходно не требовалось. + Однако, такое обнуление потребовалось после ряда этапов оптимизации и рефакторинга смежных участков кода. + Для подробностей смотрите комментарий коммита `23a417fe19614481c6546845995d6dc845baf797`. + + - Скорректировано описание ошибки `MDBX_MVCC_RETARDED` и текста соответствующего сообщения. + + - В C++ API добавлена упущенная проверка `__cpp_concepts >= 202002` для использования концептов C++. + Прочие доработки: - Существенный рефакторинг с реструктуризацией кода, переименованием внутренних структур, их полей и внутренних функций. @@ -81,6 +139,22 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - Добавлены дополнительные проверки сигнатур курсоров при итерации связанных списков. + - Кратное сокращение итераций тестов в зависимости от конфигурации Valgrind/Debug/CI. + + - Устранены предупреждения UBASN о невыравненном доступе в тесте extra/close-dbi. + + - Добавлен перехват и логирование исключений в extra-тестах на C++. + + - Расширены тесты extra/dupfix-multiple, extra/cursor-closing и extra/txn. + + - В утилиту тестирования добавлена поддержка режима/опции `MDBX_VALIDATION` и поддержка значений `on`/`off` для опций командной строки. + + - Добавлены doxygen-описания для doubtless-positioning констант. + + - Переработана проверка курсоров на входе в API-функций с добавлением `cursor_check()`, `cursor_reset()` и `cursor_drown()`. + + - Отключено использование C23 `[[атрибутов]]` для версий CLANG меньше 20. + -------------------------------------------------------------------------------- @@ -115,6 +189,45 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx ******************************************************************************** +## v0.13.4 "Sigma Boy" от 2025-02-14 + +Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов. + +Благодарности: + + - [Erigon](https://docs.erigon.tech/) за спонсорство. + - [Алексею Костюку (aka Keller)](https://t.me/keller18306) за сообщения об ошибках и недочетах. + - [Alain Picard](https://github.com/castortech) for support [Java bindings](https://github.com/castortech/mdbxjni) and MacOS universal binaries patch for CMake build scenario. + - [Alex Sharov](https://github.com/AskAlexSharov) за сообщение об ошибках и тестирование. + - [Виктору Логунову](https://t.me/vl_username) за сообщение об опечатки в имени переменной в Conan-рецепте. + +Новое: + + - Поддержка MacOS universal binaries при сборке посредством CMake. + +Исправления: + + - Устранён регресс допускающий SIGSEGV в операциях обновления после вытеснения/spilling страниц в больших транзакциях. + Ошибка присутствует в выпусках v0.13.1, v0.13.2, v0.13.3 и оставалась незамеченной из-за специфических условий и низкой вероятности проявления. + Более подробная информация в описании коммита `21630ea115690a5cb39cfa921f9d199271a08102`. + + - Исправлена опечатка в документации в упоминании `mdbx_env_resurrect_after_fork()`. + + - Исправлена опечатка в условном операторе внутри `cursor_touch()`. + При переделке курсоров было пропущено отрицание в условии, при оценке количества страниц, которые могут потребоваться для выполнения операции. + В текущем понимании ошибка не приводила к каким-либо проблемам, ибо оценка делает по верхней границе с существенным запасом, а в худшем + случае это могло приводить к прерыванию транзакции из-за достижения ограничения на кол-во грязных страниц. + + - Корректировка излишне строгого условия в assert-проверке внутри `recalculate_subpage_thresholds()`. + Ошибка могла проявляться только в отладочных сборках при выставлении определенной комбинации предельных значений опций `MDBX_opt_subpage_limit`, + `MDBX_opt_subpage_room_threshold`, `MDBX_opt_subpage_reserve_prereq`, `MDBX_opt_subpage_reserve_limit`. + + - Исправление опечатки в Conan-рецепте в коде протокольно-отладочного вывода в имени переменной `version_json_pathname`. + + +-------------------------------------------------------------------------------- + + ## v0.13.3 "Королёв" от 2025-01-12 Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов From 49e6bd9296e0396427cc47e013fc4a49e8971078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 00:29:20 +0300 Subject: [PATCH 117/181] =?UTF-8?q?mdbx++:=20=D0=B8=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20`mdbx?= =?UTF-8?q?=5Ftxn=5Frelease=5Fall=5Fcursors=5Fex()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mdbx.h++ b/mdbx.h++ index 62315f61..c0226157 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -5604,10 +5604,9 @@ inline cursor_managed txn::open_cursor(map_handle map) const { } inline size_t txn::release_all_cursors(bool unbind) const { - int err = ::mdbx_txn_release_all_cursors(handle_, unbind); - if (MDBX_UNLIKELY(err < 0)) - MDBX_CXX20_UNLIKELY error::throw_exception(err); - return size_t(err); + size_t count; + error::success_or_throw(::mdbx_txn_release_all_cursors_ex(handle_, unbind, &count)); + return count; } inline ::mdbx::map_handle txn::open_map(const ::mdbx::slice &name, const ::mdbx::key_mode key_mode, From 44467d088320a91a147f2dc4bf3b70a4e1ba638d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 00:30:01 +0300 Subject: [PATCH 118/181] =?UTF-8?q?mdbx-make:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=86=D0=B5=D0=BB=D0=B8?= =?UTF-8?q?=20`ninja-assertions`=20=D0=B8=20=D0=B5=D1=91=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BF=D1=80=D0=B8=20`make=20check`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GNUmakefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 355ce295..2d26a381 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -295,6 +295,10 @@ lib-shared libmdbx.$(SO_SUFFIX): mdbx-dylib.o $(call select_by,MDBX_BUILD_CXX,md @echo ' LD $@' $(QUIET)$(call select_by,MDBX_BUILD_CXX,$(CXX) $(CXXFLAGS),$(CC) $(CFLAGS)) $^ -pthread -shared $(LDFLAGS) $(call select_by,MDBX_BUILD_CXX,$(LIB_STDCXXFS)) $(LIBS) -o $@ +ninja-assertions: CMAKE_OPT += -DMDBX_FORCE_ASSERTIONS=ON +ninja-assertions: cmake-build +ninja-debug: CMAKE_OPT += -DCMAKE_BUILD_TYPE=Debug +ninja-debug: cmake-build ninja: cmake-build cmake-build: @echo " RUN: cmake -G Ninja && cmake --build" @@ -424,7 +428,7 @@ MDBX_SMOKE_EXTRA ?= check: DESTDIR = $(shell pwd)/@check-install check: CMAKE_OPT = -Werror=dev -check: smoke-assertion ninja dist install test ctest +check: smoke-assertion ninja-assertions dist install test ctest smoke-assertion: MDBX_BUILD_OPTIONS:=$(strip $(MDBX_BUILD_OPTIONS) -DMDBX_FORCE_ASSERTIONS=1 -UNDEBUG -DMDBX_DEBUG=0) smoke-assertion: smoke @@ -660,7 +664,7 @@ release-assets: libmdbx-amalgamated-$(MDBX_GIT_3DOT).zpaq \ @echo -n ' VERIFY amalgamated sources...' $(QUIET)rm -rf $@ $(DIST_DIR)/@tmp-essentials.inc $(DIST_DIR)/@tmp-internals.inc \ && if grep -R "define xMDBX_ALLOY" dist | grep -q MDBX_BUILD_SOURCERY; then echo "sed output is WRONG!" >&2; exit 2; fi \ - && rm -rf @dist-check && cp -r -p $(DIST_DIR) @dist-check && ($(MAKE) -j IOARENA=false CXXSTD=$(CXXSTD) -C @dist-check all ninja >@dist-check.log 2>@dist-check.err || (cat @dist-check.err && exit 1)) \ + && rm -rf @dist-check && cp -r -p $(DIST_DIR) @dist-check && ($(MAKE) -j IOARENA=false CXXSTD=$(CXXSTD) -C @dist-check all ninja-assertions >@dist-check.log 2>@dist-check.err || (cat @dist-check.err && exit 1)) \ && touch $@ || (echo " FAILED! See @dist-check.log and @dist-check.err" >&2; exit 2) && echo " Ok" %.tar.gz: @dist-checked.tag From 4d454d6e804c8ed24295c472e3122f927af591e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 00:35:47 +0300 Subject: [PATCH 119/181] =?UTF-8?q?mdbx-cmake:=20=D1=80=D0=B0=D1=81=D1=88?= =?UTF-8?q?=D0=B8=D1=80=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=BE=D0=B8=D1=81?= =?UTF-8?q?=D0=BA=D0=B0=20`LLVMgold.so`=20=D0=B2=20=D0=BE=D1=82=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?lib-=D0=B4=D0=B8=D1=80=D0=B5=D0=BA=D1=82=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D1=8F=D1=85=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmake/compiler.cmake | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake index 5fefdbae..d9197e66 100644 --- a/cmake/compiler.cmake +++ b/cmake/compiler.cmake @@ -541,13 +541,21 @@ if(CMAKE_COMPILER_IS_CLANG) if(regexp_valid) string(REGEX REPLACE "(^|\n.*)(.*programs: =)([^\n]+)((\n.*)|$)" "\\3" list ${clang_search_dirs}) string(REPLACE ":" ";" list "${list}") + set(libs_extra_subdirs "lib;../lib;lib64;../lib64;lib32;../lib32") foreach(dir IN LISTS list) get_filename_component(dir "${dir}" REALPATH) if(dir MATCHES ".*llvm.*" OR dir MATCHES ".*clang.*") - list(APPEND clang_bindirs "${dir}") + set(list_suffix "") else() - list(APPEND clang_bindirs_x "${dir}") + set(list_suffix "_x") endif() + list(APPEND clang_bindirs${list_suffix} "${dir}") + foreach(subdir IN LISTS libs_extra_subdirs) + get_filename_component(subdir "${dir}/${subdir}" REALPATH) + if(EXISTS "${subdir}") + list(APPEND clang_libdirs${list_suffix} "${subdir}") + endif() + endforeach() endforeach() list(APPEND clang_bindirs "${clang_bindirs_x}") list(REMOVE_DUPLICATES clang_bindirs) @@ -559,10 +567,11 @@ if(CMAKE_COMPILER_IS_CLANG) foreach(dir IN LISTS list) get_filename_component(dir "${dir}" REALPATH) if(dir MATCHES ".*llvm.*" OR dir MATCHES ".*clang.*") - list(APPEND clang_libdirs "${dir}") + set(list_suffix "") else() - list(APPEND clang_libdirs_x "${dir}") + set(list_suffix "_x") endif() + list(APPEND clang_libdirs${list_suffix} "${dir}") endforeach() list(APPEND clang_libdirs "${clang_libdirs_x}") list(REMOVE_DUPLICATES clang_libdirs) From d6b359756c603b2ba18d32d3d1822b5064e7ac1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 00:40:02 +0300 Subject: [PATCH 120/181] =?UTF-8?q?mdbx-cmake:=20=D1=80=D0=B0=D1=81=D1=81?= =?UTF-8?q?=D0=BB=D0=B0=D0=B1=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=83=D1=81?= =?UTF-8?q?=D0=BB=D0=BE=D0=B2=D0=B8=D0=B9=20=D0=B4=D0=BB=D1=8F=20=D0=B8?= =?UTF-8?q?=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20LTO=20=D1=81=20CLANG=20=D0=BD=D0=B0=20Linux=20(b?= =?UTF-8?q?ackport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmake/compiler.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake index d9197e66..8cee26d4 100644 --- a/cmake/compiler.cmake +++ b/cmake/compiler.cmake @@ -665,7 +665,7 @@ if(CMAKE_COMPILER_IS_CLANG) AND CMAKE_CLANG_NM AND CMAKE_CLANG_RANLIB AND ((CLANG_LTO_PLUGIN AND CMAKE_LD_GOLD) - OR (CMAKE_CLANG_LD AND NOT (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_NAME STREQUAL "Linux")) + OR CMAKE_CLANG_LD OR APPLE)) if(ANDROID AND CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 12) set(CLANG_LTO_AVAILABLE FALSE) From f82b760b6e7ad7aed067f899d34265cad0f19b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 00:37:13 +0300 Subject: [PATCH 121/181] =?UTF-8?q?mdbx-cmake:=20=D0=B8=D0=B7=D0=B1=D0=B5?= =?UTF-8?q?=D0=B3=D0=B0=D0=B5=D0=BC=20=D0=B4=D0=B2=D0=BE=D0=B9=D0=BD=D0=BE?= =?UTF-8?q?=D0=B9=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20`compiler.cmake?= =?UTF-8?q?`=20=D0=B1=D0=B5=D0=B7=20=D0=BD=D0=B5=D0=BE=D0=B1=D1=85=D0=BE?= =?UTF-8?q?=D0=B4=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D0=B8=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f8a72d68..d4dfc086 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,8 +1,10 @@ # Copyright (c) 2020-2025 Леонид Юрьев aka Leonid Yuriev ############################################### # SPDX-License-Identifier: Apache-2.0 -enable_language(CXX) -include(../cmake/compiler.cmake) +if(NOT CMAKE_CXX_COMPILER_LOADED) + enable_language(CXX) + include(../cmake/compiler.cmake) +endif() function(add_extra_test name) set(options DISABLED) From 4f59864ef51345c455345aef70d63bc4c7b7f01d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 00:41:13 +0300 Subject: [PATCH 122/181] =?UTF-8?q?mdbx-cmake:=20=D0=B8=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D1=83=D0=B5=D0=BC=20`-flto=3Dauto`=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20GCC=20>=3D=2011.4=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit При сборке посредством GCC >= 11.4 больше не возникает предупреждений: lto-wrapper: warning: using serial compilation of # LTRANS jobs lto-wrapper: note: see the ‘-flto’ option documentation for more information Однако, использование auto-режима не является оптимальным решением, так как при параллельной сборке посредством make или ninja, каждая уже запущенная ветвь компиляции породит потоки ещё для каждого ядра ЦПУ. Таким образом реальная нагрузка может расти квадратично, т.е. чем больше у вас ядер -- тем хуже и при 96 ядрах может работать 9216 потоков сборки. Тем не менее, использование `job-server` в CMake пока не возможно, а при сборке libmdbx не так много работы чтобы чтобы обрушить систему нагрузкой. --- cmake/compiler.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake index 8cee26d4..a3d789ce 100644 --- a/cmake/compiler.cmake +++ b/cmake/compiler.cmake @@ -502,7 +502,11 @@ if(CMAKE_COMPILER_IS_GNU${CMAKE_PRIMARY_LANG} AND CMAKE_GCC_RANLIB AND gcc_lto_wrapper) message(STATUS "Found GCC's LTO toolset: ${gcc_lto_wrapper}, ${CMAKE_GCC_AR}, ${CMAKE_GCC_RANLIB}") - set(GCC_LTO_CFLAGS "-flto -fno-fat-lto-objects -fuse-linker-plugin") + if(CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 11.4) + set(GCC_LTO_CFLAGS "-flto -fno-fat-lto-objects -fuse-linker-plugin") + else() + set(GCC_LTO_CFLAGS "-flto=auto -fno-fat-lto-objects -fuse-linker-plugin") + endif() set(GCC_LTO_AVAILABLE TRUE) message(STATUS "Link-Time Optimization by GCC is available") else() From 32ca9691c391c2decdc3d638bbce22c67d4ccf11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 00:44:54 +0300 Subject: [PATCH 123/181] =?UTF-8?q?mdbx-doc:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D1=81=D1=8B=D0=BB?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=BD=D0=B0=20=D0=BF=D1=80=D0=B8=D0=B2=D1=8F?= =?UTF-8?q?=D0=B7=D0=BA=D1=83=20=D0=BA=20Zig=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1bad0676..69f67b9b 100644 --- a/README.md +++ b/README.md @@ -690,6 +690,7 @@ Bindings | Java | [mdbxjni](https://github.com/castortech/mdbxjni) | [Castor Technologies](https://castortech.com/) | | Go | [mdbx-go](https://github.com/torquem-ch/mdbx-go) | [Alex Sharov](https://github.com/AskAlexSharov) | | Ruby | [ruby-mdbx](https://rubygems.org/gems/mdbx/) | [Mahlon E. Smith](https://github.com/mahlonsmith) | +| Zig | [mdbx-zig](https://github.com/theseyan/lmdbx-zig) | [Sayan J. Das](https://github.com/theseyan) | ##### Obsolete/Outdated/Unsupported: From 4150f411dc8162765776683535f081525d6f873b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 00:45:57 +0300 Subject: [PATCH 124/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=B5=D1=80=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D0=B0=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0=20=D0=91=D0=94=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D0=BE=D1=82=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D0=B8?= =?UTF-8?q?=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Переработка 05cdf9d202b14ac09c801c7893e65271fa27f378. У предыдущего варианта был недостаток, при необходимости выдачи предупреждения и открытии БД с изменением геометрии, предупреждение не выдавалось, что может затруднять анализ/разбор проблемных ситуаций. --- src/dxb.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/dxb.c b/src/dxb.c index 2b3cc03a..c0d34719 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -567,7 +567,7 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit return err; } - bool new_size_from_user = false; + size_t expected_filesize = 0; const size_t used_bytes = pgno2bytes(env, header.geometry.first_unallocated); const size_t used_aligned2os_bytes = ceil_powerof2(used_bytes, globals.sys_pagesize); if ((env->flags & MDBX_RDONLY) /* readonly */ @@ -612,28 +612,25 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit } /* altering fields to match geometry given from user */ - new_size_from_user = header.geometry.now != bytes2pgno(env, env->geo_in_bytes.now); - if (new_size_from_user) - header.geometry.now = bytes2pgno(env, env->geo_in_bytes.now); + expected_filesize = pgno_align2os_bytes(env, header.geometry.now); + header.geometry.now = bytes2pgno(env, env->geo_in_bytes.now); header.geometry.lower = bytes2pgno(env, env->geo_in_bytes.lower); header.geometry.upper = bytes2pgno(env, env->geo_in_bytes.upper); header.geometry.grow_pv = pages2pv(bytes2pgno(env, env->geo_in_bytes.grow)); header.geometry.shrink_pv = pages2pv(bytes2pgno(env, env->geo_in_bytes.shrink)); - VERBOSE("amended: root %" PRIaPGNO "/%" PRIaPGNO ", geo %" PRIaPGNO "/%" PRIaPGNO "-%" PRIaPGNO "/%" PRIaPGNO + VERBOSE("amending: root %" PRIaPGNO "/%" PRIaPGNO ", geo %" PRIaPGNO "/%" PRIaPGNO "-%" PRIaPGNO "/%" PRIaPGNO " +%u -%u, txn_id %" PRIaTXN ", %s", header.trees.main.root, header.trees.gc.root, header.geometry.lower, header.geometry.first_unallocated, header.geometry.now, header.geometry.upper, pv2pages(header.geometry.grow_pv), pv2pages(header.geometry.shrink_pv), unaligned_peek_u64(4, header.txnid_a), durable_caption(&header)); } else { - /* fetch back 'now/current' size, since it was ignored during comparison - * and may differ. */ + /* fetch back 'now/current' size, since it was ignored during comparison and may differ. */ env->geo_in_bytes.now = pgno_align2os_bytes(env, header.geometry.now); } ENSURE(env, header.geometry.now >= header.geometry.first_unallocated); } else { - /* geo-params are not pre-configured by user, - * get current values from the meta. */ + /* geo-params are not pre-configured by user, get current values from the meta. */ env->geo_in_bytes.now = pgno2bytes(env, header.geometry.now); env->geo_in_bytes.lower = pgno2bytes(env, header.geometry.lower); env->geo_in_bytes.upper = pgno2bytes(env, header.geometry.upper); @@ -643,18 +640,19 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit ENSURE(env, pgno_align2os_bytes(env, header.geometry.now) == env->geo_in_bytes.now); ENSURE(env, env->geo_in_bytes.now >= used_bytes); + if (!expected_filesize) + expected_filesize = env->geo_in_bytes.now; const uint64_t filesize_before = env->dxb_mmap.filesize; if (unlikely(filesize_before != env->geo_in_bytes.now)) { if (lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE) { - VERBOSE("filesize mismatch (expect %" PRIuPTR "b/%" PRIaPGNO "p, have %" PRIu64 "b/%" PRIaPGNO "p), " - "assume other process working", + VERBOSE("filesize mismatch (expect %" PRIuPTR "b/%" PRIaPGNO "p, have %" PRIu64 "b/%" PRIu64 + "p), assume other process working", env->geo_in_bytes.now, bytes2pgno(env, env->geo_in_bytes.now), filesize_before, - bytes2pgno(env, (size_t)filesize_before)); + filesize_before >> env->ps2ln); } else { - if (!new_size_from_user) - WARNING("filesize mismatch (expect %" PRIuSIZE "b/%" PRIaPGNO "p, have %" PRIu64 "b/%" PRIaPGNO "p)", - env->geo_in_bytes.now, bytes2pgno(env, env->geo_in_bytes.now), filesize_before, - bytes2pgno(env, (size_t)filesize_before)); + if (filesize_before != expected_filesize) + WARNING("filesize mismatch (expect %" PRIuSIZE "b/%" PRIaPGNO "p, have %" PRIu64 "b/%" PRIu64 "p)", + expected_filesize, bytes2pgno(env, expected_filesize), filesize_before, filesize_before >> env->ps2ln); if (filesize_before < used_bytes) { ERROR("last-page beyond end-of-file (last %" PRIaPGNO ", have %" PRIaPGNO ")", header.geometry.first_unallocated, bytes2pgno(env, (size_t)filesize_before)); From d8f9f3ba5842f3be288049e2af0ac8a1be965125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 00:46:45 +0300 Subject: [PATCH 125/181] =?UTF-8?q?mdbx:=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D1=8F=D0=B5=D0=BC=20=D0=B2=D1=8B=D1=80=D0=B0=D0=B2=D0=BD?= =?UTF-8?q?=D0=B8=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B0=D0=B7=D0=BC?= =?UTF-8?q?=D0=B5=D1=80=D0=B0=20=D0=91=D0=94=20=D0=BD=D0=B0=20=D1=8E=D0=BD?= =?UTF-8?q?=D0=B8=D1=82=20=D0=B2=D1=8B=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BF=D0=B0=D0=BC=D1=8F=D1=82=D0=B8,=20=D0=B0=20?= =?UTF-8?q?=D0=BD=D0=B5=20=D0=BD=D0=B0=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D1=80=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D1=8B=20(ba?= =?UTF-8?q?ckport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Теоретически до этого коммита могла быть некоторая неувязка: - при открытии БД с размером страницы 4K на Windows (где размер секции кратен 64K) в режиме read-only, - после того как БД использовалась на POSIX (где размер отображения кратен размеру системной страницы). Ранее ошибка могла возвращаться со стороны системы (например INVALID_PARAMETER) и по ней крайне сложно было понять в чем дело. Теперь же будет логирование ошибки и возврат MDBX_WANNA_RECOVERY. --- src/dxb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dxb.c b/src/dxb.c index c0d34719..fa3b8f6e 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -660,8 +660,9 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit } if (env->flags & MDBX_RDONLY) { - if (filesize_before & (globals.sys_pagesize - 1)) { - ERROR("%s", "filesize should be rounded-up to system page"); + if (filesize_before & (globals.sys_allocation_granularity - 1)) { + ERROR("filesize should be rounded-up to system allocation granularity %u", + globals.sys_allocation_granularity); return MDBX_WANNA_RECOVERY; } WARNING("%s", "ignore filesize mismatch in readonly-mode"); From 15bd9cfc89e2a0875342030d4e335f4dce3a2c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 00:52:16 +0300 Subject: [PATCH 126/181] =?UTF-8?q?mdbx:=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20`const`=20=D1=83=20=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B2=20`cursor?= =?UTF-8?q?=5Fbind()`=20=D0=B8=20`cursor=5Frenew()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 6 +++--- mdbx.h++ | 8 ++++---- src/api-cursor.c | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mdbx.h b/mdbx.h index 99a34f49..728e6eb0 100644 --- a/mdbx.h +++ b/mdbx.h @@ -5131,7 +5131,7 @@ MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *mdbx_cursor_get_userctx(const MDBX_ * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. * \retval MDBX_EINVAL An invalid parameter was specified. */ -LIBMDBX_API int mdbx_cursor_bind(const MDBX_txn *txn, MDBX_cursor *cursor, MDBX_dbi dbi); +LIBMDBX_API int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *cursor, MDBX_dbi dbi); /** \brief Unbind cursor from a transaction. * \ingroup c_cursors @@ -5200,7 +5200,7 @@ LIBMDBX_API int mdbx_cursor_reset(MDBX_cursor *cursor); * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. * \retval MDBX_EINVAL An invalid parameter was specified. */ -LIBMDBX_API int mdbx_cursor_open(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **cursor); +LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **cursor); /** \brief Close a cursor handle. * \ingroup c_cursors @@ -5288,7 +5288,7 @@ LIBMDBX_INLINE_API(int, mdbx_txn_release_all_cursors, (const MDBX_txn *txn, bool * \retval MDBX_EINVAL An invalid parameter was specified. * \retval MDBX_BAD_DBI The cursor was not bound to a DBI-handle * or such a handle became invalid. */ -LIBMDBX_API int mdbx_cursor_renew(const MDBX_txn *txn, MDBX_cursor *cursor); +LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor); /** \brief Return the cursor's transaction handle. * \ingroup c_cursors diff --git a/mdbx.h++ b/mdbx.h++ index c0226157..e993f17f 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -4474,11 +4474,11 @@ public: /// \brief Renew/bind a cursor with a new transaction and previously used /// key-value map handle. - inline void renew(const ::mdbx::txn &txn); + inline void renew(::mdbx::txn &txn); /// \brief Bind/renew a cursor with a new transaction and specified key-value /// map handle. - inline void bind(const ::mdbx::txn &txn, ::mdbx::map_handle map_handle); + inline void bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle); /// \brief Unbind cursor from a transaction. inline void unbind(); @@ -6166,9 +6166,9 @@ inline cursor::estimate_result cursor::estimate(move_operation operation) const return estimate_result(*this, operation); } -inline void cursor::renew(const ::mdbx::txn &txn) { error::success_or_throw(::mdbx_cursor_renew(txn, handle_)); } +inline void cursor::renew(::mdbx::txn &txn) { error::success_or_throw(::mdbx_cursor_renew(txn, handle_)); } -inline void cursor::bind(const ::mdbx::txn &txn, ::mdbx::map_handle map_handle) { +inline void cursor::bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle) { error::success_or_throw(::mdbx_cursor_bind(txn, handle_, map_handle.dbi)); } diff --git a/src/api-cursor.c b/src/api-cursor.c index 1fefaf2a..9176b42c 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -23,7 +23,7 @@ MDBX_cursor *mdbx_cursor_create(void *context) { return &couple->outer; } -int mdbx_cursor_renew(const MDBX_txn *txn, MDBX_cursor *mc) { +int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) { return likely(mc) ? mdbx_cursor_bind(txn, mc, (kvx_t *)mc->clc - txn->env->kvs) : LOG_IFERR(MDBX_EINVAL); } @@ -40,7 +40,7 @@ int mdbx_cursor_reset(MDBX_cursor *mc) { return MDBX_SUCCESS; } -int mdbx_cursor_bind(const MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { +int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { if (unlikely(!mc)) return LOG_IFERR(MDBX_EINVAL); @@ -130,7 +130,7 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) { return MDBX_SUCCESS; } -int mdbx_cursor_open(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) { +int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) { if (unlikely(!ret)) return LOG_IFERR(MDBX_EINVAL); *ret = nullptr; From 69895e2b552699c58cccf62d9db5c0e910e93378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 00:57:17 +0300 Subject: [PATCH 127/181] =?UTF-8?q?mdbx-make:=20=D0=BF=D0=BE=D0=B8=D1=81?= =?UTF-8?q?=D0=BA=20`gnu-sed`=20=D0=BD=D0=B0=20Darwin/MacOS=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GNUmakefile | 57 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 2d26a381..4b7aa689 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -164,6 +164,10 @@ else $(info $(TIP) Use `make V=1` for verbose.) endif +ifeq ($(UNAME),Darwin) + $(info $(TIP) Use `brew install gnu-sed gnu-tar` and add ones to the beginning of the PATH.) +endif + all: show-options $(LIBRARIES) $(MDBX_TOOLS) help: @@ -396,6 +400,9 @@ TEST_ITER := $(shell $(uname2titer)) TEST_SRC := test/osal-$(TEST_OSAL).c++ $(filter-out $(wildcard test/osal-*.c++),$(wildcard test/*.c++)) $(call select_by,MDBX_BUILD_CXX,,src/mdbx.c++) TEST_INC := $(wildcard test/*.h++) TEST_OBJ := $(patsubst %.c++,%.o,$(TEST_SRC)) +ifndef SED +SED := $(shell which gnu-sed 2>&- || echo sed) +endif TAR ?= $(shell which gnu-tar 2>&- || echo tar) ZIP ?= $(shell which zip || echo "echo 'Please install zip'") CLANG_FORMAT ?= $(shell (which clang-format-19 || which clang-format) 2>/dev/null) @@ -412,11 +419,11 @@ MAN_SRCDIR := src/man1/ ALLOY_DEPS := $(shell git ls-files src/ | grep -e /tools -e /man -v) MDBX_GIT_DIR := $(shell if [ -d .git ]; then echo .git; elif [ -s .git -a -f .git ]; then grep '^gitdir: ' .git | cut -d ':' -f 2; else echo git_directory_is_absent; fi) MDBX_GIT_LASTVTAG := $(shell git describe --tags --dirty=-DIRTY --abbrev=0 '--match=v[0-9]*' 2>&- || echo 'Please fetch tags and/or install non-obsolete git version') -MDBX_GIT_3DOT := $(shell set -o pipefail; echo "$(MDBX_GIT_LASTVTAG)" | sed -n 's|^v*\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\(.*\)|\1|p' || echo 'Please fetch tags and/or use non-obsolete git version') +MDBX_GIT_3DOT := $(shell set -o pipefail; echo "$(MDBX_GIT_LASTVTAG)" | $(SED) -n 's|^v*\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\(.*\)|\1|p' || echo 'Please fetch tags and/or use non-obsolete git version') MDBX_GIT_TWEAK := $(shell set -o pipefail; git rev-list $(shell git describe --tags --abbrev=0 '--match=v[0-9]*')..HEAD --count 2>&- || echo 'Please fetch tags and/or use non-obsolete git version') MDBX_GIT_TIMESTAMP := $(shell git show --no-patch --format=%cI HEAD 2>&- || echo 'Please install latest get version') MDBX_GIT_DESCRIBE := $(shell git describe --tags --long --dirty '--match=v[0-9]*' 2>&- || echo 'Please fetch tags and/or install non-obsolete git version') -MDBX_GIT_PRERELEASE := $(shell echo "$(MDBX_GIT_LASTVTAG)" | sed -n 's|^v*\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\(.*\)-\([-.0-1a-zA-Z]\+\)|\3|p') +MDBX_GIT_PRERELEASE := $(shell echo "$(MDBX_GIT_LASTVTAG)" | $(SED) -n 's|^v*\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\(.*\)-\([-.0-1a-zA-Z]\+\)|\3|p') MDBX_VERSION_PURE = $(MDBX_GIT_3DOT)$(if $(filter-out 0,$(MDBX_GIT_TWEAK)),.$(MDBX_GIT_TWEAK),)$(if $(MDBX_GIT_PRERELEASE),-$(MDBX_GIT_PRERELEASE),) MDBX_VERSION_IDENT = $(shell set -o pipefail; echo -n '$(MDBX_GIT_DESCRIBE)' | tr -c -s '[a-zA-Z0-9.]' _) MDBX_VERSION_NODOT = $(subst .,_,$(MDBX_VERSION_IDENT)) @@ -556,7 +563,7 @@ $(MDBX_GIT_DIR)/HEAD $(MDBX_GIT_DIR)/index $(MDBX_GIT_DIR)/refs/tags: src/version.c: src/version.c.in $(lastword $(MAKEFILE_LIST)) $(MDBX_GIT_DIR)/HEAD $(MDBX_GIT_DIR)/index $(MDBX_GIT_DIR)/refs/tags LICENSE NOTICE @echo ' MAKE $@' - $(QUIET)sed \ + $(QUIET)$(SED) \ -e "s|@MDBX_GIT_TIMESTAMP@|$(MDBX_GIT_TIMESTAMP)|" \ -e "s|@MDBX_GIT_TREE@|$(shell git show --no-patch --format=%T HEAD || echo 'Please install latest get version')|" \ -e "s|@MDBX_GIT_COMMIT@|$(shell git show --no-patch --format=%H HEAD || echo 'Please install latest get version')|" \ @@ -590,7 +597,7 @@ mdbx-static.o: src/config.h src/version.c src/alloy.c $(ALLOY_DEPS) $(lastword $ docs/Doxyfile: docs/Doxyfile.in src/version.c $(lastword $(MAKEFILE_LIST)) @echo ' MAKE $@' - $(QUIET)sed \ + $(QUIET)$(SED) \ -e "s|@MDBX_GIT_TIMESTAMP@|$(MDBX_GIT_TIMESTAMP)|" \ -e "s|@MDBX_GIT_TREE@|$(shell git show --no-patch --format=%T HEAD || echo 'Please install latest get version')|" \ -e "s|@MDBX_GIT_COMMIT@|$(shell git show --no-patch --format=%H HEAD || echo 'Please install latest get version')|" \ @@ -606,7 +613,7 @@ docs/Doxyfile: docs/Doxyfile.in src/version.c $(lastword $(MAKEFILE_LIST)) define md-extract-section docs/__$(1).md: $(2) $(lastword $(MAKEFILE_LIST)) @echo ' EXTRACT $1' - $(QUIET)sed -n '//,//p' $(2) >$$@ && test -s $$@ + $(QUIET)$(SED) -n '//,//p' $(2) >$$@ && test -s $$@ endef $(foreach section,overview mithril characteristics improvements history usage performance bindings,$(eval $(call md-extract-section,$(section),README.md))) @@ -621,16 +628,16 @@ docs/overall.md: docs/__overview.md docs/_toc.md docs/__mithril.md docs/__histor docs/intro.md: docs/_preface.md docs/__characteristics.md docs/__improvements.md docs/_restrictions.md docs/__performance.md @echo ' MAKE $@' - $(QUIET)cat $^ | sed 's/^Performance comparison$$/Performance comparison {#performance}/;s/^Improvements beyond LMDB$$/Improvements beyond LMDB {#improvements}/' >$@ + $(QUIET)cat $^ | $(SED) 's/^Performance comparison$$/Performance comparison {#performance}/;s/^Improvements beyond LMDB$$/Improvements beyond LMDB {#improvements}/' >$@ docs/usage.md: docs/__usage.md docs/_starting.md docs/__bindings.md @echo ' MAKE $@' - $(QUIET)echo -e "\\page usage Usage\n\\section getting Building & Embedding" | cat - $^ | sed 's/^Bindings$$/Bindings {#bindings}/' >$@ + $(QUIET)echo -e "\\page usage Usage\n\\section getting Building & Embedding" | cat - $^ | $(SED) 's/^Bindings$$/Bindings {#bindings}/' >$@ doxygen: docs/Doxyfile docs/overall.md docs/intro.md docs/usage.md mdbx.h mdbx.h++ src/options.h ChangeLog.md COPYRIGHT LICENSE NOTICE $(lastword $(MAKEFILE_LIST)) @echo ' RUNNING doxygen...' $(QUIET)rm -rf docs/html && \ - cat mdbx.h | tr '\n' '\r' | sed -e 's/LIBMDBX_INLINE_API\s*(\s*\([^,]\+\),\s*\([^,]\+\),\s*(\s*\([^)]\+\)\s*)\s*)\s*{/inline \1 \2(\3) {/g' | tr '\r' '\n' >docs/mdbx.h && \ + cat mdbx.h | tr '\n' '\r' | $(SED) -e 's/LIBMDBX_INLINE_API\s*(\s*\([^,]\+\),\s*\([^,]\+\),\s*(\s*\([^)]\+\)\s*)\s*)\s*{/inline \1 \2(\3) {/g' | tr '\r' '\n' >docs/mdbx.h && \ cp mdbx.h++ src/options.h ChangeLog.md docs/ && (cd docs && doxygen Doxyfile $(HUSH)) && cp COPYRIGHT LICENSE NOTICE docs/html/ mdbx++-dylib.o: src/config.h src/mdbx.c++ mdbx.h mdbx.h++ $(lastword $(MAKEFILE_LIST)) @@ -654,7 +661,7 @@ release-assets: libmdbx-amalgamated-$(MDBX_GIT_3DOT).zpaq \ libmdbx-amalgamated-$(MDBX_GIT_3DOT).tar.gz \ libmdbx-amalgamated-$(subst .,_,$(MDBX_GIT_3DOT)).zip $(QUIET)([ \ - "$$(set -o pipefail; git describe | sed -n '/^v[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}$$/p' || echo fail-left)" \ + "$$(set -o pipefail; git describe | $(SED) -n '/^v[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}$$/p' || echo fail-left)" \ == \ "$$(git describe --tags --dirty=-dirty || echo fail-right)" ] \ || (echo 'ERROR: Is not a valid release because not in the clean state with a suitable annotated tag!!!' >&2 && false)) \ @@ -691,7 +698,7 @@ $(DIST_DIR)/@tmp-essentials.inc: src/version.c $(ALLOY_DEPS) $(lastword $(MAKEFI @echo ' ALLOYING...' $(QUIET)mkdir -p dist \ && (grep -v '#include ' src/alloy.c && echo '#define MDBX_BUILD_SOURCERY $(MDBX_BUILD_SOURCERY)' \ - && sed \ + && $(SED) \ -e 's|#include "../mdbx.h"|@INCLUDE "mdbx.h"|' \ -e '/#include "preface.h"/r src/preface.h' \ -e '/#include "osal.h"/r src/osal.h' \ @@ -703,14 +710,14 @@ $(DIST_DIR)/@tmp-essentials.inc: src/version.c $(ALLOY_DEPS) $(lastword $(MAKEFI -e '/#include "utils.h"/r src/utils.h' \ -e '/#include "pnl.h"/r src/pnl.h' \ src/essentials.h \ - | sed \ + | $(SED) \ -e '/#pragma once/d' -e '/#include "/d' \ -e '/ clang-format o/d' -e '/ \*INDENT-O/d' \ | grep -v '^/// ') >$@ $(DIST_DIR)/@tmp-internals.inc: $(DIST_DIR)/@tmp-essentials.inc src/version.c $(ALLOY_DEPS) $(lastword $(MAKEFILE_LIST)) $(QUIET)(cat $(DIST_DIR)/@tmp-essentials.inc \ - && sed \ + && $(SED) \ -e '/#include "essentials.h"/d' \ -e '/#include "atomics-ops.h"/r src/atomics-ops.h' \ -e '/#include "proto.h"/r src/proto.h' \ @@ -732,22 +739,22 @@ $(DIST_DIR)/@tmp-internals.inc: $(DIST_DIR)/@tmp-essentials.inc src/version.c $( -e '/#include "walk.h"/r src/walk.h' \ -e '/#include "windows-import.h"/r src/windows-import.h' \ src/internals.h \ - | sed \ + | $(SED) \ -e '/#pragma once/d' -e '/#include "/d' \ -e '/ clang-format o/d' -e '/ \*INDENT-O/d' \ | grep -v '^/// ') >$@ $(DIST_DIR)/mdbx.c: $(DIST_DIR)/@tmp-internals.inc $(lastword $(MAKEFILE_LIST)) @echo ' MAKE $@' - $(QUIET)(cat $(DIST_DIR)/@tmp-internals.inc $(shell git ls-files src/*.c | grep -v alloy) src/version.c | sed \ + $(QUIET)(cat $(DIST_DIR)/@tmp-internals.inc $(shell git ls-files src/*.c | grep -v alloy) src/version.c | $(SED) \ -e '/#include "debug_begin.h"/r src/debug_begin.h' \ -e '/#include "debug_end.h"/r src/debug_end.h' \ - ) | sed -e '/#include "/d;/#pragma once/d' -e 's|@INCLUDE|#include|' \ + ) | $(SED) -e '/#include "/d;/#pragma once/d' -e 's|@INCLUDE|#include|' \ -e '/ clang-format o/d;/ \*INDENT-O/d' -e '3i /* clang-format off */' | cat -s >$@ $(DIST_DIR)/mdbx.c++: $(DIST_DIR)/@tmp-essentials.inc src/mdbx.c++ $(lastword $(MAKEFILE_LIST)) @echo ' MAKE $@' - $(QUIET)cat $(DIST_DIR)/@tmp-essentials.inc src/mdbx.c++ | sed \ + $(QUIET)cat $(DIST_DIR)/@tmp-essentials.inc src/mdbx.c++ | $(SED) \ -e '/#define xMDBX_ALLOY/d' \ -e '/#include "/d;/#pragma once/d' \ -e 's|@INCLUDE|#include|;s|"mdbx.h"|"mdbx.h++"|' \ @@ -757,12 +764,12 @@ define dist-tool-rule $(DIST_DIR)/mdbx_$(1).c: src/tools/$(1).c src/tools/wingetopt.h src/tools/wingetopt.c \ $(DIST_DIR)/@tmp-internals.inc $(lastword $(MAKEFILE_LIST)) @echo ' MAKE $$@' - $(QUIET)mkdir -p dist && sed \ + $(QUIET)mkdir -p dist && $(SED) \ -e '/#include "essentials.h"/r $(DIST_DIR)/@tmp-essentials.inc' \ -e '/#include "wingetopt.h"/r src/tools/wingetopt.c' \ -e '/ clang-format o/d' -e '/ \*INDENT-O/d' \ src/tools/$(1).c \ - | sed -e '/#include "/d;/#pragma once/d;/#define xMDBX_ALLOY/d' -e 's|@INCLUDE|#include|' \ + | $(SED) -e '/#include "/d;/#pragma once/d;/#define xMDBX_ALLOY/d' -e 's|@INCLUDE|#include|' \ -e '/ clang-format o/d;/ \*INDENT-O/d' -e '9i /* clang-format off */' | cat -s >$$@ endef @@ -771,7 +778,7 @@ $(foreach file,$(TOOLS),$(eval $(call dist-tool-rule,$(file)))) define dist-extra-rule $(DIST_DIR)/$(1): $(1) src/version.c $(lastword $(MAKEFILE_LIST)) @echo ' REFINE $$@' - $(QUIET)mkdir -p $$(dir $$@) && sed -e '/^#> dist-cutoff-begin/,/^#< dist-cutoff-end/d' $$< | cat -s >$$@ + $(QUIET)mkdir -p $$(dir $$@) && $(SED) -e '/^#> dist-cutoff-begin/,/^#< dist-cutoff-end/d' $$< | cat -s >$$@ endef $(foreach file,mdbx.h mdbx.h++ $(filter-out man1/% VERSION.json .clang-format-ignore %.in ntdll.def,$(DIST_EXTRA)),$(eval $(call dist-extra-rule,$(file)))) @@ -820,7 +827,7 @@ cross-gcc: @echo "FOR INSTANCE: sudo apt install \$$(apt list 'g++-*' | grep 'g++-[a-z0-9]\+-linux-gnu/' | cut -f 1 -d / | sort -u)" $(QUIET)for CC in $(CROSS_LIST_NOQEMU) $(CROSS_LIST); do \ echo "===================== $$CC"; \ - $(MAKE) IOARENA=false CXXSTD= clean && CC=$$CC CXX=$$(echo $$CC | sed 's/-gcc/-g++/') EXE_LDFLAGS=-static $(MAKE) IOARENA=false all || exit $$?; \ + $(MAKE) IOARENA=false CXXSTD= clean && CC=$$CC CXX=$$(echo $$CC | $(SED) 's/-gcc/-g++/') EXE_LDFLAGS=-static $(MAKE) IOARENA=false all || exit $$?; \ done # Unfortunately qemu don't provide robust support for futexes. @@ -834,7 +841,7 @@ cross-qemu: $(QUIET)for CC in $(CROSS_LIST); do \ echo "===================== $$CC + qemu"; \ $(MAKE) IOARENA=false CXXSTD= clean && \ - CC=$$CC CXX=$$(echo $$CC | sed 's/-gcc/-g++/') EXE_LDFLAGS=-static MDBX_BUILD_OPTIONS="-DMDBX_SAFE4QEMU $(MDBX_BUILD_OPTIONS)" \ + CC=$$CC CXX=$$(echo $$CC | $(SED) 's/-gcc/-g++/') EXE_LDFLAGS=-static MDBX_BUILD_OPTIONS="-DMDBX_SAFE4QEMU $(MDBX_BUILD_OPTIONS)" \ $(MAKE) IOARENA=false smoke-singleprocess test-singleprocess || exit $$?; \ done @@ -901,13 +908,13 @@ bench-$(1)_$(2).txt: $(3) $(IOARENA) $(lastword $(MAKEFILE_LIST)) $(QUIET)(export LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}"; \ ldd $(IOARENA) | grep -i $(1) && \ $(IOARENA) -D $(1) -B batch -m $(BENCH_CRUD_MODE) -n $(2) \ - | tee $$@ | grep throughput | sed 's/throughput/batch×N/' && \ + | tee $$@ | grep throughput | $(SED) 's/throughput/batch×N/' && \ $(IOARENA) -D $(1) -B crud -m $(BENCH_CRUD_MODE) -n $(2) \ - | tee -a $$@ | grep throughput | sed 's/throughput/ crud/' && \ + | tee -a $$@ | grep throughput | $(SED) 's/throughput/ crud/' && \ $(IOARENA) -D $(1) -B iterate,get,iterate,get,iterate -m $(BENCH_CRUD_MODE) -r 4 -n $(2) \ - | tee -a $$@ | grep throughput | sed '0,/throughput/{s/throughput/iterate/};s/throughput/ get/' && \ + | tee -a $$@ | grep throughput | $(SED) '0,/throughput/{s/throughput/iterate/};s/throughput/ get/' && \ $(IOARENA) -D $(1) -B delete -m $(BENCH_CRUD_MODE) -n $(2) \ - | tee -a $$@ | grep throughput | sed 's/throughput/ delete/' && \ + | tee -a $$@ | grep throughput | $(SED) 's/throughput/ delete/' && \ true) || mv -f $$@ $$@.error endef From f9d7eb552547948342657e706d7f9e27306ebc12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:01:05 +0300 Subject: [PATCH 128/181] =?UTF-8?q?mdbx-doc:=20=D0=B0=D0=BA=D1=82=D1=83?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B7=D0=B4=D0=B5=D0=BB=D0=B0=20MacOS=20=D0=B2=20README=20(bac?= =?UTF-8?q?kport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 69f67b9b..d3cd1c1b 100644 --- a/README.md +++ b/README.md @@ -651,16 +651,19 @@ error when opening the database in a _WSL1_ environment. ### MacOS Current [native build tools](https://en.wikipedia.org/wiki/Xcode) for MacOS include GNU Make, CLANG and an outdated version of Bash. -Therefore, to build the library, it is enough to run `make all` in the +However, the build script uses GNU-kind of `sed` and `tar`. +So the easiest way to install all prerequirements is to use [Homebrew](https://brew.sh/), +just by `brew install bash make cmake ninja gnu-sed gnu-tar --with-default-names`. + +Next, to build the library, it is enough to run `make all` in the directory with source code, and run `make check` to execute the base tests. If something goes wrong, it is recommended to install [Homebrew](https://brew.sh/) and try again. To run the [long stochastic test scenario](test/stochastic.sh), you will need to install the current (not outdated) version of -[Bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)). To do this, I -recommend that you install [Homebrew](https://brew.sh/) and then execute -`brew install bash`. +[Bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)). +Just install it as noted above. ### Android I recommend using CMake to build _libmdbx_ for Android. From 175e4a2e1bc567c0d4d613298f979ba2befa919a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:06:56 +0300 Subject: [PATCH 129/181] =?UTF-8?q?mdbx:=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=BA=D0=B0=20=D0=B2=D0=BB=D0=B0=D0=B4=D0=B5=D0=BB=D1=8C?= =?UTF-8?q?=D1=86=D0=B0=20=D0=BF=D0=BE=D1=82=D0=BE=D0=BA=D0=B0=20=D0=B2?= =?UTF-8?q?=D0=BB=D0=B0=D0=B4=D0=B5=D1=8E=D1=89=D0=B5=D0=B3=D0=BE=20=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B5=D0=B9=20?= =?UTF-8?q?=D1=82=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=BF=D1=80=D0=B8=20`MD?= =?UTF-8?q?BX=5FTXN=5FCHECKOWNER=3DON`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-txn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api-txn.c b/src/api-txn.c index 2fe01a4e..786e1e42 100644 --- a/src/api-txn.c +++ b/src/api-txn.c @@ -423,7 +423,7 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) { } #if MDBX_TXN_CHECKOWNER - if (!txn->parent && (txn->flags & MDBX_NOSTICKYTHREADS) && unlikely(txn->owner != osal_thread_self())) { + if ((txn->flags & MDBX_NOSTICKYTHREADS) && txn == env->basal_txn && unlikely(txn->owner != osal_thread_self())) { txn->flags |= MDBX_TXN_ERROR; rc = MDBX_THREAD_MISMATCH; return LOG_IFERR(rc); From b6dcdcf2dc908852a819f9abc36c456d92057412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:10:11 +0300 Subject: [PATCH 130/181] =?UTF-8?q?mdbx:=20=D0=B7=D0=B0=D0=BF=D1=80=D0=B5?= =?UTF-8?q?=D1=89=D0=B5=D0=BD=D0=B8=D0=B5=20unbind/close=20=D0=BA=D1=83?= =?UTF-8?q?=D1=80=D1=81=D0=BE=D1=80=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=B2=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=BD=D1=8B=D1=85=20=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B9=20(backp?= =?UTF-8?q?ort).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 20 ++++++++++-- src/api-cursor.c | 79 +++++++++++++++++++++--------------------------- 2 files changed, 53 insertions(+), 46 deletions(-) diff --git a/mdbx.h b/mdbx.h index 728e6eb0..559c664b 100644 --- a/mdbx.h +++ b/mdbx.h @@ -5116,6 +5116,10 @@ MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *mdbx_cursor_get_userctx(const MDBX_ * the same table handle as it was created with. This may be done whether the * previous transaction is live or dead. * + * If the transaction is nested, then the cursor should not be used in its parent transaction. + * Otherwise it is no way to restore state if this nested transaction will be aborted, + * nor impossible to define the expected behavior. + * * \note In contrast to LMDB, the MDBX required that any opened cursors can be * reused and must be freed explicitly, regardless ones was opened in a * read-only or write transaction. The REASON for this is eliminates ambiguity @@ -5140,6 +5144,10 @@ LIBMDBX_API int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *cursor, MDBX_dbi db * the original DBI-handle internally. Thus it could be renewed with any running * transaction or closed. * + * If the transaction is nested, then the cursor should not be used in its parent transaction. + * Otherwise it is no way to restore state if this nested transaction will be aborted, + * nor impossible to define the expected behavior. + * * \see mdbx_cursor_renew() * \see mdbx_cursor_bind() * \see mdbx_cursor_close() @@ -5224,6 +5232,10 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); * Unbinds either closes all cursors associated (opened or renewed) with * a given transaction in a bulk with minimal overhead. * + * A transaction should not be nested, since in this case no way to restore + * state if this nested transaction will be aborted, nor impossible to define + * the expected behavior. + * * \see mdbx_cursor_unbind() * \see mdbx_cursor_close() * @@ -5237,7 +5249,7 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. - * \retval MDBX_BAD_TXN Given transaction is invalid or has + * \retval MDBX_BAD_TXN Given transaction is invalid, nested or has * a child/nested transaction transaction. */ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count); @@ -5247,6 +5259,10 @@ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind * Unbinds either closes all cursors associated (opened or renewed) with * a given transaction in a bulk with minimal overhead. * + * A transaction should not be nested, since in this case no way to restore + * state if this nested transaction will be aborted, nor impossible to define + * the expected behavior. + * * \see mdbx_cursor_unbind() * \see mdbx_cursor_close() * @@ -5258,7 +5274,7 @@ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. - * \retval MDBX_BAD_TXN Given transaction is invalid or has + * \retval MDBX_BAD_TXN Given transaction is invalid, nested or has * a child/nested transaction transaction. */ LIBMDBX_INLINE_API(int, mdbx_txn_release_all_cursors, (const MDBX_txn *txn, bool unbind)) { return mdbx_txn_release_all_cursors_ex(txn, unbind, NULL); diff --git a/src/api-cursor.c b/src/api-cursor.c index 9176b42c..ec87e4bd 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -44,8 +44,10 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { if (unlikely(!mc)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(mc->signature != cur_signature_ready4dispose && mc->signature != cur_signature_live)) - return LOG_IFERR(MDBX_EBADSIGN); + if (unlikely(mc->signature != cur_signature_ready4dispose && mc->signature != cur_signature_live)) { + int rc = (mc->signature == cur_signature_wait4eot) ? MDBX_EINVAL : MDBX_EBADSIGN; + return LOG_IFERR(rc); + } int rc = check_txn(txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) @@ -58,24 +60,12 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { if (unlikely(dbi == FREE_DBI && !(txn->flags & MDBX_TXN_RDONLY))) return LOG_IFERR(MDBX_EACCESS); - if (unlikely(mc->backup)) /* Cursor from parent transaction */ { - cASSERT(mc, mc->signature == cur_signature_live); - if (unlikely(cursor_dbi(mc) != dbi || - /* paranoia */ mc->signature != cur_signature_live || mc->txn != txn)) - return LOG_IFERR(MDBX_EINVAL); - - cASSERT(mc, mc->tree == &txn->dbs[dbi]); - cASSERT(mc, mc->clc == &txn->env->kvs[dbi].clc); - cASSERT(mc, cursor_dbi(mc) == dbi); - return likely(cursor_dbi(mc) == dbi && - /* paranoia */ mc->signature == cur_signature_live && mc->txn == txn) - ? MDBX_SUCCESS - : LOG_IFERR(MDBX_EINVAL) /* Disallow change DBI in nested - transactions */ - ; - } + if (unlikely(mc->backup)) /* Cursor from parent transaction */ + LOG_IFERR(MDBX_EINVAL); if (mc->signature == cur_signature_live) { + if (mc->txn == txn && cursor_dbi(mc) == dbi) + return MDBX_SUCCESS; rc = mdbx_cursor_unbind(mc); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -99,25 +89,22 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) { return (mc->signature == cur_signature_ready4dispose) ? MDBX_SUCCESS : LOG_IFERR(MDBX_EBADSIGN); if (unlikely(mc->backup)) /* Cursor from parent transaction */ + /* TODO: реализовать при переходе на двусвязный список курсоров */ return LOG_IFERR(MDBX_EINVAL); - eASSERT(nullptr, mc->txn && mc->txn->signature == txn_signature); - cASSERT(mc, mc->signature == cur_signature_live); - cASSERT(mc, !mc->backup); if (unlikely(!mc->txn || mc->txn->signature != txn_signature)) { ERROR("Wrong cursor's transaction %p 0x%x", __Wpedantic_format_voidptr(mc->txn), mc->txn ? mc->txn->signature : 0); return LOG_IFERR(MDBX_PROBLEM); } + if (mc->next != mc) { - const size_t dbi = (kvx_t *)mc->clc - mc->txn->env->kvs; - cASSERT(mc, cursor_dbi(mc) == dbi); + const size_t dbi = cursor_dbi(mc); cASSERT(mc, dbi < mc->txn->n_dbi); + cASSERT(mc, &mc->txn->env->kvs[dbi].clc == mc->clc); if (dbi < mc->txn->n_dbi) { MDBX_cursor **prev = &mc->txn->cursors[dbi]; - while (*prev) { + while (/* *prev && */ *prev != mc) { ENSURE(mc->txn->env, (*prev)->signature == cur_signature_live || (*prev)->signature == cur_signature_wait4eot); - if (*prev == mc) - break; prev = &(*prev)->next; } cASSERT(mc, *prev == mc); @@ -218,30 +205,34 @@ again: int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count) { int rc = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + if (unlikely(txn->parent)) { + rc = MDBX_BAD_TXN; + ERROR("%s, err %d", "must not unbind or close cursors for a nested txn", rc); + return rc; + } + size_t n = 0; - if (likely(rc == MDBX_SUCCESS)) { - TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) { - while (txn->cursors[i]) { - ++n; - MDBX_cursor *mc = txn->cursors[i]; - ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup); - txn->cursors[i] = mc->next; - mc->next = mc; - if (unbind) { - be_poor(mc); - mc->signature = cur_signature_ready4dispose; - } else { - mc->signature = 0; - osal_free(mc); - } + TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) { + while (txn->cursors[i]) { + ++n; + MDBX_cursor *mc = txn->cursors[i]; + ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup); + txn->cursors[i] = mc->next; + mc->next = mc; + if (unbind) { + be_poor(mc); + mc->signature = cur_signature_ready4dispose; + } else { + mc->signature = 0; + osal_free(mc); } } - } else { - LOG_IFERR(rc); } if (count) *count = n; - return rc; + return MDBX_SUCCESS; } int mdbx_cursor_compare(const MDBX_cursor *l, const MDBX_cursor *r, bool ignore_multival) { From 2b6a7687508e10cdf345e51df7f70661067a0d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:12:15 +0300 Subject: [PATCH 131/181] =?UTF-8?q?mdbx:=20=D0=BA=D0=BE=D1=81=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D0=B9=20=D1=80=D0=B5?= =?UTF-8?q?=D1=84=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20`curso?= =?UTF-8?q?r=5Fshadow()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cursor.c | 40 ++++++++++++++++++---------------------- src/cursor.h | 2 +- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/cursor.c b/src/cursor.c index f24677f2..4667652e 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -184,14 +184,13 @@ __hot int cursor_touch(MDBX_cursor *const mc, const MDBX_val *key, const MDBX_va /*----------------------------------------------------------------------------*/ -int cursor_shadow(MDBX_cursor *parent_cursor, MDBX_txn *nested_txn, const size_t dbi) { - - tASSERT(nested_txn, dbi > FREE_DBI && dbi < nested_txn->n_dbi); - const size_t size = parent_cursor->subcur ? sizeof(MDBX_cursor) + sizeof(subcur_t) : sizeof(MDBX_cursor); - for (MDBX_cursor *bk; parent_cursor; parent_cursor = bk->next) { - cASSERT(parent_cursor, parent_cursor != parent_cursor->next); - bk = parent_cursor; - if (parent_cursor->signature != cur_signature_live) +int cursor_shadow(MDBX_cursor *mc, MDBX_txn *nested, const size_t dbi) { + tASSERT(nested, dbi > FREE_DBI && dbi < nested->n_dbi); + const size_t size = mc->subcur ? sizeof(MDBX_cursor) + sizeof(subcur_t) : sizeof(MDBX_cursor); + for (MDBX_cursor *bk; mc; mc = bk->next) { + cASSERT(mc, mc != mc->next); + bk = mc; + if (mc->signature != cur_signature_live) continue; bk = osal_malloc(size); if (unlikely(!bk)) @@ -200,22 +199,19 @@ int cursor_shadow(MDBX_cursor *parent_cursor, MDBX_txn *nested_txn, const size_t memset(bk, 0xCD, size); VALGRIND_MAKE_MEM_UNDEFINED(bk, size); #endif /* MDBX_DEBUG */ - *bk = *parent_cursor; - parent_cursor->backup = bk; - /* Kill pointers into src to reduce abuse: The - * user may not use mc until dst ends. But we need a valid - * txn pointer here for cursor fixups to keep working. */ - parent_cursor->txn = nested_txn; - parent_cursor->tree = &nested_txn->dbs[dbi]; - parent_cursor->dbi_state = &nested_txn->dbi_state[dbi]; - subcur_t *mx = parent_cursor->subcur; - if (mx != nullptr) { + *bk = *mc; + mc->backup = bk; + mc->txn = nested; + mc->tree = &nested->dbs[dbi]; + mc->dbi_state = &nested->dbi_state[dbi]; + subcur_t *mx = mc->subcur; + if (mx) { *(subcur_t *)(bk + 1) = *mx; - mx->cursor.txn = nested_txn; - mx->cursor.dbi_state = parent_cursor->dbi_state; + mx->cursor.txn = nested; + mx->cursor.dbi_state = &nested->dbi_state[dbi]; } - parent_cursor->next = nested_txn->cursors[dbi]; - nested_txn->cursors[dbi] = parent_cursor; + mc->next = nested->cursors[dbi]; + nested->cursors[dbi] = mc; } return MDBX_SUCCESS; } diff --git a/src/cursor.h b/src/cursor.h index c2de019b..6d984084 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -293,7 +293,7 @@ MDBX_NOTHROW_PURE_FUNCTION static inline bool check_leaf_type(const MDBX_cursor } MDBX_INTERNAL void cursor_eot(MDBX_cursor *mc, const bool merge); -MDBX_INTERNAL int cursor_shadow(MDBX_cursor *parent_cursor, MDBX_txn *nested_txn, const size_t dbi); +MDBX_INTERNAL int cursor_shadow(MDBX_cursor *mc, MDBX_txn *nested, const size_t dbi); MDBX_INTERNAL MDBX_cursor *cursor_cpstk(const MDBX_cursor *csrc, MDBX_cursor *cdst); From 2476fba287793c49cbdd6963cb88b9cf9d6fc5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:12:59 +0300 Subject: [PATCH 132/181] =?UTF-8?q?mdbx:=20=D1=80=D0=B5=D1=84=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20`cursor=5Feot()`=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BF=D1=80=D0=BE=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20`txn=5Fdone=5Fcursors()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cursor.c | 21 ++++++++++++--------- src/cursor.h | 2 +- src/dbi.h | 2 +- src/txn.c | 8 +++----- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/cursor.c b/src/cursor.c index 4667652e..bf12cd66 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -216,17 +216,21 @@ int cursor_shadow(MDBX_cursor *mc, MDBX_txn *nested, const size_t dbi) { return MDBX_SUCCESS; } -void cursor_eot(MDBX_cursor *mc, const bool merge) { +MDBX_cursor *cursor_eot(MDBX_cursor *mc, MDBX_txn *txn, const bool merge) { + MDBX_cursor *const next = mc->next; + mc->next = mc; const unsigned stage = mc->signature; MDBX_cursor *const bk = mc->backup; - ENSURE(mc->txn->env, stage == cur_signature_live || (stage == cur_signature_wait4eot && bk)); + ENSURE(txn->env, stage == cur_signature_live || (stage == cur_signature_wait4eot && bk)); + tASSERT(txn, mc->txn == txn); if (bk) { subcur_t *mx = mc->subcur; - cASSERT(mc, mc->txn->parent != nullptr); + tASSERT(txn, mc->txn->parent != nullptr); + tASSERT(txn, bk->txn == txn->parent); /* Zap: Using uninitialized memory '*mc->backup'. */ MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(6001); ENSURE(mc->txn->env, bk->signature == cur_signature_live); - cASSERT(mc, mx == bk->subcur); + tASSERT(txn, mx == bk->subcur); if (merge) { /* Update pointers to parent txn */ mc->next = bk->next; @@ -235,24 +239,23 @@ void cursor_eot(MDBX_cursor *mc, const bool merge) { mc->tree = bk->tree; mc->dbi_state = bk->dbi_state; if (mx) { - mx->cursor.txn = mc->txn; - mx->cursor.dbi_state = mc->dbi_state; + mx->cursor.txn = bk->txn; + mx->cursor.dbi_state = bk->dbi_state; } } else { /* Restore from backup, i.e. rollback/abort nested txn */ *mc = *bk; + mc->signature = stage /* Promote (cur_signature_wait4eot) state to parent txn */; if (mx) *mx = *(subcur_t *)(bk + 1); } - if (stage == cur_signature_wait4eot /* Cursor was closed by user */) - mc->signature = stage /* Promote closed state to parent txn */; bk->signature = 0; osal_free(bk); } else { ENSURE(mc->txn->env, stage == cur_signature_live); mc->signature = cur_signature_ready4dispose /* Cursor may be reused */; - mc->next = mc; } + return next; } /*----------------------------------------------------------------------------*/ diff --git a/src/cursor.h b/src/cursor.h index 6d984084..cfaca52e 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -292,7 +292,7 @@ MDBX_NOTHROW_PURE_FUNCTION static inline bool check_leaf_type(const MDBX_cursor return (((page_type(mp) ^ mc->checking) & (z_branch | z_leaf | z_largepage | z_dupfix)) == 0); } -MDBX_INTERNAL void cursor_eot(MDBX_cursor *mc, const bool merge); +MDBX_INTERNAL MDBX_cursor *cursor_eot(MDBX_cursor *mc, MDBX_txn *txn, const bool merge); MDBX_INTERNAL int cursor_shadow(MDBX_cursor *mc, MDBX_txn *nested, const size_t dbi); MDBX_INTERNAL MDBX_cursor *cursor_cpstk(const MDBX_cursor *csrc, MDBX_cursor *cdst); diff --git a/src/dbi.h b/src/dbi.h index e9b16efe..2dffd5f7 100644 --- a/src/dbi.h +++ b/src/dbi.h @@ -101,7 +101,7 @@ static inline bool dbi_changed(const MDBX_txn *txn, const size_t dbi) { const MDBX_env *const env = txn->env; eASSERT(env, dbi_state(txn, dbi) & DBI_LINDO); const uint32_t snap_seq = atomic_load32(&env->dbi_seqs[dbi], mo_AcquireRelease); - return snap_seq != txn->dbi_seqs[dbi]; + return unlikely(snap_seq != txn->dbi_seqs[dbi]); } static inline int dbi_check(const MDBX_txn *txn, const size_t dbi) { diff --git a/src/txn.c b/src/txn.c index eb198965..a83cd9c8 100644 --- a/src/txn.c +++ b/src/txn.c @@ -13,11 +13,9 @@ void txn_done_cursors(MDBX_txn *txn, const bool merge) { MDBX_cursor *mc = txn->cursors[i]; if (mc) { txn->cursors[i] = nullptr; - do { - MDBX_cursor *const next = mc->next; - cursor_eot(mc, merge); - mc = next; - } while (mc); + do + mc = cursor_eot(mc, txn, merge); + while (mc); } } } From 33ceba0a5afb679bce2b671a0a86c2d61b97d353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:13:44 +0300 Subject: [PATCH 133/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`cursor=5Freset()`=20=D0=B8=20?= =?UTF-8?q?`cursor=5Fdrown()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cursor.c | 26 +++++++++++++------------- src/cursor.c | 3 ++- src/cursor.h | 16 ++++++++++++++++ 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/api-cursor.c b/src/api-cursor.c index ec87e4bd..cfe935f1 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -12,8 +12,7 @@ MDBX_cursor *mdbx_cursor_create(void *context) { couple->outer.signature = cur_signature_ready4dispose; couple->outer.next = &couple->outer; couple->userctx = context; - couple->outer.top_and_flags = z_poor_mark; - couple->inner.cursor.top_and_flags = z_poor_mark | z_inner; + cursor_reset(couple); VALGRIND_MAKE_MEM_DEFINED(&couple->outer.backup, sizeof(couple->outer.backup)); VALGRIND_MAKE_MEM_DEFINED(&couple->outer.tree, sizeof(couple->outer.tree)); VALGRIND_MAKE_MEM_DEFINED(&couple->outer.clc, sizeof(couple->outer.clc)); @@ -31,13 +30,15 @@ int mdbx_cursor_reset(MDBX_cursor *mc) { if (unlikely(!mc)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(mc->signature != cur_signature_ready4dispose && mc->signature != cur_signature_live)) - return LOG_IFERR(MDBX_EBADSIGN); + if (likely(mc->signature == cur_signature_live)) { + cursor_reset((cursor_couple_t *)mc); + return MDBX_SUCCESS; + } - cursor_couple_t *couple = (cursor_couple_t *)mc; - couple->outer.top_and_flags = z_poor_mark; - couple->inner.cursor.top_and_flags = z_poor_mark | z_inner; - return MDBX_SUCCESS; + if (likely(mc->signature == cur_signature_ready4dispose)) + return MDBX_SUCCESS; + + return LOG_IFERR(MDBX_EBADSIGN); } int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { @@ -112,7 +113,7 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) { } mc->next = mc; } - be_poor(mc); + cursor_drown((cursor_couple_t *)mc); mc->signature = cur_signature_ready4dispose; return MDBX_SUCCESS; } @@ -221,10 +222,9 @@ int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *co ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup); txn->cursors[i] = mc->next; mc->next = mc; - if (unbind) { - be_poor(mc); - mc->signature = cur_signature_ready4dispose; - } else { + mc->signature = cur_signature_ready4dispose; + cursor_drown((cursor_couple_t *)mc); + if (!unbind) { mc->signature = 0; osal_free(mc); } diff --git a/src/cursor.c b/src/cursor.c index bf12cd66..73da6a8b 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -218,7 +218,6 @@ int cursor_shadow(MDBX_cursor *mc, MDBX_txn *nested, const size_t dbi) { MDBX_cursor *cursor_eot(MDBX_cursor *mc, MDBX_txn *txn, const bool merge) { MDBX_cursor *const next = mc->next; - mc->next = mc; const unsigned stage = mc->signature; MDBX_cursor *const bk = mc->backup; ENSURE(txn->env, stage == cur_signature_live || (stage == cur_signature_wait4eot && bk)); @@ -253,6 +252,8 @@ MDBX_cursor *cursor_eot(MDBX_cursor *mc, MDBX_txn *txn, const bool merge) { osal_free(bk); } else { ENSURE(mc->txn->env, stage == cur_signature_live); + cursor_drown((cursor_couple_t *)mc); + mc->next = mc; mc->signature = cur_signature_ready4dispose /* Cursor may be reused */; } return next; diff --git a/src/cursor.h b/src/cursor.h index cfaca52e..d06bad3a 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -355,3 +355,19 @@ MDBX_MAYBE_UNUSED static inline void cursor_inner_refresh(const MDBX_cursor *mc, } MDBX_MAYBE_UNUSED MDBX_INTERNAL bool cursor_is_tracked(const MDBX_cursor *mc); + +static inline void cursor_reset(cursor_couple_t *couple) { + couple->outer.top_and_flags = z_fresh_mark; + couple->inner.cursor.top_and_flags = z_fresh_mark | z_inner; +} + +static inline void cursor_drown(cursor_couple_t *couple) { + couple->outer.top_and_flags = z_poor_mark; + couple->inner.cursor.top_and_flags = z_poor_mark | z_inner; + couple->outer.txn = nullptr; + couple->inner.cursor.txn = nullptr; + couple->outer.tree = nullptr; + /* сохраняем clc-указатель, так он используется для вычисления dbi в mdbx_cursor_renew(). */ + couple->outer.dbi_state = nullptr; + couple->inner.cursor.dbi_state = nullptr; +} From 753b2270fdfc8df36a23c82e2e2707c7357de955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:14:34 +0300 Subject: [PATCH 134/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`mdbx=5Fcursor=5Fclose2()`=20?= =?UTF-8?q?=D0=B2=20API=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 30 +++++++++++++++- mdbx.h++ | 5 ++- src/api-cursor.c | 91 ++++++++++++++++++++++++++++++------------------ src/cursor.c | 4 +-- src/mdbx.c++ | 9 ----- 5 files changed, 93 insertions(+), 46 deletions(-) diff --git a/mdbx.h b/mdbx.h index 559c664b..e8e5748b 100644 --- a/mdbx.h +++ b/mdbx.h @@ -5210,12 +5210,17 @@ LIBMDBX_API int mdbx_cursor_reset(MDBX_cursor *cursor); * \retval MDBX_EINVAL An invalid parameter was specified. */ LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **cursor); -/** \brief Close a cursor handle. +/** \brief Closes a cursor handle without returning error code. * \ingroup c_cursors * * The cursor handle will be freed and must not be used again after this call, * but its transaction may still be live. * + * This function returns `void` but panic in case of error. Use \ref mdbx_cursor_close2() + * if you need to receive an error code instead of an app crash. + * + * \see mdbx_cursor_close2 + * * \note In contrast to LMDB, the MDBX required that any opened cursors can be * reused and must be freed explicitly, regardless ones was opened in a * read-only or write transaction. The REASON for this is eliminates ambiguity @@ -5226,6 +5231,29 @@ LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **curs * or \ref mdbx_cursor_create(). */ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); +/** \brief Closes a cursor handle with returning error code. + * \ingroup c_cursors + * + * The cursor handle will be freed and must not be used again after this call, + * but its transaction may still be live. + * + * \see mdbx_cursor_close + * + * \note In contrast to LMDB, the MDBX required that any opened cursors can be + * reused and must be freed explicitly, regardless ones was opened in a + * read-only or write transaction. The REASON for this is eliminates ambiguity + * which helps to avoid errors such as: use-after-free, double-free, i.e. + * memory corruption and segfaults. + * + * \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open() + * or \ref mdbx_cursor_create(). + * \returns A non-zero error value on failure and 0 on success, + * some possible errors are: + * \retval MDBX_THREAD_MISMATCH Given transaction is not owned + * by current thread. + * \retval MDBX_EINVAL An invalid parameter was specified. */ +LIBMDBX_API int mdbx_cursor_close2(MDBX_cursor *cursor); + /** \brief Unbind or closes all cursors of a given transaction. * \ingroup c_cursors * diff --git a/mdbx.h++ b/mdbx.h++ index e993f17f..3b6e6239 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -4545,7 +4545,10 @@ public: } /// \brief Explicitly closes the cursor. - void close(); + inline void close() { + error::success_or_throw(::mdbx_cursor_close2(handle_)); + handle_ = nullptr; + } cursor_managed(cursor_managed &&) = default; cursor_managed &operator=(cursor_managed &&other) noexcept { diff --git a/src/api-cursor.c b/src/api-cursor.c index cfe935f1..d86bc34e 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -93,6 +93,10 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) { /* TODO: реализовать при переходе на двусвязный список курсоров */ return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn(mc->txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + if (unlikely(!mc->txn || mc->txn->signature != txn_signature)) { ERROR("Wrong cursor's transaction %p 0x%x", __Wpedantic_format_voidptr(mc->txn), mc->txn ? mc->txn->signature : 0); return LOG_IFERR(MDBX_PROBLEM); @@ -137,42 +141,63 @@ int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) { return MDBX_SUCCESS; } -void mdbx_cursor_close(MDBX_cursor *mc) { - if (likely(mc)) { - ENSURE(nullptr, mc->signature == cur_signature_live || mc->signature == cur_signature_ready4dispose); - MDBX_txn *const txn = mc->txn; - if (!mc->backup) { - mc->txn = nullptr; - /* Unlink from txn, if tracked. */ - if (mc->next != mc) { - ENSURE(txn->env, check_txn(txn, 0) == MDBX_SUCCESS); - const size_t dbi = (kvx_t *)mc->clc - txn->env->kvs; - tASSERT(txn, dbi < txn->n_dbi); - if (dbi < txn->n_dbi) { - MDBX_cursor **prev = &txn->cursors[dbi]; - while (*prev) { - ENSURE(txn->env, (*prev)->signature == cur_signature_live || (*prev)->signature == cur_signature_wait4eot); - if (*prev == mc) - break; - prev = &(*prev)->next; - } - tASSERT(txn, *prev == mc); - *prev = mc->next; - } - mc->next = mc; - } - mc->signature = 0; - osal_free(mc); - } else { - /* Cursor closed before nested txn ends */ - tASSERT(txn, mc->signature == cur_signature_live); - ENSURE(txn->env, check_txn_rw(txn, 0) == MDBX_SUCCESS); - be_poor(mc); - mc->signature = cur_signature_wait4eot; - } +void mdbx_cursor_close(MDBX_cursor *cursor) { + if (likely(cursor)) { + int err = mdbx_cursor_close2(cursor); + if (unlikely(err != MDBX_SUCCESS)) + mdbx_panic("%s:%d error %d (%s) while closing cursor", __func__, __LINE__, err, mdbx_liberr2str(err)); } } +int mdbx_cursor_close2(MDBX_cursor *mc) { + if (unlikely(!mc)) + return LOG_IFERR(MDBX_EINVAL); + + if (mc->signature == cur_signature_ready4dispose) { + if (unlikely(mc->txn || mc->backup)) + return LOG_IFERR(MDBX_PANIC); + cursor_drown((cursor_couple_t *)mc); + mc->signature = 0; + osal_free(mc); + return MDBX_SUCCESS; + } + + if (unlikely(mc->signature != cur_signature_live)) + return LOG_IFERR(MDBX_EBADSIGN); + + MDBX_txn *const txn = mc->txn; + int rc = check_txn(txn, MDBX_TXN_FINISHED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + + if (mc->backup) { + /* Cursor closed before nested txn ends */ + cursor_reset((cursor_couple_t *)mc); + mc->signature = cur_signature_wait4eot; + return MDBX_SUCCESS; + } + + if (mc->next != mc) { + const size_t dbi = cursor_dbi(mc); + cASSERT(mc, dbi < mc->txn->n_dbi); + cASSERT(mc, &mc->txn->env->kvs[dbi].clc == mc->clc); + if (likely(dbi < txn->n_dbi)) { + MDBX_cursor **prev = &txn->cursors[dbi]; + while (/* *prev && */ *prev != mc) { + ENSURE(txn->env, (*prev)->signature == cur_signature_live || (*prev)->signature == cur_signature_wait4eot); + prev = &(*prev)->next; + } + tASSERT(txn, *prev == mc); + *prev = mc->next; + } + mc->next = mc; + } + cursor_drown((cursor_couple_t *)mc); + mc->signature = 0; + osal_free(mc); + return MDBX_SUCCESS; +} + int mdbx_cursor_copy(const MDBX_cursor *src, MDBX_cursor *dest) { if (unlikely(!src)) return LOG_IFERR(MDBX_EINVAL); diff --git a/src/cursor.c b/src/cursor.c index 73da6a8b..bb6f4e61 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -252,9 +252,9 @@ MDBX_cursor *cursor_eot(MDBX_cursor *mc, MDBX_txn *txn, const bool merge) { osal_free(bk); } else { ENSURE(mc->txn->env, stage == cur_signature_live); - cursor_drown((cursor_couple_t *)mc); - mc->next = mc; mc->signature = cur_signature_ready4dispose /* Cursor may be reused */; + mc->next = mc; + cursor_drown((cursor_couple_t *)mc); } return next; } diff --git a/src/mdbx.c++ b/src/mdbx.c++ index d891b654..63f56190 100644 --- a/src/mdbx.c++ +++ b/src/mdbx.c++ @@ -1590,15 +1590,6 @@ __cold bool txn::rename_map(const ::std::string &old_name, const ::std::string & //------------------------------------------------------------------------------ -void cursor_managed::close() { - if (MDBX_UNLIKELY(!handle_)) - MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL); - ::mdbx_cursor_close(handle_); - handle_ = nullptr; -} - -//------------------------------------------------------------------------------ - __cold ::std::ostream &operator<<(::std::ostream &out, const slice &it) { out << "{"; if (!it.is_valid()) From 2fbdaccf6038abb31ace63b8d5ebe0344e981a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:15:53 +0300 Subject: [PATCH 135/181] =?UTF-8?q?mdbx-tests:=20=D0=BF=D0=BE=D0=B4=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B6=D0=BA=D0=B0=20=D0=B7=D0=BD=D0=B0=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B9=20`on`/`off`=20=D0=B4=D0=BB=D1=8F=20=D0=BE?= =?UTF-8?q?=D0=BF=D1=86=D0=B8=D0=B9=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4?= =?UTF-8?q?=D0=BD=D0=BE=D0=B9=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B8=20(ba?= =?UTF-8?q?ckport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/config.c++ | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/config.c++ b/test/config.c++ index 4188e3c0..f9e75dac 100644 --- a/test/config.c++ +++ b/test/config.c++ @@ -313,12 +313,12 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option, b return true; } - if (strcasecmp(value_cstr, "yes") == 0 || strcasecmp(value_cstr, "1") == 0) { + if (strcasecmp(value_cstr, "yes") == 0 || strcasecmp(value_cstr, "1") == 0 || strcasecmp(value_cstr, "on") == 0) { value = true; return true; } - if (strcasecmp(value_cstr, "no") == 0 || strcasecmp(value_cstr, "0") == 0) { + if (strcasecmp(value_cstr, "no") == 0 || strcasecmp(value_cstr, "0") == 0 || strcasecmp(value_cstr, "off") == 0) { value = false; return true; } From 484b488f92a1e61be9398bf5c284f2c523518662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:16:48 +0300 Subject: [PATCH 136/181] =?UTF-8?q?mdbx-tests:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=BE=D0=B4=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B6=D0=BA=D0=B8=20=D0=BE=D0=BF=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20`MDBX=5FVALIDATION`=20=D0=B8=20=D0=B8=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B2?= =?UTF-8?q?=20=D1=81=D1=82=D0=BE=D1=85=D0=B0=D1=81=D1=82=D0=B8=D1=87=D0=B5?= =?UTF-8?q?=D1=81=D0=BA=D0=BE=D0=BC=20=D1=82=D0=B5=D1=81=D1=82=D0=B5=20(ba?= =?UTF-8?q?ckport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/config.c++ | 1 + test/stochastic.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/config.c++ b/test/config.c++ index f9e75dac..4bc20b32 100644 --- a/test/config.c++ +++ b/test/config.c++ @@ -342,6 +342,7 @@ const struct option_verb mode_bits[] = {{"rdonly", unsigned(MDBX_RDONLY)}, {"perturb", unsigned(MDBX_PAGEPERTURB)}, {"accede", unsigned(MDBX_ACCEDE)}, {"exclusive", unsigned(MDBX_EXCLUSIVE)}, + {"validation", unsigned(MDBX_VALIDATION)}, {nullptr, 0}}; const struct option_verb table_bits[] = {{"key.reverse", unsigned(MDBX_REVERSEKEY)}, diff --git a/test/stochastic.sh b/test/stochastic.sh index 18ea6737..d7abcdf5 100755 --- a/test/stochastic.sh +++ b/test/stochastic.sh @@ -440,7 +440,7 @@ else fi if [ "$EXTRA" != "no" ]; then - options=(perturb nomeminit nordahead writemap lifo nostickythreads) + options=(perturb nomeminit nordahead writemap lifo nostickythreads validation) else options=(writemap lifo nostickythreads) fi From 0fff8d07042c75930749a2708f21c60245783ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:17:11 +0300 Subject: [PATCH 137/181] =?UTF-8?q?mdbx-doc:=20doxygen-=D0=BE=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=BB=D1=8F=20doubtless?= =?UTF-8?q?-positioning=20=D0=BA=D0=BE=D0=BD=D1=81=D1=82=D0=B0=D0=BD=D1=82?= =?UTF-8?q?=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/mdbx.h b/mdbx.h index e8e5748b..fb7d1400 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1791,26 +1791,28 @@ typedef enum MDBX_cursor_op { * \ref MDBX_NOTFOUND otherwise. */ MDBX_SET_UPPERBOUND, - /* Doubtless cursor positioning at a specified key. */ + /** Doubtless cursor positioning at a specified key. */ 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_KEY_LESSER_OR_EQUAL /** \copydoc MDBX_TO_KEY_LESSER_THAN */, + MDBX_TO_KEY_EQUAL /** \copydoc MDBX_TO_KEY_LESSER_THAN */, + MDBX_TO_KEY_GREATER_OR_EQUAL /** \copydoc MDBX_TO_KEY_LESSER_THAN */, + MDBX_TO_KEY_GREATER_THAN /** \copydoc MDBX_TO_KEY_LESSER_THAN */, - /* Doubtless cursor positioning at a specified key-value pair + /** Doubtless cursor positioning at a specified key-value pair * for dupsort/multi-value hives. */ 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_EXACT_KEY_VALUE_LESSER_OR_EQUAL /** \copydoc MDBX_TO_EXACT_KEY_VALUE_LESSER_THAN */, + MDBX_TO_EXACT_KEY_VALUE_EQUAL /** \copydoc MDBX_TO_EXACT_KEY_VALUE_LESSER_THAN */, + MDBX_TO_EXACT_KEY_VALUE_GREATER_OR_EQUAL /** \copydoc MDBX_TO_EXACT_KEY_VALUE_LESSER_THAN */, + MDBX_TO_EXACT_KEY_VALUE_GREATER_THAN /** \copydoc MDBX_TO_EXACT_KEY_VALUE_LESSER_THAN */, + /** Doubtless cursor positioning at a specified key-value pair + * for dupsort/multi-value hives. */ 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_TO_PAIR_LESSER_OR_EQUAL /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, + MDBX_TO_PAIR_EQUAL /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, + MDBX_TO_PAIR_GREATER_OR_EQUAL /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, + MDBX_TO_PAIR_GREATER_THAN /** \copydoc MDBX_TO_PAIR_LESSER_THAN */ } MDBX_cursor_op; /** \brief Errors and return codes From 91570a084f1f633138208c8c7928544fdcd058d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:17:47 +0300 Subject: [PATCH 138/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`MDBX=5FSEEK=5FAND=5FGET=5FMUL?= =?UTF-8?q?TIPLE`=20=D0=B2=20API=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B9=20=D0=BA=D1=83=D1=80=D1=81=D0=BE=D1=80=D0=B0=20(ba?= =?UTF-8?q?ckport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 16 +++++++++++----- src/cursor.c | 38 +++++++++++++------------------------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/mdbx.h b/mdbx.h index fb7d1400..cce6c6a5 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1718,7 +1718,7 @@ typedef enum MDBX_cursor_op { /** \ref MDBX_DUPFIXED -only: Return up to a page of duplicate data items * from current cursor position. Move cursor to prepare - * for \ref MDBX_NEXT_MULTIPLE. */ + * for \ref MDBX_NEXT_MULTIPLE. \see MDBX_SEEK_AND_GET_MULTIPLE */ MDBX_GET_MULTIPLE, /** Position at last key/data item */ @@ -1734,8 +1734,8 @@ typedef enum MDBX_cursor_op { MDBX_NEXT_DUP, /** \ref MDBX_DUPFIXED -only: Return up to a page of duplicate data items - * from next cursor position. Move cursor to prepare - * for `MDBX_NEXT_MULTIPLE`. */ + * from next cursor position. Move cursor to prepare for `MDBX_NEXT_MULTIPLE`. + * \see MDBX_SEEK_AND_GET_MULTIPLE \see MDBX_GET_MULTIPLE */ MDBX_NEXT_MULTIPLE, /** Position at first data item of next key */ @@ -1760,7 +1760,8 @@ typedef enum MDBX_cursor_op { MDBX_SET_RANGE, /** \ref MDBX_DUPFIXED -only: Position at previous page and return up to - * a page of duplicate data items. */ + * a page of duplicate data items. + * \see MDBX_SEEK_AND_GET_MULTIPLE \see MDBX_GET_MULTIPLE */ MDBX_PREV_MULTIPLE, /** Positions cursor at first key-value pair greater than or equal to @@ -1812,7 +1813,12 @@ typedef enum MDBX_cursor_op { MDBX_TO_PAIR_LESSER_OR_EQUAL /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, MDBX_TO_PAIR_EQUAL /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, MDBX_TO_PAIR_GREATER_OR_EQUAL /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, - MDBX_TO_PAIR_GREATER_THAN /** \copydoc MDBX_TO_PAIR_LESSER_THAN */ + MDBX_TO_PAIR_GREATER_THAN /** \copydoc MDBX_TO_PAIR_LESSER_THAN */, + + /** \ref MDBX_DUPFIXED -only: Seek to given key and return up to a page of + * duplicate data items from current cursor position. Move cursor to prepare + * for \ref MDBX_NEXT_MULTIPLE. \see MDBX_GET_MULTIPLE */ + MDBX_SEEK_AND_GET_MULTIPLE } MDBX_cursor_op; /** \brief Errors and return codes diff --git a/src/cursor.c b/src/cursor.c index bb6f4e61..9c1192d9 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -2047,27 +2047,24 @@ __hot int cursor_ops(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, const MDBX_ cASSERT(mc, is_poor(mc) && !is_filled(mc)); return rc; + case MDBX_SEEK_AND_GET_MULTIPLE: + if (unlikely(!key)) + return MDBX_EINVAL; + rc = cursor_seek(mc, key, data, MDBX_SET).err; + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + __fallthrough /* fall through */; case MDBX_GET_MULTIPLE: if (unlikely(!data)) return MDBX_EINVAL; if (unlikely((mc->tree->flags & MDBX_DUPFIXED) == 0)) return MDBX_INCOMPATIBLE; - if (unlikely(!is_pointed(mc))) { - if (unlikely(!key)) - return MDBX_EINVAL; - if (unlikely((mc->flags & z_fresh) == 0)) - return MDBX_ENODATA; - rc = cursor_seek(mc, key, data, MDBX_SET).err; - if (unlikely(rc != MDBX_SUCCESS)) - return rc; - } else { - if (unlikely(!is_filled(mc))) - return MDBX_ENODATA; - if (key) { - const page_t *mp = mc->pg[mc->top]; - const node_t *node = page_node(mp, mc->ki[mc->top]); - *key = get_key(node); - } + if (unlikely(!is_filled(mc))) + return MDBX_ENODATA; + if (key) { + const page_t *mp = mc->pg[mc->top]; + const node_t *node = page_node(mp, mc->ki[mc->top]); + *key = get_key(node); } cASSERT(mc, is_filled(mc)); if (unlikely(!inner_filled(mc))) { @@ -2102,15 +2099,6 @@ __hot int cursor_ops(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, const MDBX_ return MDBX_EINVAL; if (unlikely(mc->subcur == nullptr)) return MDBX_INCOMPATIBLE; - if (unlikely(!is_pointed(mc))) { - if (unlikely((mc->flags & z_fresh) == 0)) - return MDBX_ENODATA; - rc = outer_last(mc, key, data); - if (unlikely(rc != MDBX_SUCCESS)) - return rc; - mc->subcur->cursor.ki[mc->subcur->cursor.top] = 0; - goto fetch_multiple; - } if (unlikely(!is_filled(mc) || !inner_filled(mc))) return MDBX_ENODATA; rc = cursor_sibling_left(&mc->subcur->cursor); From 17207620800c285200901bb99d24fb12070bb013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:19:31 +0300 Subject: [PATCH 139/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B8?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20`curso?= =?UTF-8?q?r=5Fvalidate()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cursor.c | 20 ++++++++++---------- src/cursor.h | 4 ++-- src/tree-ops.c | 16 ++++++++-------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/cursor.c b/src/cursor.c index 9c1192d9..ff2c67e8 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -5,7 +5,7 @@ #include "internals.h" -__cold int cursor_check(const MDBX_cursor *mc) { +__cold int cursor_validate(const MDBX_cursor *mc) { if (!mc->txn->tw.dirtylist) { cASSERT(mc, (mc->txn->flags & MDBX_WRITEMAP) != 0 && !MDBX_AVOID_MSYNC); } else { @@ -81,10 +81,10 @@ __cold int cursor_check(const MDBX_cursor *mc) { return MDBX_SUCCESS; } -__cold int cursor_check_updating(MDBX_cursor *mc) { +__cold int cursor_validate_updating(MDBX_cursor *mc) { const uint8_t checking = mc->checking; mc->checking |= z_updating; - const int rc = cursor_check(mc); + const int rc = cursor_validate(mc); mc->checking = checking; return rc; } @@ -938,7 +938,7 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig } if (AUDIT_ENABLED()) { - err = cursor_check(mc); + err = cursor_validate(mc); if (unlikely(err != MDBX_SUCCESS)) return err; } @@ -947,7 +947,7 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig more: if (AUDIT_ENABLED()) { - err = cursor_check(mc); + err = cursor_validate(mc); if (unlikely(err != MDBX_SUCCESS)) return err; } @@ -1008,7 +1008,7 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig memcpy(page_data(lp.page), data->iov_base, data->iov_len); if (AUDIT_ENABLED()) { - err = cursor_check(mc); + err = cursor_validate(mc); if (unlikely(err != MDBX_SUCCESS)) return err; } @@ -1274,7 +1274,7 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig } if (AUDIT_ENABLED()) { - err = cursor_check(mc); + err = cursor_validate(mc); if (unlikely(err != MDBX_SUCCESS)) return err; } @@ -1292,7 +1292,7 @@ insert_node:; if (page_room(mc->pg[mc->top]) < nsize) { rc = page_split(mc, key, ref_data, P_INVALID, insert_key ? naf : naf | MDBX_SPLIT_REPLACE); if (rc == MDBX_SUCCESS && AUDIT_ENABLED()) - rc = insert_key ? cursor_check(mc) : cursor_check_updating(mc); + rc = insert_key ? cursor_validate(mc) : cursor_validate_updating(mc); } else { /* There is room already in this leaf page. */ if (is_dupfix_leaf(mc->pg[mc->top])) { @@ -1414,7 +1414,7 @@ insert_node:; } } if (AUDIT_ENABLED()) - rc = cursor_check(mc); + rc = cursor_validate(mc); } return rc; @@ -1686,7 +1686,7 @@ del_key: cASSERT(mc, rc == MDBX_SUCCESS); if (AUDIT_ENABLED()) - rc = cursor_check(mc); + rc = cursor_validate(mc); return rc; fail: diff --git a/src/cursor.h b/src/cursor.h index d06bad3a..4fa0e585 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -233,7 +233,7 @@ enum cursor_checking { z_pagecheck = 0x80 /* perform page checking, see MDBX_VALIDATION */ }; -MDBX_INTERNAL int __must_check_result cursor_check(const MDBX_cursor *mc); +MDBX_INTERNAL int __must_check_result cursor_validate(const MDBX_cursor *mc); MDBX_MAYBE_UNUSED MDBX_NOTHROW_PURE_FUNCTION static inline size_t cursor_dbi(const MDBX_cursor *mc) { cASSERT(mc, mc->txn && mc->txn->signature == txn_signature); @@ -305,7 +305,7 @@ MDBX_INTERNAL int __must_check_result cursor_put_checklen(MDBX_cursor *mc, const MDBX_INTERNAL int __must_check_result cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsigned flags); -MDBX_INTERNAL int __must_check_result cursor_check_updating(MDBX_cursor *mc); +MDBX_INTERNAL int __must_check_result cursor_validate_updating(MDBX_cursor *mc); MDBX_INTERNAL int __must_check_result cursor_del(MDBX_cursor *mc, unsigned flags); diff --git a/src/tree-ops.c b/src/tree-ops.c index d0456792..85131c42 100644 --- a/src/tree-ops.c +++ b/src/tree-ops.c @@ -880,7 +880,7 @@ retry: if (nkeys >= minkeys) { mc->ki[mc->top] = (indx_t)ki_top; if (AUDIT_ENABLED()) - return cursor_check_updating(mc); + return cursor_validate_updating(mc); return MDBX_SUCCESS; } @@ -920,7 +920,7 @@ int page_split(MDBX_cursor *mc, const MDBX_val *const newkey, MDBX_val *const ne const size_t newindx = mc->ki[mc->top]; size_t nkeys = page_numkeys(mp); if (AUDIT_ENABLED()) { - rc = cursor_check_updating(mc); + rc = cursor_validate_updating(mc); if (unlikely(rc != MDBX_SUCCESS)) return rc; } @@ -979,7 +979,7 @@ int page_split(MDBX_cursor *mc, const MDBX_val *const newkey, MDBX_val *const ne mc->top = 1; prev_top = 0; if (AUDIT_ENABLED()) { - rc = cursor_check_updating(mc); + rc = cursor_validate_updating(mc); if (unlikely(rc != MDBX_SUCCESS)) goto done; } @@ -1092,10 +1092,10 @@ int page_split(MDBX_cursor *mc, const MDBX_val *const newkey, MDBX_val *const ne } if (AUDIT_ENABLED()) { - rc = cursor_check_updating(mc); + rc = cursor_validate_updating(mc); if (unlikely(rc != MDBX_SUCCESS)) goto done; - rc = cursor_check_updating(mn); + rc = cursor_validate_updating(mn); if (unlikely(rc != MDBX_SUCCESS)) goto done; } @@ -1221,7 +1221,7 @@ int page_split(MDBX_cursor *mc, const MDBX_val *const newkey, MDBX_val *const ne goto done; cASSERT(mc, mc->top - top == mc->tree->height - height); if (AUDIT_ENABLED()) { - rc = cursor_check_updating(mc); + rc = cursor_validate_updating(mc); if (unlikely(rc != MDBX_SUCCESS)) goto done; } @@ -1474,7 +1474,7 @@ done: mc->txn->flags |= MDBX_TXN_ERROR; else { if (AUDIT_ENABLED()) - rc = cursor_check_updating(mc); + rc = cursor_validate_updating(mc); if (unlikely(naf & MDBX_RESERVE)) { node_t *node = page_node(mc->pg[mc->top], mc->ki[mc->top]); if (!(node_flags(node) & N_BIG)) @@ -1524,7 +1524,7 @@ int tree_propagate_key(MDBX_cursor *mc, const MDBX_val *key) { node_del(mc, 0); int err = page_split(mc, key, nullptr, pgno, MDBX_SPLIT_REPLACE); if (err == MDBX_SUCCESS && AUDIT_ENABLED()) - err = cursor_check_updating(mc); + err = cursor_validate_updating(mc); return err; } From 5dfe3433a8f446d5c63a032bcccff011c6cd492a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:21:02 +0300 Subject: [PATCH 140/181] =?UTF-8?q?mdbx:=20=D1=83=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B3=D0=BE=D0=BD=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=B2=20`tbl=5Fsetup(MDBX=5FDUPFIXED=20|=20MDBX=5FINTEGERDU?= =?UTF-8?q?P)`=20=D0=BF=D1=80=D0=B8=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B5?= =?UTF-8?q?=20=D0=B2=20=D1=80=D0=B0=D0=B7=D0=BD=D1=8B=D1=85=20=D0=BF=D0=BE?= =?UTF-8?q?=D1=82=D0=BE=D0=BA=D0=B0=D1=85=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проблема была в том, что в случаях фиксированного размера значений clc.lmin/clc.lmax устанавливались в env->kvs[], а затем корректировались по актуальному размеру данных в БД. Поэтому при конкурентном вызове из разных потоков, один поток мог выполнять инициализацию, а второй прочитать временные/промежуточные значения lmin/lmax. В результате, при конкурентном старте транзакций в разных потоках при использовании только-что открытого dbi-хендла, проверка допустимости длины значения могла заканчиваться ложной ошибкой MDBX_BAD_VALSIZE. --- src/cogs.h | 4 ++++ src/cursor.c | 6 ++---- src/proto.h | 2 +- src/table.c | 40 ++++++++++++++++++++++++++-------------- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/cogs.h b/src/cogs.h index 11d7fe1d..7e814e7b 100644 --- a/src/cogs.h +++ b/src/cogs.h @@ -200,6 +200,10 @@ static inline bool check_table_flags(unsigned flags) { } } +static inline int tbl_setup_ifneed(const MDBX_env *env, volatile kvx_t *const kvx, const tree_t *const db) { + return likely(kvx->clc.v.lmax) ? MDBX_SUCCESS : tbl_setup(env, kvx, db); +} + /*----------------------------------------------------------------------------*/ MDBX_NOTHROW_PURE_FUNCTION static inline size_t pgno2bytes(const MDBX_env *env, size_t pgno) { diff --git a/src/cursor.c b/src/cursor.c index ff2c67e8..01fc8a56 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -298,10 +298,7 @@ static __always_inline int couple_init(cursor_couple_t *couple, const MDBX_txn * if (unlikely(*dbi_state & DBI_STALE)) return tbl_fetch(couple->outer.txn, cursor_dbi(&couple->outer)); - if (unlikely(kvx->clc.k.lmax == 0)) - return tbl_setup(txn->env, kvx, tree); - - return MDBX_SUCCESS; + return tbl_setup_ifneed(txn->env, kvx, tree); } __cold int cursor_init4walk(cursor_couple_t *couple, const MDBX_txn *const txn, tree_t *const tree, kvx_t *const kvx) { @@ -387,6 +384,7 @@ int cursor_dupsort_setup(MDBX_cursor *mc, const node_t *node, const page_t *mp) } mc->tree->dupfix_size = mx->nested_tree.dupfix_size; mc->clc->v.lmin = mc->clc->v.lmax = mx->nested_tree.dupfix_size; + cASSERT(mc, mc->clc->v.lmax >= mc->clc->v.lmin); } DEBUG("Sub-db dbi -%zu root page %" PRIaPGNO, cursor_dbi(&mx->cursor), mx->nested_tree.root); diff --git a/src/proto.h b/src/proto.h index f0a6657f..92bbce6d 100644 --- a/src/proto.h +++ b/src/proto.h @@ -95,7 +95,7 @@ MDBX_INTERNAL void recalculate_subpage_thresholds(MDBX_env *env); /* table.c */ MDBX_INTERNAL int __must_check_result tbl_fetch(MDBX_txn *txn, size_t dbi); -MDBX_INTERNAL int __must_check_result tbl_setup(const MDBX_env *env, kvx_t *const kvx, const tree_t *const db); +MDBX_INTERNAL int __must_check_result tbl_setup(const MDBX_env *env, volatile kvx_t *const kvx, const tree_t *const db); /* coherency.c */ MDBX_INTERNAL bool coherency_check_meta(const MDBX_env *env, const volatile meta_t *meta, bool report); diff --git a/src/table.c b/src/table.c index faa44da1..5b3e441a 100644 --- a/src/table.c +++ b/src/table.c @@ -3,28 +3,37 @@ #include "internals.h" -int tbl_setup(const MDBX_env *env, kvx_t *const kvx, const tree_t *const db) { +int tbl_setup(const MDBX_env *env, volatile kvx_t *const kvx, const tree_t *const db) { + osal_memory_fence(mo_AcquireRelease, false); + if (unlikely(!check_table_flags(db->flags))) { ERROR("incompatible or invalid db.flags (0x%x) ", db->flags); return MDBX_INCOMPATIBLE; } - if (unlikely(!kvx->clc.k.cmp)) { - kvx->clc.k.cmp = builtin_keycmp(db->flags); - kvx->clc.v.cmp = builtin_datacmp(db->flags); + + size_t v_lmin = valsize_min(db->flags); + size_t v_lmax = env_valsize_max(env, db->flags); + if ((db->flags & (MDBX_DUPFIXED | MDBX_INTEGERDUP)) != 0 && db->dupfix_size) { + if (!MDBX_DISABLE_VALIDATION && unlikely(db->dupfix_size < v_lmin || db->dupfix_size > v_lmax)) { + ERROR("db.dupfix_size (%u) <> min/max value-length (%zu/%zu)", db->dupfix_size, v_lmin, v_lmax); + return MDBX_CORRUPTED; + } + v_lmin = v_lmax = db->dupfix_size; } kvx->clc.k.lmin = keysize_min(db->flags); kvx->clc.k.lmax = env_keysize_max(env, db->flags); - kvx->clc.v.lmin = valsize_min(db->flags); - kvx->clc.v.lmax = env_valsize_max(env, db->flags); - - if ((db->flags & (MDBX_DUPFIXED | MDBX_INTEGERDUP)) != 0 && db->dupfix_size) { - if (!MDBX_DISABLE_VALIDATION && unlikely(db->dupfix_size < kvx->clc.v.lmin || db->dupfix_size > kvx->clc.v.lmax)) { - ERROR("db.dupfix_size (%u) <> min/max value-length (%zu/%zu)", db->dupfix_size, kvx->clc.v.lmin, kvx->clc.v.lmax); - return MDBX_CORRUPTED; - } - kvx->clc.v.lmin = kvx->clc.v.lmax = db->dupfix_size; + if (unlikely(!kvx->clc.k.cmp)) { + kvx->clc.v.cmp = builtin_datacmp(db->flags); + kvx->clc.k.cmp = builtin_keycmp(db->flags); } + kvx->clc.v.lmin = v_lmin; + osal_memory_fence(mo_Relaxed, true); + kvx->clc.v.lmax = v_lmax; + osal_memory_fence(mo_AcquireRelease, true); + + eASSERT(env, kvx->clc.k.lmax >= kvx->clc.k.lmin); + eASSERT(env, kvx->clc.v.lmax >= kvx->clc.v.lmin); return MDBX_SUCCESS; } @@ -86,10 +95,13 @@ int tbl_fetch(MDBX_txn *txn, size_t dbi) { return MDBX_CORRUPTED; } #endif /* !MDBX_DISABLE_VALIDATION */ - rc = tbl_setup(txn->env, kvx, db); + rc = tbl_setup_ifneed(txn->env, kvx, db); if (unlikely(rc != MDBX_SUCCESS)) return rc; + if (unlikely(dbi_changed(txn, dbi))) + return MDBX_BAD_DBI; + txn->dbi_state[dbi] &= ~DBI_STALE; return MDBX_SUCCESS; } From 58729a2fbd4a2cd6b9cbe80be993149c2ee3b946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:40:11 +0300 Subject: [PATCH 141/181] =?UTF-8?q?mdbx:=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=BE=D0=BF?= =?UTF-8?q?=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D1=8F=20`MDBX=5FMVCC=5FRETARDED`?= =?UTF-8?q?=20=D0=B8=20=D1=81=D0=BE=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B5=D0=B3=D0=BE=20=D1=81=D0=BE?= =?UTF-8?q?=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BE=D0=B1=20?= =?UTF-8?q?=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B5=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 3 +-- src/api-misc.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/mdbx.h b/mdbx.h index cce6c6a5..0ae5921a 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1972,8 +1972,7 @@ typedef enum MDBX_error { * recycling old MVCC snapshots. */ MDBX_OUSTED = -30411, - /** MVCC snapshot used by read transaction is outdated and could not be - * copied since corresponding meta-pages was overwritten. */ + /** MVCC snapshot used by parked transaction was bygone. */ MDBX_MVCC_RETARDED = -30410, /* The last of MDBX-added error codes */ diff --git a/src/api-misc.c b/src/api-misc.c index 7e54c51d..27e82a90 100644 --- a/src/api-misc.c +++ b/src/api-misc.c @@ -199,9 +199,7 @@ __cold const char *mdbx_liberr2str(int errnum) { return "MDBX_OUSTED: The parked read transaction was outed for the sake" " of recycling old MVCC snapshots"; case MDBX_MVCC_RETARDED: - return "MDBX_MVCC_RETARDED: MVCC snapshot used by read transaction" - " is outdated and could not be copied" - " since corresponding meta-pages was overwritten"; + return "MDBX_MVCC_RETARDED: MVCC snapshot used by parked transaction was bygone"; default: return nullptr; } From 73d52c19638c52ae8ab4de8a377b93b187cd2337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:40:41 +0300 Subject: [PATCH 142/181] =?UTF-8?q?mdbx++:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`mdbx::cursor=5Fmanaged:?= =?UTF-8?q?:withdraw=5Fhandle()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mdbx.h++ b/mdbx.h++ index 3b6e6239..8ba9f102 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -4155,9 +4155,9 @@ public: class LIBMDBX_API_TYPE cursor { protected: MDBX_cursor *handle_{nullptr}; - MDBX_CXX11_CONSTEXPR cursor(MDBX_cursor *ptr) noexcept; public: + MDBX_CXX11_CONSTEXPR cursor(MDBX_cursor *ptr) noexcept; MDBX_CXX11_CONSTEXPR cursor() noexcept = default; cursor(const cursor &) noexcept = default; inline cursor &operator=(cursor &&other) noexcept; @@ -4561,6 +4561,12 @@ public: return *this; } + inline MDBX_cursor *withdraw_handle() noexcept { + MDBX_cursor *handle = handle_; + handle_ = nullptr; + return handle; + } + cursor_managed(const cursor_managed &) = delete; cursor_managed &operator=(const cursor_managed &) = delete; ~cursor_managed() noexcept { ::mdbx_cursor_close(handle_); } From d8890bc1695e69cc748ac2e78fe7426d358a8214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:41:05 +0300 Subject: [PATCH 143/181] =?UTF-8?q?mdbx++:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`inplace=5Fstorage=5Fsiz?= =?UTF-8?q?e=5Frounding`=20=D0=B2=20`capacity=5Fpolicy`=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=B1=D1=83=D1=84=D0=B5=D1=80=D0=BE=D0=B2=20(backport?= =?UTF-8?q?).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 111 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 45 deletions(-) diff --git a/mdbx.h++ b/mdbx.h++ index 8ba9f102..97120b3f 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -1162,7 +1162,12 @@ template struct swap_alloc { } // namespace allocation_aware_details struct default_capacity_policy { - enum : size_t { extra_inplace_storage = 0, pettiness_threshold = 64, max_reserve = 65536 }; + enum : size_t { + extra_inplace_storage = 0, + inplace_storage_size_rounding = 16, + pettiness_threshold = 64, + max_reserve = 65536 + }; static MDBX_CXX11_CONSTEXPR size_t round(const size_t value) { static_assert((pettiness_threshold & (pettiness_threshold - 1)) == 0, "pettiness_threshold must be a power of 2"); @@ -1486,6 +1491,10 @@ public: max_length = MDBX_MAXDATASIZE, max_capacity = (max_length / 3u * 4u + 1023u) & ~size_t(1023), extra_inplace_storage = reservation_policy::extra_inplace_storage, + inplace_storage_size_rounding = + (alignof(max_align_t) * 2 > size_t(reservation_policy::inplace_storage_size_rounding)) + ? alignof(max_align_t) * 2 + : size_t(reservation_policy::inplace_storage_size_rounding), pettiness_threshold = reservation_policy::pettiness_threshold }; @@ -1529,41 +1538,51 @@ private: #endif /* __cpp_lib_to_address */ } - union bin { - struct allocated { + union alignas(max_align_t) bin { + struct stub_allocated_holder /* используется только для вычисления (минимального необходимого) размера, + с учетом выравнивания */ + { allocator_pointer ptr_; - size_t capacity_bytes_; - constexpr allocated(allocator_pointer ptr, size_t bytes) noexcept : ptr_(ptr), capacity_bytes_(bytes) {} - constexpr allocated(const allocated &) noexcept = default; - constexpr allocated(allocated &&) noexcept = default; - MDBX_CXX17_CONSTEXPR allocated &operator=(const allocated &) noexcept = default; - MDBX_CXX17_CONSTEXPR allocated &operator=(allocated &&) noexcept = default; + size_t stub_capacity_bytes_; }; - allocated allocated_; - uint64_t align_hint_; - byte inplace_[(sizeof(allocated) + extra_inplace_storage + 7u) & ~size_t(7)]; - - static constexpr bool is_suitable_for_inplace(size_t capacity_bytes) noexcept { - static_assert(sizeof(bin) == sizeof(inplace_), "WTF?"); - return capacity_bytes < sizeof(bin); - } - - enum : byte { lastbyte_inplace_signature = byte(~byte(0)) }; + enum : byte { lastbyte_poison = 0, lastbyte_inplace_signature = byte(~byte(lastbyte_poison)) }; enum : size_t { inplace_signature_limit = size_t(lastbyte_inplace_signature) - << (sizeof(size_t /* allocated::capacity_bytes_ */) - 1) * CHAR_BIT + << (sizeof(size_t /* allocated::capacity_bytes_ */) - 1) * CHAR_BIT, + inplace_size_rounding = size_t(inplace_storage_size_rounding) - 1, + inplace_size = + (sizeof(stub_allocated_holder) + extra_inplace_storage + inplace_size_rounding) & ~inplace_size_rounding }; - constexpr byte inplace_lastbyte() const noexcept { return inplace_[sizeof(bin) - 1]; } - MDBX_CXX17_CONSTEXPR byte &inplace_lastbyte() noexcept { return inplace_[sizeof(bin) - 1]; } + struct capacity_holder { + byte pad_[inplace_size - sizeof(allocator_pointer)]; + size_t bytes_; + }; + + struct inplace_flag_holder { + byte buffer_[inplace_size - sizeof(byte)]; + byte lastbyte_; + }; + + allocator_pointer allocated_ptr_; + capacity_holder capacity_; + inplace_flag_holder inplace_; + + static constexpr bool is_suitable_for_inplace(size_t capacity_bytes) noexcept { + static_assert((size_t(reservation_policy::inplace_storage_size_rounding) & + (size_t(reservation_policy::inplace_storage_size_rounding) - 1)) == 0, + "CAPACITY_POLICY::inplace_storage_size_rounding must be power of 2"); + static_assert(sizeof(bin) == sizeof(inplace_) && sizeof(bin) == sizeof(capacity_), "WTF?"); + return capacity_bytes < sizeof(bin); + } constexpr bool is_inplace() const noexcept { static_assert(size_t(inplace_signature_limit) > size_t(max_capacity), "WTF?"); static_assert(std::numeric_limits::max() - (std::numeric_limits::max() >> CHAR_BIT) == inplace_signature_limit, "WTF?"); - return inplace_lastbyte() == lastbyte_inplace_signature; + return inplace_.lastbyte_ == lastbyte_inplace_signature; } constexpr bool is_allocated() const noexcept { return !is_inplace(); } @@ -1571,26 +1590,27 @@ private: if (destroy_ptr) { MDBX_CONSTEXPR_ASSERT(is_allocated()); /* properly destroy allocator::pointer */ - allocated_.~allocated(); + allocated_ptr_.~allocator_pointer(); } if (::std::is_trivial::value) /* workaround for "uninitialized" warning from some compilers */ - memset(&allocated_.ptr_, 0, sizeof(allocated_.ptr_)); - inplace_lastbyte() = lastbyte_inplace_signature; - MDBX_CONSTEXPR_ASSERT(is_inplace() && address() == inplace_ && is_suitable_for_inplace(capacity())); + memset(&allocated_ptr_, 0, sizeof(allocated_ptr_)); + inplace_.lastbyte_ = lastbyte_inplace_signature; + MDBX_CONSTEXPR_ASSERT(is_inplace() && address() == inplace_.buffer_ && is_suitable_for_inplace(capacity())); return address(); } template MDBX_CXX17_CONSTEXPR byte *make_allocated(allocator_pointer ptr, size_t capacity_bytes) noexcept { MDBX_CONSTEXPR_ASSERT(inplace_signature_limit > capacity_bytes); - if (construct_ptr) + if (construct_ptr) { /* properly construct allocator::pointer */ - new (&allocated_) allocated(ptr, capacity_bytes); - else { + new (&allocated_ptr_) allocator_pointer(ptr); + capacity_.bytes_ = capacity_bytes; + } else { MDBX_CONSTEXPR_ASSERT(is_allocated()); - allocated_.ptr_ = ptr; - allocated_.capacity_bytes_ = capacity_bytes; + allocated_ptr_ = ptr; + capacity_.bytes_ = capacity_bytes; } MDBX_CONSTEXPR_ASSERT(is_allocated() && address() == to_address(ptr) && capacity() == capacity_bytes); return address(); @@ -1608,16 +1628,17 @@ private: MDBX_CXX20_CONSTEXPR ~bin() { if (is_allocated()) /* properly destroy allocator::pointer */ - allocated_.~allocated(); + allocated_ptr_.~allocator_pointer(); } MDBX_CXX20_CONSTEXPR bin(bin &&ditto) noexcept { if (ditto.is_inplace()) { // micro-optimization: don't use make_inplace<> here // since memcpy() will copy the flag. - memcpy(inplace_, ditto.inplace_, sizeof(inplace_)); + memcpy(&inplace_, &ditto.inplace_, sizeof(inplace_)); MDBX_CONSTEXPR_ASSERT(is_inplace()); } else { - new (&allocated_) allocated(::std::move(ditto.allocated_)); + new (&allocated_ptr_) allocator_pointer(::std::move(ditto.allocated_ptr_)); + capacity_.bytes_ = ditto.capacity_.bytes_; ditto.make_inplace(); MDBX_CONSTEXPR_ASSERT(is_allocated()); } @@ -1629,13 +1650,13 @@ private: // since memcpy() will copy the flag. if (is_allocated()) /* properly destroy allocator::pointer */ - allocated_.~allocated(); - memcpy(inplace_, ditto.inplace_, sizeof(inplace_)); + allocated_ptr_.~allocator_pointer(); + memcpy(&inplace_, &ditto.inplace_, sizeof(inplace_)); MDBX_CONSTEXPR_ASSERT(is_inplace()); } else if (is_inplace()) - make_allocated(ditto.allocated_.ptr_, ditto.allocated_.capacity_bytes_); + make_allocated(ditto.allocated_ptr_, ditto.capacity_.bytes_); else - make_allocated(ditto.allocated_.ptr_, ditto.allocated_.capacity_bytes_); + make_allocated(ditto.allocated_ptr_, ditto.capacity_.bytes_); return *this; } @@ -1656,12 +1677,12 @@ private: } constexpr const byte *address() const noexcept { - return is_inplace() ? inplace_ : static_cast(to_address(allocated_.ptr_)); + return is_inplace() ? inplace_.buffer_ : static_cast(to_address(allocated_ptr_)); } MDBX_CXX17_CONSTEXPR byte *address() noexcept { - return is_inplace() ? inplace_ : static_cast(to_address(allocated_.ptr_)); + return is_inplace() ? inplace_.buffer_ : static_cast(to_address(allocated_ptr_)); } - constexpr size_t capacity() const noexcept { return is_inplace() ? sizeof(bin) - 1 : allocated_.capacity_bytes_; } + constexpr size_t capacity() const noexcept { return is_inplace() ? sizeof(bin) - 1 : capacity_.bytes_; } } bin_; MDBX_CXX20_CONSTEXPR void *init(size_t capacity) { @@ -1678,7 +1699,7 @@ private: MDBX_CXX20_CONSTEXPR void release() noexcept { if (bin_.is_allocated()) { - deallocate_storage(bin_.allocated_.ptr_, bin_.allocated_.capacity_bytes_); + deallocate_storage(bin_.allocated_ptr_, bin_.capacity_.bytes_); bin_.template make_inplace(); } } @@ -1709,7 +1730,7 @@ private: if (bin::is_suitable_for_inplace(new_capacity)) { assert(bin_.is_allocated()); - const auto old_allocated = ::std::move(bin_.allocated_.ptr_); + const auto old_allocated = ::std::move(bin_.allocated_ptr_); byte *const new_place = bin_.template make_inplace() + wanna_headroom; if (MDBX_LIKELY(length)) MDBX_CXX20_LIKELY memcpy(new_place, content, length); @@ -1727,7 +1748,7 @@ private: return new_place; } - const auto old_allocated = ::std::move(bin_.allocated_.ptr_); + const auto old_allocated = ::std::move(bin_.allocated_ptr_); if (external_content) deallocate_storage(old_allocated, old_capacity); const auto pair = allocate_storage(new_capacity); From c5936eb5da73f1c70091707c895a4fd3b4805253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:41:32 +0300 Subject: [PATCH 144/181] =?UTF-8?q?mdbx++:=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D1=80=D0=B8=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=81=D0=B5=20=D1=82=D1=80=D0=B0=D0=BD=D0=B7?= =?UTF-8?q?=D0=B0=D0=BA=D1=86=D0=B8=D0=B8=20=D1=83=20=D0=BE=D1=82=D1=81?= =?UTF-8?q?=D0=BE=D0=B5=D0=B4=D0=B8=D0=BD=D1=91=D0=BD=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=BA=D1=83=D1=80=D1=81=D0=BE=D1=80=D0=B0=20(backport?= =?UTF-8?q?).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 1 - 1 file changed, 1 deletion(-) diff --git a/mdbx.h++ b/mdbx.h++ index 97120b3f..e6186b1e 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -6206,7 +6206,6 @@ inline void cursor::unbind() { error::success_or_throw(::mdbx_cursor_unbind(hand inline txn cursor::txn() const { MDBX_txn *txn = ::mdbx_cursor_txn(handle_); - error::throw_on_nullptr(txn, MDBX_EINVAL); return ::mdbx::txn(txn); } From 682233ba28488827c3eb15291ed1c9cbdb218f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:41:58 +0300 Subject: [PATCH 145/181] =?UTF-8?q?mdbx++:=20=D0=BF=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B5=20(=D0=B2=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=BD=D0=BE)=20=D0=BD=D0=B5=D0=B8=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D1=83=D0=B5=D0=BC=D0=BE=D0=B3=D0=BE=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4=D0=B0=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mdbx.c++ | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/mdbx.c++ b/src/mdbx.c++ index 63f56190..7b4d8aa1 100644 --- a/src/mdbx.c++ +++ b/src/mdbx.c++ @@ -63,8 +63,8 @@ class trouble_location { #endif public: - MDBX_CXX11_CONSTEXPR trouble_location(unsigned line, const char *condition, - const char *function, const char *filename) + MDBX_CXX11_CONSTEXPR trouble_location(unsigned line, const char *condition, const char *function, + const char *filename) : #if TROUBLE_PROVIDE_LINENO line_(line) @@ -133,7 +133,7 @@ public: //------------------------------------------------------------------------------ -__cold std::string format_va(const char *fmt, va_list ap) { +__cold std::string format_va(const char *fmt, va_list ap) { va_list ones; va_copy(ones, ap); #ifdef _MSC_VER @@ -146,15 +146,14 @@ __cold std::string format_va(const char *fmt, va_list ap) { result.reserve(size_t(needed + 1)); result.resize(size_t(needed), '\0'); assert(int(result.capacity()) > needed); - int actual = vsnprintf(const_cast(result.data()), result.capacity(), - fmt, ones); + int actual = vsnprintf(const_cast(result.data()), result.capacity(), fmt, ones); assert(actual == needed); (void)actual; va_end(ones); return result; } -__cold std::string format(const char *fmt, ...) { +__cold std::string format(const char *fmt, ...) { va_list ap; va_start(ap, fmt); std::string result = format_va(fmt, ap); @@ -175,17 +174,14 @@ public: virtual ~bug() noexcept; }; -__cold bug::bug(const trouble_location &location) noexcept - : std::runtime_error(format("mdbx.bug: %s.%s at %s:%u", location.function(), - location.condition(), location.filename(), - location.line())), +__cold bug::bug(const trouble_location &location) noexcept + : std::runtime_error(format("mdbx.bug: %s.%s at %s:%u", location.function(), location.condition(), + location.filename(), location.line())), location_(location) {} -__cold bug::~bug() noexcept {} +__cold bug::~bug() noexcept {} -[[noreturn]] __cold void raise_bug(const trouble_location &what_and_where) { - throw bug(what_and_where); -} +[[maybe_unused, noreturn]] __cold void raise_bug(const trouble_location &what_and_where) { throw bug(what_and_where); } #define RAISE_BUG(line, condition, function, file) \ do { \ @@ -193,6 +189,7 @@ __cold bug::~bug() noexcept {} raise_bug(bug); \ } while (0) +#undef ENSURE #define ENSURE(condition) \ do \ if (MDBX_UNLIKELY(!(condition))) \ From 5fd319bbc2913b452b48ce5dc06958694044e46c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:42:50 +0300 Subject: [PATCH 146/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=B5=D1=80=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20`mdbx=5Ftxn=5Frelease=5F?= =?UTF-8?q?all=5Fcursors=5Fex()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 26 ++++++++++-------------- src/api-cursor.c | 51 +++++++++++++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/mdbx.h b/mdbx.h index 0ae5921a..ae2af5ad 100644 --- a/mdbx.h +++ b/mdbx.h @@ -5261,15 +5261,12 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor); * \retval MDBX_EINVAL An invalid parameter was specified. */ LIBMDBX_API int mdbx_cursor_close2(MDBX_cursor *cursor); -/** \brief Unbind or closes all cursors of a given transaction. +/** \brief Unbind or closes all cursors of a given transaction and of all + * its parent transactions if ones are. * \ingroup c_cursors * - * Unbinds either closes all cursors associated (opened or renewed) with - * a given transaction in a bulk with minimal overhead. - * - * A transaction should not be nested, since in this case no way to restore - * state if this nested transaction will be aborted, nor impossible to define - * the expected behavior. + * Unbinds either closes all cursors associated (opened, renewed or binded) with + * the given transaction in a bulk with minimal overhead. * * \see mdbx_cursor_unbind() * \see mdbx_cursor_close() @@ -5284,19 +5281,16 @@ LIBMDBX_API int mdbx_cursor_close2(MDBX_cursor *cursor); * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. - * \retval MDBX_BAD_TXN Given transaction is invalid, nested or has + * \retval MDBX_BAD_TXN Given transaction is invalid or has * a child/nested transaction transaction. */ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count); -/** \brief Unbind or closes all cursors of a given transaction. +/** \brief Unbind or closes all cursors of a given transaction and of all + * its parent transactions if ones are. * \ingroup c_cursors * - * Unbinds either closes all cursors associated (opened or renewed) with - * a given transaction in a bulk with minimal overhead. - * - * A transaction should not be nested, since in this case no way to restore - * state if this nested transaction will be aborted, nor impossible to define - * the expected behavior. + * Unbinds either closes all cursors associated (opened, renewed or binded) with + * the given transaction in a bulk with minimal overhead. * * \see mdbx_cursor_unbind() * \see mdbx_cursor_close() @@ -5309,7 +5303,7 @@ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind * some possible errors are: * \retval MDBX_THREAD_MISMATCH Given transaction is not owned * by current thread. - * \retval MDBX_BAD_TXN Given transaction is invalid, nested or has + * \retval MDBX_BAD_TXN Given transaction is invalid or has * a child/nested transaction transaction. */ LIBMDBX_INLINE_API(int, mdbx_txn_release_all_cursors, (const MDBX_txn *txn, bool unbind)) { return mdbx_txn_release_all_cursors_ex(txn, unbind, NULL); diff --git a/src/api-cursor.c b/src/api-cursor.c index d86bc34e..24288fb5 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -233,28 +233,43 @@ int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *co int rc = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(txn->parent)) { - rc = MDBX_BAD_TXN; - ERROR("%s, err %d", "must not unbind or close cursors for a nested txn", rc); - return rc; - } size_t n = 0; - TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) { - while (txn->cursors[i]) { - ++n; - MDBX_cursor *mc = txn->cursors[i]; - ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup); - txn->cursors[i] = mc->next; - mc->next = mc; - mc->signature = cur_signature_ready4dispose; - cursor_drown((cursor_couple_t *)mc); - if (!unbind) { - mc->signature = 0; - osal_free(mc); + do { + TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) { + MDBX_cursor *mc = txn->cursors[i], *next = nullptr; + if (mc) { + txn->cursors[i] = nullptr; + do { + next = mc->next; + if (mc->signature == cur_signature_live) { + mc->signature = cur_signature_wait4eot; + cursor_drown((cursor_couple_t *)mc); + } else + ENSURE(nullptr, mc->signature == cur_signature_wait4eot); + if (mc->backup) { + MDBX_cursor *bk = mc->backup; + mc->next = bk->next; + mc->backup = bk->backup; + mc->backup = nullptr; + bk->signature = 0; + bk = bk->next; + osal_free(bk); + } else { + mc->signature = cur_signature_ready4dispose; + mc->next = mc; + ++n; + if (!unbind) { + mc->signature = 0; + osal_free(mc); + } + } + } while ((mc = next) != nullptr); } } - } + txn = txn->parent; + } while (txn); + if (count) *count = n; return MDBX_SUCCESS; From 6c036add8bc0eec3461e6a2c93df85c29c59daf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:44:20 +0300 Subject: [PATCH 147/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=B5=D1=80=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D0=B8=20=D0=BA=D1=83=D1=80=D1=81=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=BD=D0=B0=20=D0=B2=D1=85=D0=BE=D0=B4=D0=B5=20?= =?UTF-8?q?API-=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B9=20=D1=81=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=D0=BC=20`cursor=5Fcheck()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cold.c | 2 +- src/api-cursor.c | 155 ++++++++++++--------------------------- src/api-range-estimate.c | 34 ++++----- src/api-txn-data.c | 57 ++++++-------- src/api-txn.c | 12 ++- src/cogs.h | 14 +--- src/cursor.c | 30 ++++++++ src/cursor.h | 15 ++++ src/txn.c | 5 +- 9 files changed, 149 insertions(+), 175 deletions(-) diff --git a/src/api-cold.c b/src/api-cold.c index 8a8c8588..57e1d667 100644 --- a/src/api-cold.c +++ b/src/api-cold.c @@ -141,7 +141,7 @@ __cold int mdbx_env_warmup(const MDBX_env *env, const MDBX_txn *txn, MDBX_warmup return LOG_IFERR(MDBX_EINVAL); if (txn) { - int err = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR); + int err = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_ERROR); if (unlikely(err != MDBX_SUCCESS)) return LOG_IFERR(err); } diff --git a/src/api-cursor.c b/src/api-cursor.c index 24288fb5..18396299 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -27,18 +27,12 @@ int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) { } int mdbx_cursor_reset(MDBX_cursor *mc) { - if (unlikely(!mc)) - return LOG_IFERR(MDBX_EINVAL); + int rc = cursor_check(mc, MDBX_TXN_FINISHED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); - if (likely(mc->signature == cur_signature_live)) { - cursor_reset((cursor_couple_t *)mc); - return MDBX_SUCCESS; - } - - if (likely(mc->signature == cur_signature_ready4dispose)) - return MDBX_SUCCESS; - - return LOG_IFERR(MDBX_EBADSIGN); + cursor_reset((cursor_couple_t *)mc); + return MDBX_SUCCESS; } int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { @@ -50,17 +44,17 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { return LOG_IFERR(rc); } - int rc = check_txn(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - - rc = dbi_check(txn, dbi); + int rc = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); if (unlikely(dbi == FREE_DBI && !(txn->flags & MDBX_TXN_RDONLY))) return LOG_IFERR(MDBX_EACCESS); + rc = dbi_check(txn, dbi); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + if (unlikely(mc->backup)) /* Cursor from parent transaction */ LOG_IFERR(MDBX_EINVAL); @@ -199,12 +193,11 @@ int mdbx_cursor_close2(MDBX_cursor *mc) { } int mdbx_cursor_copy(const MDBX_cursor *src, MDBX_cursor *dest) { - if (unlikely(!src)) - return LOG_IFERR(MDBX_EINVAL); - if (unlikely(src->signature != cur_signature_live)) - return LOG_IFERR((src->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check(src, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); - int rc = mdbx_cursor_bind(src->txn, dest, cursor_dbi(src)); + rc = mdbx_cursor_bind(src->txn, dest, cursor_dbi(src)); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -277,15 +270,16 @@ int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *co int mdbx_cursor_compare(const MDBX_cursor *l, const MDBX_cursor *r, bool ignore_multival) { const int incomparable = INT16_MAX + 1; + if (unlikely(!l)) return r ? -incomparable * 9 : 0; else if (unlikely(!r)) return incomparable * 9; - if (unlikely(l->signature != cur_signature_live)) - return (r->signature == cur_signature_live) ? -incomparable * 8 : 0; - if (unlikely(r->signature != cur_signature_live)) - return (l->signature == cur_signature_live) ? incomparable * 8 : 0; + if (unlikely(cursor_check_pure(l) != MDBX_SUCCESS)) + return (cursor_check_pure(r) == MDBX_SUCCESS) ? -incomparable * 8 : 0; + if (unlikely(cursor_check_pure(r) != MDBX_SUCCESS)) + return (cursor_check_pure(l) == MDBX_SUCCESS) ? incomparable * 8 : 0; if (unlikely(l->clc != r->clc)) { if (l->txn->env != r->txn->env) @@ -351,13 +345,7 @@ int mdbx_cursor_compare(const MDBX_cursor *l, const MDBX_cursor *r, bool ignore_ } int mdbx_cursor_count_ex(const MDBX_cursor *mc, size_t *count, MDBX_stat *ns, size_t bytes) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_ro(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); @@ -407,11 +395,9 @@ int mdbx_cursor_count(const MDBX_cursor *mc, size_t *count) { } int mdbx_cursor_on_first(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); for (intptr_t i = 0; i <= mc->top; ++i) { if (mc->ki[i]) @@ -422,11 +408,9 @@ int mdbx_cursor_on_first(const MDBX_cursor *mc) { } int mdbx_cursor_on_first_dup(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); if (is_filled(mc) && mc->subcur) { mc = &mc->subcur->cursor; @@ -440,11 +424,9 @@ int mdbx_cursor_on_first_dup(const MDBX_cursor *mc) { } int mdbx_cursor_on_last(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); for (intptr_t i = 0; i <= mc->top; ++i) { size_t nkeys = page_numkeys(mc->pg[i]); @@ -456,11 +438,9 @@ int mdbx_cursor_on_last(const MDBX_cursor *mc) { } int mdbx_cursor_on_last_dup(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); if (is_filled(mc) && mc->subcur) { mc = &mc->subcur->cursor; @@ -475,29 +455,18 @@ int mdbx_cursor_on_last_dup(const MDBX_cursor *mc) { } int mdbx_cursor_eof(const MDBX_cursor *mc) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check_pure(mc); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); return is_eof(mc) ? MDBX_RESULT_TRUE : MDBX_RESULT_FALSE; } int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, MDBX_cursor_op op) { - if (unlikely(mc == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_ro(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(cursor_dbi_changed(mc))) - return LOG_IFERR(MDBX_BAD_DBI); - return LOG_IFERR(cursor_ops(mc, key, data, op)); } @@ -622,19 +591,13 @@ int mdbx_cursor_get_batch(MDBX_cursor *mc, size_t *count, MDBX_val *pairs, size_ return LOG_IFERR(MDBX_EINVAL); *count = 0; - if (unlikely(mc == nullptr || limit < 4 || limit > INTPTR_MAX - 2)) + if (unlikely(limit < 4 || limit > INTPTR_MAX - 2)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_ro(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(cursor_dbi_changed(mc))) - return LOG_IFERR(MDBX_BAD_DBI); - if (unlikely(mc->subcur)) return LOG_IFERR(MDBX_INCOMPATIBLE) /* must be a non-dupsort table */; @@ -703,11 +666,9 @@ bailout: /*----------------------------------------------------------------------------*/ int mdbx_cursor_set_userctx(MDBX_cursor *mc, void *ctx) { - if (unlikely(!mc)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_ready4dispose && mc->signature != cur_signature_live)) - return LOG_IFERR(MDBX_EBADSIGN); + int rc = cursor_check(mc, 0); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); cursor_couple_t *couple = container_of(mc, cursor_couple_t, outer); couple->userctx = ctx; @@ -745,21 +706,13 @@ MDBX_dbi mdbx_cursor_dbi(const MDBX_cursor *mc) { /*----------------------------------------------------------------------------*/ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, MDBX_put_flags_t flags) { - if (unlikely(mc == nullptr || key == nullptr || data == nullptr)) + if (unlikely(key == nullptr || data == nullptr)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn_rw(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_rw(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(cursor_dbi_changed(mc))) - return LOG_IFERR(MDBX_BAD_DBI); - - cASSERT(mc, cursor_is_tracked(mc)); - /* Check this first so counter will always be zero on any early failures. */ if (unlikely(flags & MDBX_MULTIPLE)) { if (unlikely(flags & MDBX_RESERVE)) @@ -784,35 +737,21 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, MDBX_p data->iov_base = nullptr; } - if (unlikely(mc->txn->flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED))) - return LOG_IFERR((mc->txn->flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN); - return LOG_IFERR(cursor_put_checklen(mc, key, data, flags)); } int mdbx_cursor_del(MDBX_cursor *mc, MDBX_put_flags_t flags) { - if (unlikely(!mc)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn_rw(mc->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_rw(mc); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(cursor_dbi_changed(mc))) - return LOG_IFERR(MDBX_BAD_DBI); - return LOG_IFERR(cursor_del(mc, flags)); } __cold int mdbx_cursor_ignord(MDBX_cursor *mc) { - if (unlikely(!mc)) - return LOG_IFERR(MDBX_EINVAL); - - if (unlikely(mc->signature != cur_signature_live)) - return LOG_IFERR((mc->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); + int rc = cursor_check(mc, 0); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); mc->checking |= z_ignord; if (mc->subcur) diff --git a/src/api-range-estimate.c b/src/api-range-estimate.c index 5356d4da..56564da0 100644 --- a/src/api-range-estimate.c +++ b/src/api-range-estimate.c @@ -16,12 +16,6 @@ __hot static int cursor_diff(const MDBX_cursor *const __restrict x, const MDBX_c r->level = 0; r->root_nkeys = 0; - if (unlikely(x->signature != cur_signature_live)) - return (x->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN; - - if (unlikely(y->signature != cur_signature_live)) - return (y->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN; - int rc = check_txn(x->txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -146,12 +140,20 @@ __hot static ptrdiff_t estimate(const tree_t *tree, diff_t *const __restrict dr) * Range-Estimation API */ __hot int mdbx_estimate_distance(const MDBX_cursor *first, const MDBX_cursor *last, ptrdiff_t *distance_items) { - if (unlikely(first == nullptr || last == nullptr || distance_items == nullptr)) + if (unlikely(!distance_items)) return LOG_IFERR(MDBX_EINVAL); + int rc = cursor_check_pure(first); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + + rc = cursor_check_pure(last); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + *distance_items = 0; diff_t dr; - int rc = cursor_diff(last, first, &dr); + rc = cursor_diff(last, first, &dr); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); @@ -172,14 +174,10 @@ __hot int mdbx_estimate_distance(const MDBX_cursor *first, const MDBX_cursor *la __hot int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val *data, MDBX_cursor_op move_op, ptrdiff_t *distance_items) { - if (unlikely(cursor == nullptr || distance_items == nullptr || move_op == MDBX_GET_CURRENT || - move_op == MDBX_GET_MULTIPLE)) + if (unlikely(!distance_items || move_op == MDBX_GET_CURRENT || move_op == MDBX_GET_MULTIPLE)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(cursor->signature != cur_signature_live)) - return LOG_IFERR((cursor->signature == cur_signature_ready4dispose) ? MDBX_EINVAL : MDBX_EBADSIGN); - - int rc = check_txn(cursor->txn, MDBX_TXN_BLOCKED); + int rc = cursor_check_ro(cursor); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); @@ -232,10 +230,6 @@ __hot int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key, MDBX_val __hot 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 *size_items) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!size_items)) return LOG_IFERR(MDBX_EINVAL); @@ -248,6 +242,10 @@ __hot int mdbx_estimate_range(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val if (unlikely(begin_key == MDBX_EPSILON && end_key == MDBX_EPSILON)) return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + cursor_couple_t begin; /* LY: first, initialize cursor to refresh a DB in case it have DB_STALE */ rc = cursor_init(&begin.outer, txn, dbi); diff --git a/src/api-txn-data.c b/src/api-txn-data.c index 76bdf32a..2be54df8 100644 --- a/src/api-txn-data.c +++ b/src/api-txn-data.c @@ -51,15 +51,15 @@ __cold int mdbx_dbi_dupsort_depthmask(const MDBX_txn *txn, MDBX_dbi dbi, uint32_ } int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); + if (unlikely(canary == nullptr)) + return LOG_IFERR(MDBX_EINVAL); + + int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); if (unlikely(rc != MDBX_SUCCESS)) { memset(canary, 0, sizeof(*canary)); return LOG_IFERR(rc); } - if (unlikely(canary == nullptr)) - return LOG_IFERR(MDBX_EINVAL); - *canary = txn->canary; return MDBX_SUCCESS; } @@ -68,13 +68,13 @@ int mdbx_get(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *d DKBUF_DEBUG; DEBUG("===> get db %u key [%s]", dbi, DKEY_DEBUG(key)); + if (unlikely(!key || !data)) + return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn(txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(!key || !data)) - return LOG_IFERR(MDBX_EINVAL); - cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) @@ -84,15 +84,12 @@ int mdbx_get(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *d } int mdbx_get_equal_or_great(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!key || !data)) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(txn->flags & MDBX_TXN_BLOCKED)) - return LOG_IFERR(MDBX_BAD_TXN); + int rc = check_txn(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); @@ -106,13 +103,13 @@ int mdbx_get_ex(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data DKBUF_DEBUG; DEBUG("===> get db %u key [%s]", dbi, DKEY_DEBUG(key)); + if (unlikely(!key || !data)) + return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn(txn, MDBX_TXN_BLOCKED); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - if (unlikely(!key || !data)) - return LOG_IFERR(MDBX_EINVAL); - cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) @@ -179,7 +176,7 @@ int mdbx_canary_put(MDBX_txn *txn, const MDBX_canary *canary) { * расположен в той-же странице памяти, в том числе для многостраничных * P_LARGE страниц с длинными данными. */ int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); + int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); @@ -215,18 +212,15 @@ int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) { } int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, const MDBX_val *data) { - int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!key)) return LOG_IFERR(MDBX_EINVAL); if (unlikely(dbi <= FREE_DBI)) return LOG_IFERR(MDBX_BAD_DBI); - if (unlikely(txn->flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED))) - return LOG_IFERR((txn->flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN); + int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); @@ -254,10 +248,6 @@ int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, const MDBX_val *d } int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, MDBX_put_flags_t flags) { - int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) - return LOG_IFERR(rc); - if (unlikely(!key || !data)) return LOG_IFERR(MDBX_EINVAL); @@ -268,8 +258,9 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, M MDBX_APPENDDUP | MDBX_CURRENT | MDBX_MULTIPLE))) return LOG_IFERR(MDBX_EINVAL); - if (unlikely(txn->flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED))) - return LOG_IFERR((txn->flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS : MDBX_BAD_TXN); + int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); @@ -330,10 +321,6 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, M 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 LOG_IFERR(rc); - if (unlikely(!key || !old_data || old_data == new_data)) return LOG_IFERR(MDBX_EINVAL); @@ -350,6 +337,10 @@ int mdbx_replace_ex(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val * MDBX_APPENDDUP | MDBX_CURRENT))) return LOG_IFERR(MDBX_EINVAL); + int rc = check_txn_rw(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + cursor_couple_t cx; rc = cursor_init(&cx.outer, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) diff --git a/src/api-txn.c b/src/api-txn.c index 786e1e42..474f32fd 100644 --- a/src/api-txn.c +++ b/src/api-txn.c @@ -9,7 +9,7 @@ __attribute__((__no_sanitize_thread__, __noinline__)) #endif int mdbx_txn_straggler(const MDBX_txn *txn, int *percent) { - int rc = check_txn(txn, MDBX_TXN_BLOCKED); + int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR((rc > 0) ? -rc : rc); @@ -200,9 +200,13 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, M MDBX_txn *txn = nullptr; if (parent) { /* Nested transactions: Max 1 child, write txns only, no writemap */ - rc = check_txn_rw(parent, MDBX_TXN_RDONLY | MDBX_WRITEMAP | MDBX_TXN_BLOCKED); - if (unlikely(rc != MDBX_SUCCESS)) { - if (rc == MDBX_BAD_TXN && (parent->flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)) == 0) { + rc = check_txn(parent, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + + if (unlikely(parent->flags & (MDBX_TXN_RDONLY | MDBX_WRITEMAP))) { + rc = MDBX_BAD_TXN; + if ((parent->flags & MDBX_TXN_RDONLY) == 0) { ERROR("%s mode is incompatible with nested transactions", "MDBX_WRITEMAP"); rc = MDBX_INCOMPATIBLE; } diff --git a/src/cogs.h b/src/cogs.h index 7e814e7b..498e92b7 100644 --- a/src/cogs.h +++ b/src/cogs.h @@ -416,10 +416,11 @@ static __always_inline int check_txn(const MDBX_txn *txn, int bad_bits) { return MDBX_EPERM; if (unlikely(txn->flags & bad_bits)) { + if ((bad_bits & MDBX_TXN_RDONLY) && unlikely(txn->flags & MDBX_TXN_RDONLY)) + return MDBX_EACCESS; if ((bad_bits & MDBX_TXN_PARKED) == 0) return MDBX_BAD_TXN; - else - return txn_check_badbits_parked(txn, bad_bits); + return txn_check_badbits_parked(txn, bad_bits); } } @@ -437,14 +438,7 @@ static __always_inline int check_txn(const MDBX_txn *txn, int bad_bits) { } static inline int check_txn_rw(const MDBX_txn *txn, int bad_bits) { - int err = check_txn(txn, bad_bits & ~MDBX_TXN_PARKED); - if (unlikely(err)) - return err; - - if (unlikely(txn->flags & MDBX_TXN_RDONLY)) - return MDBX_EACCESS; - - return MDBX_SUCCESS; + return check_txn(txn, (bad_bits | MDBX_TXN_RDONLY) & ~MDBX_TXN_PARKED); } /*----------------------------------------------------------------------------*/ diff --git a/src/cursor.c b/src/cursor.c index 01fc8a56..8a96387d 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -2329,3 +2329,33 @@ __hot int cursor_ops(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, const MDBX_ return MDBX_EINVAL; } } + +int cursor_check(const MDBX_cursor *mc, int txn_bad_bits) { + if (unlikely(mc == nullptr)) + return MDBX_EINVAL; + + if (unlikely(mc->signature != cur_signature_live)) { + if (mc->signature != cur_signature_ready4dispose) + return MDBX_EBADSIGN; + return (txn_bad_bits > MDBX_TXN_FINISHED) ? MDBX_EINVAL : MDBX_SUCCESS; + } + + /* проверяем что курсор в связном списке для отслеживания, исключение допускается только для read-only операций для + * служебных/временных курсоров на стеке. */ + MDBX_MAYBE_UNUSED char stack_top[sizeof(void *)]; + cASSERT(mc, cursor_is_tracked(mc) || (!(txn_bad_bits & MDBX_TXN_RDONLY) && stack_top < (char *)mc && + (char *)mc - stack_top < (ptrdiff_t)globals.sys_pagesize * 4)); + + if (txn_bad_bits) { + int rc = check_txn(mc->txn, txn_bad_bits); + if (unlikely(rc != MDBX_SUCCESS)) { + cASSERT(mc, rc != MDBX_RESULT_TRUE); + return rc; + } + + if (unlikely(cursor_dbi_changed(mc))) + return MDBX_BAD_DBI; + } + + return MDBX_SUCCESS; +} diff --git a/src/cursor.h b/src/cursor.h index 4fa0e585..7f109bcc 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -292,6 +292,21 @@ MDBX_NOTHROW_PURE_FUNCTION static inline bool check_leaf_type(const MDBX_cursor return (((page_type(mp) ^ mc->checking) & (z_branch | z_leaf | z_largepage | z_dupfix)) == 0); } +MDBX_INTERNAL int cursor_check(const MDBX_cursor *mc, int txn_bad_bits); + +/* без необходимости доступа к данным, без активации припаркованных транзакций. */ +static inline int cursor_check_pure(const MDBX_cursor *mc) { + return cursor_check(mc, MDBX_TXN_BLOCKED - MDBX_TXN_PARKED); +} + +/* для чтения данных, с активацией припаркованных транзакций. */ +static inline int cursor_check_ro(const MDBX_cursor *mc) { return cursor_check(mc, MDBX_TXN_BLOCKED); } + +/* для записи данных. */ +static inline int cursor_check_rw(const MDBX_cursor *mc) { + return cursor_check(mc, (MDBX_TXN_BLOCKED - MDBX_TXN_PARKED) | MDBX_TXN_RDONLY); +} + MDBX_INTERNAL MDBX_cursor *cursor_eot(MDBX_cursor *mc, MDBX_txn *txn, const bool merge); MDBX_INTERNAL int cursor_shadow(MDBX_cursor *mc, MDBX_txn *nested, const size_t dbi); diff --git a/src/txn.c b/src/txn.c index a83cd9c8..36ddaf64 100644 --- a/src/txn.c +++ b/src/txn.c @@ -995,7 +995,10 @@ int txn_check_badbits_parked(const MDBX_txn *txn, int bad_bits) { * - но при распарковке поломанные транзакции завершаются. * - получается что транзакцию можно припарковать, потом поломать вызвав * mdbx_txn_break(), но далее любое её использование приведет к завершению - * при распарковке. */ + * при распарковке. + * + * Поэтому для припаркованных транзакций возвращается ошибка если не-включена + * авто-распарковка, либо есть другие плохие биты. */ if ((txn->flags & (bad_bits | MDBX_TXN_AUTOUNPARK)) != (MDBX_TXN_PARKED | MDBX_TXN_AUTOUNPARK)) return LOG_IFERR(MDBX_BAD_TXN); From c457804fad3732f827506b530b00d8c796b9d916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:46:13 +0300 Subject: [PATCH 148/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B7=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BA=D1=83=D1=80=D1=81=D0=BE?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=20=D0=B2=D0=BE=20=D0=B2=D0=BB=D0=BE=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D1=8B=D1=85=20=D1=82=D1=80=D0=B0=D0=BD=D0=B7?= =?UTF-8?q?=D0=B0=D0=BA=D1=86=D0=B8=D1=8F=D1=85=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cursor.c | 6 ++---- src/cursor.c | 13 ++++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/api-cursor.c b/src/api-cursor.c index 18396299..f5f09c20 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -690,11 +690,9 @@ MDBX_txn *mdbx_cursor_txn(const MDBX_cursor *mc) { if (unlikely(!mc || mc->signature != cur_signature_live)) return nullptr; MDBX_txn *txn = mc->txn; - if (unlikely(!txn || txn->signature != txn_signature)) + if (unlikely(!txn || txn->signature != txn_signature || (txn->flags & MDBX_TXN_FINISHED))) return nullptr; - if (unlikely(txn->flags & MDBX_TXN_FINISHED)) - return nullptr; - return txn; + return (txn->flags & MDBX_TXN_HAS_CHILD) ? txn->env->txn : txn; } MDBX_dbi mdbx_cursor_dbi(const MDBX_cursor *mc) { diff --git a/src/cursor.c b/src/cursor.c index 8a96387d..b313a78f 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -2347,14 +2347,21 @@ int cursor_check(const MDBX_cursor *mc, int txn_bad_bits) { (char *)mc - stack_top < (ptrdiff_t)globals.sys_pagesize * 4)); if (txn_bad_bits) { - int rc = check_txn(mc->txn, txn_bad_bits); + int rc = check_txn(mc->txn, txn_bad_bits & ~MDBX_TXN_HAS_CHILD); if (unlikely(rc != MDBX_SUCCESS)) { cASSERT(mc, rc != MDBX_RESULT_TRUE); return rc; } - if (unlikely(cursor_dbi_changed(mc))) - return MDBX_BAD_DBI; + if (likely((mc->txn->flags & MDBX_TXN_HAS_CHILD) == 0)) + return likely(!cursor_dbi_changed(mc)) ? MDBX_SUCCESS : MDBX_BAD_DBI; + + cASSERT(mc, (mc->txn->flags & MDBX_TXN_RDONLY) == 0 && mc->txn != mc->txn->env->txn && mc->txn->env->txn); + rc = dbi_check(mc->txn->env->txn, cursor_dbi(mc)); + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + + cASSERT(mc, (mc->txn->flags & MDBX_TXN_RDONLY) == 0 && mc->txn == mc->txn->env->txn); } return MDBX_SUCCESS; From 5f37ea60d2b45c531a1cd92df6d65d165964ca51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:46:43 +0300 Subject: [PATCH 149/181] =?UTF-8?q?mdbx++:=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D0=B0=20`=5F=5Fcpp=5Fconcepts=20>=3D=2020200?= =?UTF-8?q?2`=20=D0=B4=D0=BB=D1=8F=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D1=86=D0=B5=D0=BF=D1=82=D0=BE=D0=B2=20C++=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mdbx.h++ b/mdbx.h++ index e6186b1e..55bfc8e9 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -243,7 +243,7 @@ #endif /* MDBX_CXX20_UNLIKELY */ #ifndef MDBX_HAVE_CXX20_CONCEPTS -#if defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L +#if defined(__cpp_concepts) && __cpp_concepts >= 202002L && defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L #include #define MDBX_HAVE_CXX20_CONCEPTS 1 #elif defined(DOXYGEN) From 9c177de034386a2414af2eda1172e3891a44d0f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:47:24 +0300 Subject: [PATCH 150/181] =?UTF-8?q?mdbx-tests:=20=D0=B4=D0=BE=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20extra/txn=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/txn.c++ | 539 ++++++++++++++++++++++++--------------------- 1 file changed, 287 insertions(+), 252 deletions(-) diff --git a/test/extra/txn.c++ b/test/extra/txn.c++ index 3a616015..e1abb1e6 100644 --- a/test/extra/txn.c++ +++ b/test/extra/txn.c++ @@ -1,4 +1,5 @@ #include "mdbx.h++" +#include MDBX_CONFIG_H #include @@ -25,267 +26,301 @@ static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int li fprintf(stdout, "%s:%u %s", function, line, msg); } +bool case0(const mdbx::path &path) { + mdbx::env_managed::create_parameters createParameters; + createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, 84 * mdbx::env::geometry::MiB); + + mdbx::env::operate_parameters operateParameters(100, 10); + operateParameters.options.no_sticky_threads = false; + mdbx::env_managed env(path, createParameters, operateParameters); + auto txn = env.start_write(false); + /* mdbx::map_handle testHandle = */ txn.create_map("xyz", mdbx::key_mode::usual, mdbx::value_mode::single); + txn.commit(); + + //------------------------------------- + txn = env.start_write(); + MDBX_txn *c_txn = txn; + int err = mdbx_txn_reset(txn); + assert(err == MDBX_EINVAL); + bool ok = err == MDBX_EINVAL; + + err = mdbx_txn_break(txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + + err = mdbx_txn_commit(txn); + assert(err == MDBX_RESULT_TRUE); + ok = ok && err == MDBX_RESULT_TRUE; + + //------------------------------------- + err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + assert(c_txn == (const MDBX_txn *)txn); + + err = mdbx_txn_break(txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + + err = mdbx_txn_reset(txn); + assert(err == MDBX_EINVAL); + ok = ok && err == MDBX_EINVAL; + + err = mdbx_txn_commit(txn); + assert(err == MDBX_RESULT_TRUE); + ok = ok && err == MDBX_RESULT_TRUE; + + err = mdbx_txn_abort(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + //------------------------------------- + err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + assert(c_txn == (const MDBX_txn *)txn); + txn.commit(); + + err = mdbx_txn_reset(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + err = mdbx_txn_break(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + err = mdbx_txn_abort(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + + //===================================== + + txn = env.start_read(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + txn.make_broken(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + txn.reset_reading(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + txn.abort(); + + //------------------------------------- + + txn = env.start_read(); + txn.reset_reading(); + txn.make_broken(); + txn.abort(); + + //===================================== + + std::latch s(1); + txn = env.start_read(); + c_txn = txn; + + std::thread t([&]() { + s.wait(); +#if MDBX_TXN_CHECKOWNER + err = mdbx_txn_reset(c_txn); + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; + err = mdbx_txn_break(c_txn); + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; + err = mdbx_txn_commit(c_txn); + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; + err = mdbx_txn_abort(c_txn); + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; +#endif /* MDBX_TXN_CHECKOWNER */ + + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); +#if MDBX_TXN_CHECKOWNER + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; +#else + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; +#endif /* MDBX_TXN_CHECKOWNER */ + }); + + s.count_down(); + t.join(); + + return ok; +} + +bool case1(const mdbx::path &path) { + mdbx::env::operate_parameters operateParameters(100, 10); + operateParameters.options.no_sticky_threads = true; + operateParameters.options.nested_write_transactions = true; + mdbx::env_managed env(path, operateParameters); + + //------------------------------------- + auto txn = env.start_write(); + MDBX_txn *c_txn = txn; + int err = mdbx_txn_reset(txn); + assert(err == MDBX_EINVAL); + bool ok = err == MDBX_EINVAL; + + err = mdbx_txn_break(txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + + err = mdbx_txn_commit(txn); + assert(err == MDBX_RESULT_TRUE); + ok = ok && err == MDBX_RESULT_TRUE; + + //------------------------------------- + err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + assert(c_txn == (const MDBX_txn *)txn); + + err = mdbx_txn_break(txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + + err = mdbx_txn_reset(txn); + assert(err == MDBX_EINVAL); + ok = ok && err == MDBX_EINVAL; + + err = mdbx_txn_commit(txn); + assert(err == MDBX_RESULT_TRUE); + ok = ok && err == MDBX_RESULT_TRUE; + + err = mdbx_txn_abort(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + //------------------------------------- + err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + assert(c_txn == (const MDBX_txn *)txn); + txn.commit(); + + err = mdbx_txn_reset(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + err = mdbx_txn_break(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + err = mdbx_txn_abort(c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + + //===================================== + + txn = env.start_read(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + txn.make_broken(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + txn.reset_reading(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_BAD_TXN); + ok = ok && err == MDBX_BAD_TXN; + txn.abort(); + + //------------------------------------- + + txn = env.start_read(); + txn.reset_reading(); + txn.make_broken(); + txn.abort(); + + //===================================== + + std::latch s1(1), s2(1), s3(1); + txn = env.start_read(); + c_txn = txn; + + std::thread t([&]() { + s1.wait(); + err = mdbx_txn_break(c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + err = mdbx_txn_reset(c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + txn.renew_reading(); + s2.count_down(); + + s3.wait(); + err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + err = mdbx_txn_commit(c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + c_txn = txn; + err = mdbx_txn_commit(c_txn); + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; + err = mdbx_txn_abort(c_txn); + assert(err == MDBX_THREAD_MISMATCH); + ok = ok && err == MDBX_THREAD_MISMATCH; + err = mdbx_txn_break(c_txn); + assert(err == MDBX_SUCCESS); + ok = ok && err == MDBX_SUCCESS; + err = mdbx_txn_reset(c_txn); + assert(err == MDBX_EINVAL); + ok = ok && err == MDBX_EINVAL; + }); + + s1.count_down(); + s2.wait(); + txn.commit(); + txn = env.start_write(); + s3.count_down(); + + t.join(); + txn.abort(); + + return ok; +} + +bool case2(const mdbx::path &path, bool no_sticky_threads) { + mdbx::env::operate_parameters operateParameters(100, 10); + operateParameters.options.no_sticky_threads = no_sticky_threads; + mdbx::env_managed env(path, operateParameters); + + std::latch s(1); + std::vector l; + for (size_t n = 0; n < 8; ++n) + l.push_back(std::thread([&]() { + s.wait(); + for (size_t i = 0; i < 1000000; ++i) { + auto txn = env.start_read(); + txn.abort(); + } + })); + + s.count_down(); + for (auto &t : l) + t.join(); + + return true; +} + int main(int argc, const char *argv[]) { (void)argc; (void)argv; - bool ok = true; - int err; mdbx_setup_debug_nofmt(MDBX_LOG_VERBOSE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); mdbx::path path = "test-txn"; mdbx::env::remove(path); - mdbx::env::operate_parameters operateParameters(100, 10); - { - mdbx::env_managed::create_parameters createParameters; - createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, 84 * mdbx::env::geometry::MiB); - - operateParameters.options.no_sticky_threads = false; - mdbx::env_managed env(path, createParameters, operateParameters); - auto txn = env.start_write(false); - /* mdbx::map_handle testHandle = */ txn.create_map("xyz", mdbx::key_mode::usual, mdbx::value_mode::single); - txn.commit(); - - //------------------------------------- - txn = env.start_write(); - MDBX_txn *c_txn = txn; - err = mdbx_txn_reset(txn); - assert(err == MDBX_EINVAL); - ok = ok && err == MDBX_EINVAL; - - err = mdbx_txn_break(txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - - err = mdbx_txn_commit(txn); - assert(err == MDBX_RESULT_TRUE); - ok = ok && err == MDBX_RESULT_TRUE; - - //------------------------------------- - err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - assert(c_txn == (const MDBX_txn *)txn); - - err = mdbx_txn_break(txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - - err = mdbx_txn_reset(txn); - assert(err == MDBX_EINVAL); - ok = ok && err == MDBX_EINVAL; - - err = mdbx_txn_commit(txn); - assert(err == MDBX_RESULT_TRUE); - ok = ok && err == MDBX_RESULT_TRUE; - - err = mdbx_txn_abort(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - //------------------------------------- - err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - assert(c_txn == (const MDBX_txn *)txn); - txn.commit(); - - err = mdbx_txn_reset(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - err = mdbx_txn_break(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - err = mdbx_txn_abort(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - - //===================================== - - txn = env.start_read(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - txn.make_broken(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - txn.reset_reading(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - txn.abort(); - - //------------------------------------- - - txn = env.start_read(); - txn.reset_reading(); - txn.make_broken(); - txn.abort(); - - //===================================== - - std::latch s(1); - txn = env.start_read(); - c_txn = txn; - - std::thread t([&]() { - s.wait(); -#if MDBX_TXN_CHECKOWNER - err = mdbx_txn_reset(c_txn); - assert(err == MDBX_THREAD_MISMATCH); - ok = ok && err == MDBX_THREAD_MISMATCH; - err = mdbx_txn_break(c_txn); - assert(err == MDBX_THREAD_MISMATCH); - ok = ok && err == MDBX_THREAD_MISMATCH; - err = mdbx_txn_commit(c_txn); - assert(err == MDBX_THREAD_MISMATCH); - ok = ok && err == MDBX_THREAD_MISMATCH; - err = mdbx_txn_abort(c_txn); - assert(err == MDBX_THREAD_MISMATCH); - ok = ok && err == MDBX_THREAD_MISMATCH; -#endif /* MDBX_TXN_CHECKOWNER */ - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - }); - - s.count_down(); - t.join(); - } - - //===================================== - //===================================== - - { - operateParameters.options.no_sticky_threads = true; - operateParameters.options.nested_write_transactions = true; - mdbx::env_managed env(path, operateParameters); - - //------------------------------------- - auto txn = env.start_write(); - MDBX_txn *c_txn = txn; - err = mdbx_txn_reset(txn); - assert(err == MDBX_EINVAL); - ok = ok && err == MDBX_EINVAL; - - err = mdbx_txn_break(txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - - err = mdbx_txn_commit(txn); - assert(err == MDBX_RESULT_TRUE); - ok = ok && err == MDBX_RESULT_TRUE; - - //------------------------------------- - err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - assert(c_txn == (const MDBX_txn *)txn); - - err = mdbx_txn_break(txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - - err = mdbx_txn_reset(txn); - assert(err == MDBX_EINVAL); - ok = ok && err == MDBX_EINVAL; - - err = mdbx_txn_commit(txn); - assert(err == MDBX_RESULT_TRUE); - ok = ok && err == MDBX_RESULT_TRUE; - - err = mdbx_txn_abort(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - //------------------------------------- - err = mdbx_txn_begin(env, nullptr, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - assert(c_txn == (const MDBX_txn *)txn); - txn.commit(); - - err = mdbx_txn_reset(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - err = mdbx_txn_break(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - err = mdbx_txn_abort(c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - - //===================================== - - txn = env.start_read(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - txn.make_broken(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - txn.reset_reading(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_BAD_TXN); - ok = ok && err == MDBX_BAD_TXN; - txn.abort(); - - //------------------------------------- - - txn = env.start_read(); - txn.reset_reading(); - txn.make_broken(); - txn.abort(); - - //===================================== - - std::latch s1(1), s2(1), s3(1); - txn = env.start_read(); - c_txn = txn; - - std::thread t([&]() { - s1.wait(); - err = mdbx_txn_break(c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - err = mdbx_txn_reset(c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - txn.renew_reading(); - s2.count_down(); - - s3.wait(); - err = mdbx_txn_begin(env, txn, MDBX_TXN_READWRITE, &c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - err = mdbx_txn_commit(c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - c_txn = txn; - err = mdbx_txn_commit(c_txn); - assert(err == MDBX_THREAD_MISMATCH); - ok = ok && err == MDBX_THREAD_MISMATCH; - err = mdbx_txn_abort(c_txn); - assert(err == MDBX_THREAD_MISMATCH); - ok = ok && err == MDBX_THREAD_MISMATCH; - err = mdbx_txn_break(c_txn); - assert(err == MDBX_SUCCESS); - ok = ok && err == MDBX_SUCCESS; - err = mdbx_txn_reset(c_txn); - assert(err == MDBX_EINVAL); - ok = ok && err == MDBX_EINVAL; - }); - - s1.count_down(); - s2.wait(); - txn.commit(); - txn = env.start_write(); - s3.count_down(); - - t.join(); - txn.abort(); - } + bool ok = case0(path); + ok = case1(path) && ok; + ok = case2(path, false) && ok; + ok = case2(path, true) && ok; std::cout << (ok ? "OK\n" : "FAIL\n"); return ok ? EXIT_SUCCESS : EXIT_FAILURE; From 0a9c9840daa77c7eb0995e9accae7f48bb9587d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:47:56 +0300 Subject: [PATCH 151/181] =?UTF-8?q?mdbx-tests:=20=D1=81=D1=83=D1=89=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B2=D0=B5=D0=BD=D0=BD=D0=BE=D0=B5=20=D1=80=D0=B0?= =?UTF-8?q?=D1=81=D1=88=D0=B8=D1=80=D0=B5=D0=BD=D0=B8=D0=B5=20`extra/curso?= =?UTF-8?q?r-closing`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/cursor_closing.c++ | 341 +++++++++++++++++++++++++++++++--- 1 file changed, 313 insertions(+), 28 deletions(-) diff --git a/test/extra/cursor_closing.c++ b/test/extra/cursor_closing.c++ index 045b7677..60749dbd 100644 --- a/test/extra/cursor_closing.c++ +++ b/test/extra/cursor_closing.c++ @@ -1,6 +1,13 @@ #include "mdbx.h++" +#include +#include #include +#include +#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L +#include +#include +#endif static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg, unsigned length) noexcept { @@ -11,6 +18,304 @@ static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int li static char log_buffer[1024]; +//-------------------------------------------------------------------------------------------- + +bool case0(mdbx::env env) { + auto txn = env.start_write(); + auto table = txn.create_map("case0", mdbx::key_mode::usual, mdbx::value_mode::single); + auto cursor_1 = txn.open_cursor(table); + auto cursor_2 = cursor_1.clone(); + + auto nested = env.start_write(txn); + auto nested_cursor_1 = nested.open_cursor(table); + auto nested_cursor_2 = nested_cursor_1.clone(); + auto nested_cursor_3 = cursor_1.clone(); + + auto deep = env.start_write(nested); + auto deep_cursor_1 = deep.open_cursor(table); + auto deep_cursor_2 = nested_cursor_1.clone(); + auto deep_cursor_3 = cursor_1.clone(); + deep_cursor_1.close(); + deep.commit(); + deep_cursor_2.close(); + + nested_cursor_1.close(); + nested.abort(); + nested_cursor_2.close(); + + cursor_1.close(); + txn.commit(); + cursor_2.close(); + return true; +} + +//-------------------------------------------------------------------------------------------- + +/* Сценарий: + * + * 0. Создаём N таблиц, курсор для каждой таблицы и заполняем (1000 ключей, от 1 до 1000 значений в каждом ключе). + * 1. Запускаем N-1 фоновых потоков и используем текущий/основной. + * 2. В каждом потоке 100500 раз повторяем последовательность действий: + * - 100500 раз запускаем читающую транзакцию и выполняем "читающий цикл": + * - в читающей транзакции создаем 0..3 курсоров, потом подключаем заранее созданный курсор, + * потом еще 0..3 курсоров; + * - выполняем по паре поисков через каждый курсор; + * - отключаем заранее созданный курсор; + * - снова выполняем несколько поисков по каждому курсору; + * - псевдослучайно закрываем один из курсоров и один отключаем; + * - псевдослучайно выполняем один из путей: + * - закрываем все курсоры посредством mdbx_txn_release_all_cursors(); + * - отсоединяем все курсоры посредством mdbx_txn_release_all_cursors(); + * - псевдослучайно закрываем один из курсоров и один отключаем; + * - ничего не делаем; + * - завершаем читающую транзакцию псевдослучайно выбирая между commit и abort; + * - закрываем оставшиеся курсоры. + * 3. Выполняем "пишущий цикл": + * - запускаем пишущую или вложенную транзакцию; + * - из оставшихся с предыдущих итераций курсоров половину закрываем, + * половину подключаем к транзакции; + * - для каждой таблицы с вероятностью 1/2 выполняем "читающий цикл"; + * - для каждой таблицы с вероятностью 1/2 выполняем "модифицирующий" цикл: + * - подключаем курсор, либо создаем при отсутствии подходящих; + * - 100 раз выполняем поиск случайных пар ключ/значение; + * - при успешном поиске удаляем значение, иначе вставляем; + * - с вероятностью 1/2 повторяем "читающий цикл"; + * - с вероятностью 7/16 запускаем вложенную транзакцию: + * - действуем рекурсивно как с пишущей транзакцией; + * - в "читающих циклах" немного меняем поведение: + * - игнорируем ожидаемые ошибки mdbx_cursor_unbind(); + * - в 2-3 раза уменьшаем вероятность использования mdbx_txn_release_all_cursors(); + * - завершаем вложенную транзакцию псевдослучайно выбирая между commit и abort; + * - для каждой таблицы с вероятностью 1/2 выполняем "читающий цикл"; + * - завершаем транзакцию псевдослучайно выбирая между commit и abort; + * 4. Ждем завершения фоновых потоков. + * 5. Закрываем оставшиеся курсоры и закрываем БД. */ + +thread_local size_t salt; + +static size_t prng() { + salt = salt * 134775813 + 1; + return salt ^ ((salt >> 11) * 1822226723); +} + +static inline bool flipcoin() { return prng() & 1; } + +static inline size_t prng(size_t range) { return prng() % range; } + +void case1_shuffle_pool(std::vector &pool) { + for (size_t n = 1; n < pool.size(); ++n) { + const auto i = prng(n); + if (i != n) + std::swap(pool[n], pool[i]); + } +} + +void case1_read_pool(std::vector &pool) { + for (auto c : pool) + if (flipcoin()) + mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(1000)), mdbx::slice::wrap(prng(1000)), false); + for (auto c : pool) + if (flipcoin()) + mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(1000)), mdbx::slice::wrap(prng(1000)), false); +} + +MDBX_cursor *case1_try_unbind(MDBX_cursor *cursor) { + if (cursor) { + auto err = mdbx::error(static_cast(mdbx_cursor_unbind(cursor))); + if (err.code() != MDBX_EINVAL) + err.success_or_throw(); + } + return cursor; +} + +MDBX_cursor *case1_pool_remove(std::vector &pool) { + switch (pool.size()) { + case 0: + return nullptr; + case 1: + if (flipcoin()) { + const auto c = pool[0]; + pool.pop_back(); + return c; + } + return nullptr; + default: + const auto i = prng(pool.size()); + const auto c = pool[i]; + pool.erase(pool.begin() + i); + return c; + } +} + +mdbx::map_handle case1_cycle_dbi(std::deque &dbi) { + const auto h = dbi.front(); + dbi.pop_front(); + dbi.push_back(h); + return h; +} + +void case1_read_cycle(mdbx::txn txn, std::deque &dbi, std::vector &pool, + mdbx::cursor pre, bool nested = false) { + for (auto c : pool) + mdbx::cursor(c).bind(txn, case1_cycle_dbi(dbi)); + pre.bind(txn, case1_cycle_dbi(dbi)); + + for (auto n = prng(3 + dbi.size()); n > 0; --n) { + auto c = txn.open_cursor(dbi[prng(dbi.size())]); + pool.push_back(c.withdraw_handle()); + } + case1_shuffle_pool(pool); + case1_read_pool(pool); + + pool.push_back(pre); + case1_read_pool(pool); + pool.pop_back(); + + for (auto n = prng(3 + dbi.size()); n > 0; --n) { + auto c = txn.open_cursor(dbi[prng(dbi.size())]); + pool.push_back(c.withdraw_handle()); + } + pool.push_back(pre); + case1_read_pool(pool); + pool.pop_back(); + + case1_try_unbind(pre); + case1_shuffle_pool(pool); + case1_read_pool(pool); + + if (flipcoin()) { + mdbx_cursor_close(case1_pool_remove(pool)); + auto u = case1_try_unbind(case1_pool_remove(pool)); + case1_read_pool(pool); + if (u) + pool.push_back(u); + } else { + auto u = case1_try_unbind(case1_pool_remove(pool)); + mdbx_cursor_close(case1_pool_remove(pool)); + case1_read_pool(pool); + if (u) + pool.push_back(u); + } + + switch (prng(nested ? 7 : 3)) { + case 0: + for (auto i = pool.begin(); i != pool.end();) + if (mdbx_cursor_txn(*i)) + i = pool.erase(i); + else + ++i; + txn.close_all_cursors(); + break; + case 1: + txn.unbind_all_cursors(); + break; + } +} + +void case1_write_cycle(mdbx::txn_managed txn, std::deque &dbi, std::vector &pool, + mdbx::cursor pre, bool nested = false) { + if (flipcoin()) + case1_cycle_dbi(dbi); + if (flipcoin()) + case1_shuffle_pool(pool); + + for (auto n = prng(dbi.size() + 1); n > 1; n -= 2) { + if (!nested) + pre.unbind(); + if (!pre.txn()) + pre.bind(txn, dbi[prng(dbi.size())]); + for (auto i = 0; i < 1000; ++i) { + auto k = mdbx::default_buffer::wrap(prng(1000)); + auto v = mdbx::default_buffer::wrap(prng(1000)); + if (pre.find_multivalue(k, v, false)) + pre.erase(); + else + pre.upsert(k, v); + } + } + + if (prng(16) > 8) + case1_write_cycle(txn.start_nested(), dbi, pool, pre, true); + + if (flipcoin()) + txn.commit(); + else + txn.abort(); +} + +bool case1_thread(mdbx::env env, std::deque dbi, mdbx::cursor pre) { + salt = size_t(std::chrono::high_resolution_clock::now().time_since_epoch().count()); + std::vector pool; + for (auto loop = 0; loop < 333; ++loop) { + for (auto read = 0; read < 333; ++read) { + auto txn = env.start_read(); + case1_read_cycle(txn, dbi, pool, pre); + if (flipcoin()) + txn.commit(); + else + txn.abort(); + } + + case1_write_cycle(env.start_write(), dbi, pool, pre); + + for (auto c : pool) + mdbx_cursor_close(c); + pool.clear(); + } + + pre.unbind(); + return true; +} + +bool case1(mdbx::env env) { + bool ok = true; + std::deque dbi; + std::vector cursors; +#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L + static const auto N = 10; +#else + static const auto N = 3; +#endif + for (auto t = 0; t < N; ++t) { + auto txn = env.start_write(); + auto table = txn.create_map(std::to_string(t), mdbx::key_mode::ordinal, mdbx::value_mode::multi_samelength); + auto cursor = txn.open_cursor(table); + for (size_t i = 0; i < 10000; ++i) + cursor.upsert(mdbx::default_buffer::wrap(prng(1000)), mdbx::default_buffer::wrap(prng(1000))); + txn.commit(); + + cursors.push_back(std::move(cursor)); + dbi.push_back(table); + } + +#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L + std::latch s(1); + std::vector threads; + for (auto t = 1; t < N; ++t) { + case1_cycle_dbi(dbi); + threads.push_back(std::thread([&, t]() { + s.wait(); + if (!case1_thread(env, dbi, cursors[t])) + ok = false; + })); + } + case1_cycle_dbi(dbi); + s.count_down(); +#endif + + if (!case1_thread(env, dbi, cursors[0])) + ok = false; + +#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L + for (auto &t : threads) + t.join(); +#endif + + return ok; +} + +//-------------------------------------------------------------------------------------------- + int main(int argc, const char *argv[]) { (void)argc; (void)argv; @@ -23,34 +328,14 @@ int main(int argc, const char *argv[]) { mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters(42, 0, mdbx::env::nested_transactions)); - { - auto txn = env.start_write(); - auto table = txn.create_map("dummy", mdbx::key_mode::usual, mdbx::value_mode::single); - auto cursor_1 = txn.open_cursor(table); - auto cursor_2 = cursor_1.clone(); + bool ok = case0(env); + ok = case1(env) && ok; - auto nested = env.start_write(txn); - auto nested_cursor_1 = nested.open_cursor(table); - auto nested_cursor_2 = nested_cursor_1.clone(); - auto nested_cursor_3 = cursor_1.clone(); - - auto deep = env.start_write(nested); - auto deep_cursor_1 = deep.open_cursor(table); - auto deep_cursor_2 = nested_cursor_1.clone(); - auto deep_cursor_3 = cursor_1.clone(); - deep_cursor_1.close(); - deep.commit(); - deep_cursor_2.close(); - - nested_cursor_1.close(); - nested.abort(); - nested_cursor_2.close(); - - cursor_1.close(); - txn.commit(); - cursor_2.close(); + if (ok) { + std::cout << "OK\n"; + return EXIT_SUCCESS; + } else { + std::cout << "FAIL!\n"; + return EXIT_FAILURE; } - - std::cout << "OK\n"; - return EXIT_SUCCESS; } From 767ba21977535819ddc24ae41a3feaee1e8211dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:48:22 +0300 Subject: [PATCH 152/181] =?UTF-8?q?mdbx:=20=D0=BA=D0=BE=D1=81=D1=82=D1=8B?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=B4=D0=BB=D1=8F=20CLANG=20<=2020=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D0=B8=20`[[=D0=B0=D1=82=D1=80=D0=B8?= =?UTF-8?q?=D0=B1=D1=83=D1=82=D0=BE=D0=B2]]`=20C23=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mdbx.h b/mdbx.h index ae2af5ad..a6cdb7de 100644 --- a/mdbx.h +++ b/mdbx.h @@ -204,7 +204,7 @@ typedef mode_t mdbx_mode_t; #ifndef __has_cpp_attribute #define __has_cpp_attribute(x) 0 #define __has_cpp_attribute_qualified(x) 0 -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) || (__clang__ && __clang__ < 14) /* MSVC don't support `namespace::attr` syntax */ #define __has_cpp_attribute_qualified(x) 0 #else @@ -318,7 +318,7 @@ typedef mode_t mdbx_mode_t; #ifndef MDBX_DEPRECATED #ifdef __deprecated #define MDBX_DEPRECATED __deprecated -#elif defined(DOXYGEN) || ((!defined(__GNUC__) || defined(__clang__) || __GNUC__ > 5) && \ +#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))) @@ -504,7 +504,7 @@ typedef mode_t mdbx_mode_t; #if defined(DOXYGEN) || \ (defined(__cplusplus) && __cplusplus >= 201603L && __has_cpp_attribute(maybe_unused) && \ - __has_cpp_attribute(maybe_unused) >= 201603L) || \ + __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__) From 1dfe1e872e993ff5cf9fa59aa7920cc91c121f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:48:58 +0300 Subject: [PATCH 153/181] =?UTF-8?q?mdbx++:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`mdbx::cursor::seek=5Fmu?= =?UTF-8?q?ltiple=5Fsamelength()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/mdbx.h++ b/mdbx.h++ index 55bfc8e9..ba403bca 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -4265,9 +4265,14 @@ public: batch_samelength = MDBX_GET_MULTIPLE, batch_samelength_next = MDBX_NEXT_MULTIPLE, - batch_samelength_previous = MDBX_PREV_MULTIPLE + batch_samelength_previous = MDBX_PREV_MULTIPLE, + seek_and_batch_samelength = MDBX_SEEK_AND_GET_MULTIPLE }; + // TODO: добавить легковесный proxy-класс для замещения параметра throw_notfound более сложным набором опций, + // в том числе с explicit-конструктором из bool, чтобы защититься от неявной конвертации ключей поиска + // и других параметров в bool-throw_notfound. + struct move_result : public pair_result { inline move_result(const cursor &cursor, bool throw_notfound); move_result(cursor &cursor, move_operation operation, bool throw_notfound) @@ -4465,8 +4470,8 @@ public: inline move_result lower_bound_multivalue(const slice &key, const slice &value, bool throw_notfound = false); inline move_result upper_bound_multivalue(const slice &key, const slice &value, bool throw_notfound = false); - inline move_result get_multiple_samelength(const slice &key, bool throw_notfound = true) { - return move(batch_samelength, key, throw_notfound); + inline move_result seek_multiple_samelength(const slice &key, bool throw_notfound = true) { + return move(seek_and_batch_samelength, key, throw_notfound); } inline move_result get_multiple_samelength(bool throw_notfound = false) { From 529f2c23809014fdf1fca590afb20f2a2913c230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:49:17 +0300 Subject: [PATCH 154/181] =?UTF-8?q?mdbx-tests:=20=D1=83=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=8C=D1=88=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BB-?= =?UTF-8?q?=D0=B2=D0=B0=20=D0=B8=D1=82=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B9?= =?UTF-8?q?=20=D0=B2=20extra/crunched-delete=20=D0=B4=D0=BB=D1=8F=2032-?= =?UTF-8?q?=D0=B1=D0=B8=D1=82=D0=BD=D1=8B=D1=85=20=D1=81=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=B2=D0=BE=20=D0=B8=D0=B7=D0=B1=D0=B5=D0=B6?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F=20`MDBX=5FMAP=5FFULL`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/crunched_delete.c++ | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/extra/crunched_delete.c++ b/test/extra/crunched_delete.c++ index 5655fd8a..134dbafe 100644 --- a/test/extra/crunched_delete.c++ +++ b/test/extra/crunched_delete.c++ @@ -7,8 +7,10 @@ #if MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) #define NN 1024 -#else +#elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul #define NN 4096 +#else +#define NN 2048 #endif std::string format_va(const char *fmt, va_list ap) { From 3282adf8bd53811b198ef09633b58f87fdbcc4e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:49:42 +0300 Subject: [PATCH 155/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B5=D0=B3=D1=80?= =?UTF-8?q?=D0=B5=D1=81=D1=81=D0=B0=20=D0=B2=20=D0=BF=D1=83=D1=82=D0=B8=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8=20`MDBX?= =?UTF-8?q?=5FMULTIPLE`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Пакетная вставка значений посредством операции `MDBX_MULTIPLE` могла приводить к падениям и повреждению структуры БД. Ошибка оставалось не замеченной из-за специфических условий проявления, которые не реализовались в тестах. Проблема присутствовала во всех выпусках начиная с v0.13.1, но соответствующая ошибка не связана с конкретным коммита в истории, а является следствием нескольких доработок (шагов рефакторинга), которые суммарно привели к регрессу. Технически ошибка обусловлена не-обнулением переменной, которая не обнулялась в некотором пути выполнения и исходно не требовала обнуления, но такое обнуление потребовалось после ряда этапов оптимизации кода и рефакторинга. Основным условием проявления является пакетная вставка multi-значений в dupsort-таблицу с фиксированным размером значений, при котором набор значений соответствующий обновляемом ключу, перестаёт помещаться на вложенной странице и преобразуется/выносится во вложенное дерево страниц. Если такой вынос/преобразование происходило до исчерпания переданного набора значений, то при следующей итерации повторно производились действия соответствующие выносу данных в отдельное дерево страниц. Что могла приводить как к разыменованию неверных указателей (повреждению содержимого памяти) и/или к повреждению содержимого страниц образующих структуру БД. Исправление свелось к добавлению одной строчки кода, но также были расширены тесты для покрытия соответствующих сценариев. --- src/cursor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cursor.c b/src/cursor.c index b313a78f..036ab123 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -1408,6 +1408,7 @@ insert_node:; data[0].iov_base = ptr_disp(data[0].iov_base, data[0].iov_len); insert_key = insert_data = false; old_singledup.iov_base = nullptr; + sub_root = nullptr; goto more; } } From 52a19feccaf11dc39f1770f8ae6984f66a5fad15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:50:27 +0300 Subject: [PATCH 156/181] =?UTF-8?q?mdbx++:=20=D1=8F=D0=B2=D0=BD=D0=BE?= =?UTF-8?q?=D0=B5=20=D0=BE=D0=BF=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20external-=D0=B8=D0=BD=D1=81=D1=82=D0=B0=D0=BD?= =?UTF-8?q?=D1=86=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20`mdbx:?= =?UTF-8?q?:buffer<>`=20c=20API-=D0=B0=D1=82=D1=80=D0=B8=D0=B1=D1=83=D1=82?= =?UTF-8?q?=D0=B0=D0=BC=D0=B8=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 23 +++++++++++++++++++++-- src/mdbx.c++ | 24 ++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/mdbx.h++ b/mdbx.h++ index ba403bca..6426f3fa 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -107,6 +107,16 @@ #include #endif +#if !defined(_MSC_VER) || defined(__clang__) +/* adequate compilers */ +#define MDBX_EXTERN_API_TEMPLATE(API_ATTRIBUTES, API_TYPENAME) extern template class API_ATTRIBUTES API_TYPENAME +#define MDBX_INSTALL_API_TEMPLATE(API_ATTRIBUTES, API_TYPENAME) template class API_TYPENAME +#else +/* stupid microsoft showing off */ +#define MDBX_EXTERN_API_TEMPLATE(API_ATTRIBUTES, API_TYPENAME) extern template class API_TYPENAME +#define MDBX_INSTALL_API_TEMPLATE(API_ATTRIBUTES, API_TYPENAME) template class API_ATTRIBUTES API_TYPENAME +#endif + #if __cplusplus >= 201103L #include #include @@ -1500,8 +1510,7 @@ public: private: friend class txn; - struct silo; - using swap_alloc = allocation_aware_details::swap_alloc; + using swap_alloc = allocation_aware_details::swap_alloc; struct silo /* Empty Base Class Optimization */ : public allocator_type { MDBX_CXX20_CONSTEXPR const allocator_type &get_allocator() const noexcept { return *this; } MDBX_CXX20_CONSTEXPR allocator_type &get_allocator() noexcept { return *this; } @@ -2729,6 +2738,12 @@ inline string make_string(const PRODUCER &producer, const ALLOCATOR & return result; } +MDBX_EXTERN_API_TEMPLATE(LIBMDBX_API_TYPE, buffer); + +#if defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L && _GLIBCXX_USE_CXX11_ABI +MDBX_EXTERN_API_TEMPLATE(LIBMDBX_API_TYPE, buffer); +#endif /* __cpp_lib_memory_resource >= 201603L */ + /// \brief Combines data slice with boolean flag to represent result of certain /// operations. struct value_result { @@ -2854,9 +2869,13 @@ template struct buffer_pair_spec operator pair() const noexcept { return pair(key, value); } }; +/// \brief Combines pair of buffers for key and value to hold an operands for certain operations. template using buffer_pair = buffer_pair_spec; +/// \brief Default pair of buffers. +using default_buffer_pair = buffer_pair; + /// end of cxx_data @} //------------------------------------------------------------------------------ diff --git a/src/mdbx.c++ b/src/mdbx.c++ index 7b4d8aa1..565c79e9 100644 --- a/src/mdbx.c++ +++ b/src/mdbx.c++ @@ -1162,12 +1162,32 @@ bool from_base64::is_erroneous() const noexcept { //------------------------------------------------------------------------------ -template class LIBMDBX_API_TYPE buffer; +#if defined(_MSC_VER) +#pragma warning(push) +/* warning C4251: 'mdbx::buffer<...>::silo_': + * struct 'mdbx::buffer<..>::silo' needs to have dll-interface to be used by clients of class 'mdbx::buffer<...>' + * + * Microsoft не хочет признавать ошибки и пересматривать приятные решения, поэтому MSVC продолжает кошмарить + * и стращать разработчиков предупреждениями, тем самым перекладывая ответственность на их плечи. + * + * В данном случае предупреждение выдаётся из-за инстанцирования std::string::allocator_type::pointer и + * std::pmr::string::allocator_type::pointer внутри mdbx::buffer<..>::silo. А так как эти типы являются частью + * стандартной библиотеки C++ они всегда будут доступны и без необходимости их инстанцирования и экспорта из libmdbx. + * + * Поэтому нет других вариантов как заглушить это предупреждение и еще раз плюнуть в сторону microsoft. */ +#pragma warning(disable : 4251) +#endif /* MSVC */ + +MDBX_INSTALL_API_TEMPLATE(LIBMDBX_API_TYPE, buffer); #if defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L && _GLIBCXX_USE_CXX11_ABI -template class LIBMDBX_API_TYPE buffer; +MDBX_INSTALL_API_TEMPLATE(LIBMDBX_API_TYPE, buffer); #endif /* __cpp_lib_memory_resource >= 201603L */ +#if defined(_MSC_VER) +#pragma warning(pop) +#endif /* MSVC */ + //------------------------------------------------------------------------------ static inline MDBX_env_flags_t mode2flags(env::mode mode) { From 7ed769e9c6d12d643816424b5d576f8bdb2239de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:51:37 +0300 Subject: [PATCH 157/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B6=D0=BA=D0=B0=20`MDBX=5FMULTIPLE`=20=D1=81=20=D0=BD?= =?UTF-8?q?=D1=83=D0=BB=D0=B5=D0=B2=D1=8B=D0=BC=20=D1=80=D0=B0=D0=B7=D0=BC?= =?UTF-8?q?=D0=B5=D1=80=D0=BE=D0=BC=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= =?UTF-8?q?=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cursor.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/cursor.c b/src/cursor.c index 036ab123..632aecc7 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -731,8 +731,17 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig if (mc->clc->k.cmp(key, ¤t_key) != 0) return MDBX_EKEYMISMATCH; - if (unlikely((flags & MDBX_MULTIPLE))) - goto drop_current; + if (unlikely((flags & MDBX_MULTIPLE))) { + if (unlikely(!mc->subcur)) + return MDBX_EINVAL; + err = cursor_del(mc, flags & MDBX_ALLDUPS); + if (unlikely(err != MDBX_SUCCESS)) + return err; + if (unlikely(data[1].iov_len == 0)) + return MDBX_SUCCESS; + flags -= MDBX_CURRENT; + goto skip_check_samedata; + } if (mc->subcur) { node_t *node = page_node(mc->pg[mc->top], mc->ki[mc->top]); @@ -742,7 +751,6 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig * отличается, то вместо обновления требуется удаление и * последующая вставка. */ if (mc->subcur->nested_tree.items > 1 || current_data.iov_len != data->iov_len) { - drop_current: err = cursor_del(mc, flags & MDBX_ALLDUPS); if (unlikely(err != MDBX_SUCCESS)) return err; @@ -847,6 +855,8 @@ __hot int cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsig size_t *batch_dupfix_done = nullptr, batch_dupfix_given = 0; if (unlikely(flags & MDBX_MULTIPLE)) { batch_dupfix_given = data[1].iov_len; + if (unlikely(data[1].iov_len == 0)) + return /* nothing todo */ MDBX_SUCCESS; batch_dupfix_done = &data[1].iov_len; *batch_dupfix_done = 0; } From 9653c8f45bb0dba18ac73c9d8052cafdcc8701e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:52:21 +0300 Subject: [PATCH 158/181] =?UTF-8?q?mdbx:=20=D1=80=D0=B5=D1=84=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BE=D0=BA=20=D1=81=20=D0=B2=D1=8B=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D0=BE=D0=BC=20=D0=B2=20`cursor=5Fcheck=5Fmultiple()`=20(?= =?UTF-8?q?backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api-cursor.c | 18 +++--------------- src/api-txn-data.c | 13 +++++++++++++ src/cursor.c | 15 +++++++++++++++ src/cursor.h | 3 +++ 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/api-cursor.c b/src/api-cursor.c index f5f09c20..ef905024 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -711,22 +711,10 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, MDBX_p if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - /* Check this first so counter will always be zero on any early failures. */ if (unlikely(flags & MDBX_MULTIPLE)) { - if (unlikely(flags & MDBX_RESERVE)) - return LOG_IFERR(MDBX_EINVAL); - if (unlikely(!(mc->tree->flags & MDBX_DUPFIXED))) - return LOG_IFERR(MDBX_INCOMPATIBLE); - const size_t dcount = data[1].iov_len; - if (unlikely(dcount < 2 || data->iov_len == 0)) - return LOG_IFERR(MDBX_BAD_VALSIZE); - if (unlikely(mc->tree->dupfix_size != data->iov_len) && mc->tree->dupfix_size) - return LOG_IFERR(MDBX_BAD_VALSIZE); - if (unlikely(dcount > MAX_MAPSIZE / 2 / (BRANCH_NODE_MAX(MDBX_MAX_PAGESIZE) - NODESIZE))) { - /* checking for multiplication overflow */ - if (unlikely(dcount > MAX_MAPSIZE / 2 / data->iov_len)) - return LOG_IFERR(MDBX_TOO_LARGE); - } + rc = cursor_check_multiple(mc, key, data, flags); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); } if (flags & MDBX_RESERVE) { diff --git a/src/api-txn-data.c b/src/api-txn-data.c index 2be54df8..cc0891cb 100644 --- a/src/api-txn-data.c +++ b/src/api-txn-data.c @@ -266,6 +266,19 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, M rc = cursor_init(&cx.outer, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); + + if (unlikely(flags & MDBX_MULTIPLE)) { + rc = cursor_check_multiple(&cx.outer, key, data, flags); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + } + + if (flags & MDBX_RESERVE) { + if (unlikely(cx.outer.tree->flags & (MDBX_DUPSORT | MDBX_REVERSEDUP | MDBX_INTEGERDUP | MDBX_DUPFIXED))) + return LOG_IFERR(MDBX_INCOMPATIBLE); + data->iov_base = nullptr; + } + cx.outer.next = txn->cursors[dbi]; txn->cursors[dbi] = &cx.outer; diff --git a/src/cursor.c b/src/cursor.c index 632aecc7..be82940f 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -1438,6 +1438,21 @@ insert_node:; return rc; } +int cursor_check_multiple(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsigned flags) { + (void)key; + if (unlikely(flags & MDBX_RESERVE)) + return MDBX_EINVAL; + if (unlikely(!(mc->tree->flags & MDBX_DUPFIXED))) + return MDBX_INCOMPATIBLE; + const size_t number = data[1].iov_len; + if (unlikely(number > MAX_MAPSIZE / 2 / (BRANCH_NODE_MAX(MDBX_MAX_PAGESIZE) - NODESIZE))) { + /* checking for multiplication overflow */ + if (unlikely(number > MAX_MAPSIZE / 2 / data->iov_len)) + return MDBX_TOO_LARGE; + } + return MDBX_SUCCESS; +} + __hot int cursor_put_checklen(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsigned flags) { cASSERT(mc, (mc->flags & z_inner) == 0); if (unlikely(key->iov_len > mc->clc->k.lmax || key->iov_len < mc->clc->k.lmin)) { diff --git a/src/cursor.h b/src/cursor.h index 7f109bcc..cf5c8548 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -315,6 +315,9 @@ MDBX_INTERNAL MDBX_cursor *cursor_cpstk(const MDBX_cursor *csrc, MDBX_cursor *cd MDBX_INTERNAL int __must_check_result cursor_ops(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, const MDBX_cursor_op op); +MDBX_INTERNAL int __must_check_result cursor_check_multiple(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, + unsigned flags); + MDBX_INTERNAL int __must_check_result cursor_put_checklen(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsigned flags); From 065aef35eac679e7e95b7485b4597166294317f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:55:10 +0300 Subject: [PATCH 159/181] =?UTF-8?q?mdbx++:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`mdbx::cursor::put=5Fmul?= =?UTF-8?q?tiple=5Fsamelength()`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h++ | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/mdbx.h++ b/mdbx.h++ index 6426f3fa..ff4d0dba 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -4100,8 +4100,9 @@ public: return append(map, kv.key, kv.value, multivalue_order_preserved); } - size_t put_multiple_samelength(map_handle map, const slice &key, const size_t value_length, const void *values_array, - size_t values_count, put_mode mode, bool allow_partial = false); + inline size_t put_multiple_samelength(map_handle map, const slice &key, const size_t value_length, + const void *values_array, size_t values_count, put_mode mode, + bool allow_partial = false); template size_t put_multiple_samelength(map_handle map, const slice &key, const VALUE *values_array, size_t values_count, put_mode mode, bool allow_partial = false) { @@ -4567,6 +4568,21 @@ public: /// \brief Seeks and removes the particular multi-value entry of the key. /// \return `True` if the given key-value pair is found and removed. inline bool erase(const slice &key, const slice &value); + + inline size_t put_multiple_samelength(const slice &key, const size_t value_length, const void *values_array, + size_t values_count, put_mode mode, bool allow_partial = false); + template + size_t put_multiple_samelength(const slice &key, const VALUE *values_array, size_t values_count, put_mode mode, + bool allow_partial = false) { + static_assert(::std::is_standard_layout::value && !::std::is_pointer::value && + !::std::is_array::value, + "Must be a standard layout type!"); + return put_multiple_samelength(key, sizeof(VALUE), values_array, values_count, mode, allow_partial); + } + template + void put_multiple_samelength(const slice &key, const ::std::vector &vector, put_mode mode) { + put_multiple_samelength(key, vector.data(), vector.size(), mode); + } }; /// \brief Managed cursor. @@ -6354,6 +6370,24 @@ inline bool cursor::erase(const slice &key, const slice &value) { return data.done && erase(); } +inline size_t cursor::put_multiple_samelength(const slice &key, const size_t value_length, const void *values_array, + size_t values_count, put_mode mode, bool allow_partial) { + MDBX_val args[2] = {{const_cast(values_array), value_length}, {nullptr, values_count}}; + const int err = ::mdbx_cursor_put(handle_, const_cast(&key), args, MDBX_put_flags_t(mode) | MDBX_MULTIPLE); + switch (err) { + case MDBX_SUCCESS: + MDBX_CXX20_LIKELY break; + case MDBX_KEYEXIST: + if (allow_partial) + break; + mdbx_txn_break(txn()); + MDBX_CXX17_FALLTHROUGH /* fallthrough */; + default: + MDBX_CXX20_UNLIKELY error::throw_exception(err); + } + return args[1].iov_len /* done item count */; +} + /// end cxx_api @} } // namespace mdbx From 2127d3b7d725349560b1bcea9f5e7da6848a7204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:55:41 +0300 Subject: [PATCH 160/181] =?UTF-8?q?mdbx-tests:=20=D1=80=D0=B0=D1=81=D1=88?= =?UTF-8?q?=D0=B8=D1=80=D0=B5=D0=BD=D0=B8=D0=B5=20extra/dupfix-multiple=20?= =?UTF-8?q?(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/dupfix_multiple.c++ | 168 ++++++++++++++++++++++----------- 1 file changed, 111 insertions(+), 57 deletions(-) diff --git a/test/extra/dupfix_multiple.c++ b/test/extra/dupfix_multiple.c++ index a212984b..ecc02bc7 100644 --- a/test/extra/dupfix_multiple.c++ +++ b/test/extra/dupfix_multiple.c++ @@ -2,15 +2,12 @@ /// \copyright SPDX-License-Identifier: Apache-2.0 #include "mdbx.h++" -#include +#include #include -int doit() { - mdbx::path db_filename = "test-dupfix-multiple"; - mdbx::env_managed::remove(db_filename); - mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters()); +using buffer = mdbx::default_buffer; - using buffer = mdbx::buffer; +bool case1_ordering(mdbx::env env) { auto txn = env.start_write(); auto map = txn.create_map(nullptr, mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal); @@ -30,10 +27,9 @@ int doit() { cursor.to_next().value.as_uint64() != 17 || cursor.to_next().value.as_uint64() != 16 || cursor.to_next().value.as_uint64() != 15 || cursor.to_next().value.as_uint64() != 14 || cursor.to_next().value.as_uint64() != 13 || cursor.to_next().value.as_uint64() != 12 || - cursor.to_next(false).done || !cursor.eof()) { - std::cerr << "Fail\n"; - return EXIT_FAILURE; - } + cursor.to_next(false).done || !cursor.eof()) + return false; + txn.abort(); const uint64_t array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 42, 17, 99, 0, 33, 333}; @@ -87,10 +83,9 @@ int doit() { /* key = 24 */ cursor.to_next().value.as_uint64() != 15 || /* key = 25 */ cursor.to_next().value.as_uint64() != 14 || /* key = 26 */ cursor.to_next().value.as_uint64() != 13 || - /* key = 27 */ cursor.to_next().value.as_uint64() != 12 || cursor.to_next(false).done || !cursor.eof()) { - std::cerr << "Fail\n"; - return EXIT_FAILURE; - } + /* key = 27 */ cursor.to_next().value.as_uint64() != 12 || cursor.to_next(false).done || !cursor.eof()) + return false; + txn.abort(); txn = env.start_write(); @@ -163,40 +158,24 @@ int doit() { cursor.to_next().value.as_uint64() != 0 || cursor.to_next().value.as_uint64() != 33 || cursor.to_next().value.as_uint64() != 333 || - cursor.to_next(false).done || !cursor.eof()) { - std::cerr << "Fail\n"; - return EXIT_FAILURE; - } + cursor.to_next(false).done || !cursor.eof()) + return false; + txn.abort(); - //---------------------------------------------------------------------------- - - // let dir = tempdir().unwrap(); - // let db = Database::open(&dir).unwrap(); - - // let txn = db.begin_rw_txn().unwrap(); - // let table = txn - // .create_table(None, TableFlags::DUP_SORT | TableFlags::DUP_FIXED) - // .unwrap(); - // for (k, v) in [ - // (b"key1", b"val1"), - // (b"key1", b"val2"), - // (b"key1", b"val3"), - // (b"key2", b"val1"), - // (b"key2", b"val2"), - // (b"key2", b"val3"), - // ] { - // txn.put(&table, k, v, WriteFlags::empty()).unwrap(); - // } - - // let mut cursor = txn.cursor(&table).unwrap(); - // assert_eq!(cursor.first().unwrap(), Some((*b"key1", *b"val1"))); - // assert_eq!(cursor.get_multiple().unwrap(), Some(*b"val1val2val3")); - // assert_eq!(cursor.next_multiple::<(), ()>().unwrap(), None); - txn = env.start_write(); txn.clear_map(map); - map = txn.create_map(nullptr, mdbx::key_mode::usual, mdbx::value_mode::multi_samelength); + txn.commit(); + + return true; +} + +//-------------------------------------------------------------------------------------------- + +bool case2_batch_read(mdbx::env env) { + + auto txn = env.start_write(); + auto map = txn.create_map(nullptr, mdbx::key_mode::usual, mdbx::value_mode::multi_samelength); txn.upsert(map, mdbx::slice("key1"), mdbx::slice("val1")); txn.upsert(map, mdbx::pair("key1", "val2")); txn.upsert(map, mdbx::pair("key1", "val3")); @@ -205,30 +184,105 @@ int doit() { txn.upsert(map, mdbx::pair("key2", "val3")); // cursor.close(); - cursor = txn.open_cursor(map); + auto cursor = txn.open_cursor(map); const auto t1 = cursor.to_first(); if (!t1 || t1.key != "key1" || t1.value != "val1") { std::cerr << "Fail-t1\n"; - return EXIT_FAILURE; + return false; } const auto t2 = cursor.get_multiple_samelength(); if (!t2 || t2.key != "key1" || t2.value != "val1val2val3") { std::cerr << "Fail-t2\n"; - return EXIT_FAILURE; + return false; } - // const auto t3 = cursor.get_multiple_samelength("key2"); - // if (!t3 || t3.key != "key2" || t3.value != "val1val2val3") { - // std::cerr << "Fail-t3\n"; - // return EXIT_FAILURE; - // } - const auto t4 = cursor.next_multiple_samelength(); - if (t4) { + const auto t3 = cursor.next_multiple_samelength(); + if (t3) { + std::cerr << "Fail-t3\n"; + return false; + } + const auto t4 = cursor.seek_multiple_samelength("key2"); + if (!t4 || t4.key != "key2" || t4.value != "val1val2val3") { std::cerr << "Fail-t4\n"; - return EXIT_FAILURE; + return false; } - std::cout << "OK\n"; - return EXIT_SUCCESS; + txn.clear_map(map); + txn.commit(); + + return true; +} + +//-------------------------------------------------------------------------------------------- + +size_t salt; + +static size_t prng() { + salt = salt * 134775813 + 1; + return salt ^ ((salt >> 11) * 1822226723); +} + +static inline size_t prng(size_t range) { return prng() % range; } + +static mdbx::default_buffer_pair prng_kv(size_t n, size_t space) { + space = (space + !space) * 1024 * 32; + const size_t w = (n ^ 1455614549) * 1664525 + 1013904223; + const size_t k = (prng(42 + w % space) ^ 1725278851) * 433750991; + const size_t v = prng(); + return mdbx::default_buffer_pair(mdbx::slice::wrap(k), mdbx::slice::wrap(v)); +} + +bool case3_put_a_lot(mdbx::env env) { + salt = size_t(std::chrono::high_resolution_clock::now().time_since_epoch().count()); + auto txn = env.start_write(); + auto map = txn.create_map("case3", mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal); + for (size_t n = 0; n < 5555555; ++n) + txn.upsert(map, prng_kv(n, 1)); + txn.commit(); + + for (size_t t = 0; t < 555; ++t) { + txn = env.start_write(); + auto cursor = txn.open_cursor(map); + for (size_t n = 0; n < 111; ++n) { + auto v = std::vector(); + const auto r = 1 + prng(3); + if (r & 1) { + const auto k = prng_kv(n + t, 2).key; + for (size_t i = prng(42 + prng(111) * prng(111)); i > 0; --i) + v.push_back(prng()); + txn.put_multiple_samelength(map, k, v, mdbx::upsert); + } + if (r & 2) { + const auto k = prng_kv(n + t, 2).key; + if (cursor.seek(k)) { + v.clear(); + for (size_t i = prng(42 + prng(111) * prng(111)); i > 0; --i) + v.push_back(prng()); + cursor.put_multiple_samelength(k, v, mdbx::upsert); + } + } + } + txn.commit(); + } + + return true; +} + +int doit() { + mdbx::path db_filename = "test-dupfix-multiple"; + mdbx::env_managed::remove(db_filename); + mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters(1)); + + bool ok = case1_ordering(env); + ok = case2_batch_read(env) && ok; + ok = case3_put_a_lot(env) && ok; + + if (ok) { + std::cout << "OK\n"; + return EXIT_SUCCESS; + } else { + std::cerr << "Fail\n"; + return EXIT_FAILURE; + } } int main(int argc, const char *argv[]) { From 59343d9106ec257d8ecf1ff44b7819d0c36c1d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:56:07 +0300 Subject: [PATCH 161/181] mdbx++: minor reflow Doxygen comments (backport). --- mdbx.h++ | 205 ++++++++++++++++++------------------------------------- 1 file changed, 68 insertions(+), 137 deletions(-) diff --git a/mdbx.h++ b/mdbx.h++ index ff4d0dba..2d5f62b1 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -158,8 +158,7 @@ #endif #endif /* Byte Order */ -/** Workaround for old compilers without properly support for `C++17 constexpr`. - */ +/** Workaround for old compilers without properly support for `C++17 constexpr` */ #if defined(DOXYGEN) #define MDBX_CXX17_CONSTEXPR constexpr #elif defined(__cpp_constexpr) && __cpp_constexpr >= 201603L && \ @@ -170,8 +169,7 @@ #define MDBX_CXX17_CONSTEXPR inline #endif /* MDBX_CXX17_CONSTEXPR */ -/** Workaround for old compilers without properly support for C++20 `constexpr`. - */ +/** Workaround for old compilers without properly support for C++20 `constexpr`. */ #if defined(DOXYGEN) #define MDBX_CXX20_CONSTEXPR constexpr #elif defined(__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L && \ @@ -195,8 +193,7 @@ #define MDBX_CXX20_CONSTEXPR_ENUM inline #endif /* CONSTEXPR_ENUM_FLAGS_OPERATIONS */ -/** Workaround for old compilers without support assertion inside `constexpr` - * functions. */ +/** Workaround for old compilers without support assertion inside `constexpr` functions. */ #if defined(CONSTEXPR_ASSERT) #define MDBX_CONSTEXPR_ASSERT(expr) CONSTEXPR_ASSERT(expr) #elif defined NDEBUG @@ -221,8 +218,7 @@ #endif #endif /* MDBX_UNLIKELY */ -/** Workaround for old compilers without properly support for C++20 `if - * constexpr`. */ +/** Workaround for old compilers without properly support for C++20 `if constexpr`. */ #if defined(DOXYGEN) #define MDBX_IF_CONSTEXPR constexpr #elif defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L @@ -398,8 +394,7 @@ namespace filesystem = ::std::experimental::filesystem; namespace filesystem = ::std::filesystem; /// \brief Defined if `mdbx::filesystem::path` is available. /// \details If defined, it is always `mdbx::filesystem::path`, -/// which in turn can be refs to `std::filesystem::path` -/// or `std::experimental::filesystem::path`. +/// which in turn can be refs to `std::filesystem::path` or `std::experimental::filesystem::path`. /// Nonetheless `MDBX_STD_FILESYSTEM_PATH` not defined if the `::mdbx::path` /// is fallbacked to c `std::string` or `std::wstring`. #define MDBX_STD_FILESYSTEM_PATH ::mdbx::filesystem::path @@ -499,9 +494,7 @@ public: static inline void success_or_panic(int error_code, const char *context_where, const char *func_who) noexcept; }; -/// \brief Base class for all libmdbx's exceptions that are corresponds -/// to libmdbx errors. -/// +/// \brief Base class for all libmdbx's exceptions that are corresponds to libmdbx errors. /// \see MDBX_error_t class LIBMDBX_API_TYPE exception : public ::std::runtime_error { using base = ::std::runtime_error; @@ -517,8 +510,7 @@ public: const ::mdbx::error error() const noexcept { return error_; } }; -/// \brief Fatal exception that lead termination anyway -/// in dangerous unrecoverable cases. +/// \brief Fatal exception that lead termination anyway in dangerous unrecoverable cases. class LIBMDBX_API_TYPE fatal : public exception { using base = exception; @@ -654,8 +646,7 @@ struct LIBMDBX_API_TYPE slice : public ::MDBX_val { /// \brief Create an empty slice. MDBX_CXX11_CONSTEXPR slice() noexcept; - /// \brief Create a slice that refers to [0,bytes-1] of memory bytes pointed - /// by ptr. + /// \brief Create a slice that refers to [0,bytes-1] of memory bytes pointed by ptr. MDBX_CXX14_CONSTEXPR slice(const void *ptr, size_t bytes); /// \brief Create a slice that refers to [begin,end] of memory bytes. @@ -1010,8 +1001,7 @@ struct LIBMDBX_API_TYPE slice : public ::MDBX_val { /// \brief Checks the slice is not refers to null address or has zero length. MDBX_CXX11_CONSTEXPR bool is_valid() const noexcept { return !(iov_base == nullptr && iov_len != 0); } - /// \brief Build an invalid slice which non-zero length and refers to null - /// address. + /// \brief Build an invalid slice which non-zero length and refers to null address. MDBX_CXX14_CONSTEXPR static slice invalid() noexcept { return slice(size_t(-1)); } template MDBX_CXX14_CONSTEXPR POD as_pod() const { @@ -1239,8 +1229,7 @@ struct LIBMDBX_API to_hex { char *write_bytes(char *dest, size_t dest_size) const; /// \brief Output hexadecimal dump of passed slice to the std::ostream. - /// \throws std::ios_base::failure corresponding to std::ostream::write() - /// behaviour. + /// \throws std::ios_base::failure corresponding to std::ostream::write() behaviour. ::std::ostream &output(::std::ostream &out) const; /// \brief Checks whether a passed slice is empty, @@ -1283,23 +1272,18 @@ struct LIBMDBX_API to_base58 { return wrap_width ? bytes + bytes / wrap_width : bytes; } - /// \brief Fills the buffer by [Base58](https://en.wikipedia.org/wiki/Base58) - /// dump of passed slice. + /// \brief Fills the buffer by [Base58](https://en.wikipedia.org/wiki/Base58) dump of passed slice. /// \throws std::length_error if given buffer is too small. char *write_bytes(char *dest, size_t dest_size) const; - /// \brief Output [Base58](https://en.wikipedia.org/wiki/Base58) - /// dump of passed slice to the std::ostream. - /// \throws std::ios_base::failure corresponding to std::ostream::write() - /// behaviour. + /// \brief Output [Base58](https://en.wikipedia.org/wiki/Base58) dump of passed slice to the std::ostream. + /// \throws std::ios_base::failure corresponding to std::ostream::write() behaviour. ::std::ostream &output(::std::ostream &out) const; - /// \brief Checks whether a passed slice is empty, - /// and therefore there will be no output bytes. + /// \brief Checks whether a passed slice is empty, and therefore there will be no output bytes. bool is_empty() const noexcept { return source.empty(); } - /// \brief Checks whether the content of a passed slice is a valid data - /// and could be encoded or unexpectedly not. + /// \brief Checks whether the content of a passed slice is a valid data and could be encoded or unexpectedly not. bool is_erroneous() const noexcept { return false; } }; @@ -1341,8 +1325,7 @@ struct LIBMDBX_API to_base64 { /// \brief Output [Base64](https://en.wikipedia.org/wiki/Base64) /// dump of passed slice to the std::ostream. - /// \throws std::ios_base::failure corresponding to std::ostream::write() - /// behaviour. + /// \throws std::ios_base::failure corresponding to std::ostream::write() behaviour. ::std::ostream &output(::std::ostream &out) const; /// \brief Checks whether a passed slice is empty, @@ -1383,13 +1366,11 @@ struct LIBMDBX_API from_hex { /// hexadecimal dump from a passed slice to decoded data. MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept { return source.length() >> 1; } - /// \brief Fills the destination with data decoded from hexadecimal dump - /// from a passed slice. + /// \brief Fills the destination with data decoded from hexadecimal dump from a passed slice. /// \throws std::length_error if given buffer is too small. char *write_bytes(char *dest, size_t dest_size) const; - /// \brief Checks whether a passed slice is empty, - /// and therefore there will be no output bytes. + /// \brief Checks whether a passed slice is empty, and therefore there will be no output bytes. bool is_empty() const noexcept { return source.empty(); } /// \brief Checks whether the content of a passed slice is a valid hexadecimal @@ -1422,8 +1403,7 @@ struct LIBMDBX_API from_base58 { } /// \brief Returns the number of bytes needed for conversion - /// [Base58](https://en.wikipedia.org/wiki/Base58) dump from a passed slice to - /// decoded data. + /// [Base58](https://en.wikipedia.org/wiki/Base58) dump from a passed slice to decoded data. MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept { return source.length() /* могут быть все нули кодируемые один-к-одному */; } @@ -1433,13 +1413,11 @@ struct LIBMDBX_API from_base58 { /// \throws std::length_error if given buffer is too small. char *write_bytes(char *dest, size_t dest_size) const; - /// \brief Checks whether a passed slice is empty, - /// and therefore there will be no output bytes. + /// \brief Checks whether a passed slice is empty, and therefore there will be no output bytes. bool is_empty() const noexcept { return source.empty(); } /// \brief Checks whether the content of a passed slice is a valid - /// [Base58](https://en.wikipedia.org/wiki/Base58) dump, and therefore there - /// could be decoded or not. + /// [Base58](https://en.wikipedia.org/wiki/Base58) dump, and therefore there could be decoded or not. bool is_erroneous() const noexcept; }; @@ -1468,8 +1446,7 @@ struct LIBMDBX_API from_base64 { } /// \brief Returns the number of bytes needed for conversion - /// [Base64](https://en.wikipedia.org/wiki/Base64) dump from a passed slice to - /// decoded data. + /// [Base64](https://en.wikipedia.org/wiki/Base64) dump from a passed slice to decoded data. MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept { return (source.length() + 3) / 4 * 3; } /// \brief Fills the destination with data decoded from @@ -1936,8 +1913,7 @@ public: /// the buffer, rather than stores it. MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR bool is_reference() const noexcept { return !is_freestanding(); } - /// \brief Returns the number of bytes that can be held in currently allocated - /// storage. + /// \brief Returns the number of bytes that can be held in currently allocated storage. MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX20_CONSTEXPR size_t capacity() const noexcept { return is_freestanding() ? silo_.capacity() : 0; } @@ -1961,16 +1937,14 @@ public: MDBX_CXX11_CONSTEXPR const byte *end_byte_ptr() const noexcept { return slice_.end_byte_ptr(); } /// \brief Returns casted to pointer to byte an address of data. - /// \pre REQUIRES: The buffer should store data chunk, but not referenced to - /// an external one. + /// \pre REQUIRES: The buffer should store data chunk, but not referenced to an external one. MDBX_CXX11_CONSTEXPR byte *byte_ptr() noexcept { MDBX_CONSTEXPR_ASSERT(is_freestanding()); return const_cast(slice_.byte_ptr()); } /// \brief Returns casted to pointer to byte an end of data. - /// \pre REQUIRES: The buffer should store data chunk, but not referenced to - /// an external one. + /// \pre REQUIRES: The buffer should store data chunk, but not referenced to an external one. MDBX_CXX11_CONSTEXPR byte *end_byte_ptr() noexcept { MDBX_CONSTEXPR_ASSERT(is_freestanding()); return const_cast(slice_.end_byte_ptr()); @@ -1983,16 +1957,14 @@ public: MDBX_CXX11_CONSTEXPR const char *end_char_ptr() const noexcept { return slice_.end_char_ptr(); } /// \brief Returns casted to pointer to char an address of data. - /// \pre REQUIRES: The buffer should store data chunk, but not referenced to - /// an external one. + /// \pre REQUIRES: The buffer should store data chunk, but not referenced to an external one. MDBX_CXX11_CONSTEXPR char *char_ptr() noexcept { MDBX_CONSTEXPR_ASSERT(is_freestanding()); return const_cast(slice_.char_ptr()); } /// \brief Returns casted to pointer to char an end of data. - /// \pre REQUIRES: The buffer should store data chunk, but not referenced to - /// an external one. + /// \pre REQUIRES: The buffer should store data chunk, but not referenced to an external one. MDBX_CXX11_CONSTEXPR char *end_char_ptr() noexcept { MDBX_CONSTEXPR_ASSERT(is_freestanding()); return const_cast(slice_.end_char_ptr()); @@ -2005,16 +1977,14 @@ public: MDBX_CXX11_CONSTEXPR const void *end() const noexcept { return slice_.end(); } /// \brief Return a pointer to the beginning of the referenced data. - /// \pre REQUIRES: The buffer should store data chunk, but not referenced to - /// an external one. + /// \pre REQUIRES: The buffer should store data chunk, but not referenced to an external one. MDBX_CXX11_CONSTEXPR void *data() noexcept { MDBX_CONSTEXPR_ASSERT(is_freestanding()); return const_cast(slice_.data()); } /// \brief Return a pointer to the end of the referenced data. - /// \pre REQUIRES: The buffer should store data chunk, but not referenced to - /// an external one. + /// \pre REQUIRES: The buffer should store data chunk, but not referenced to an external one. MDBX_CXX11_CONSTEXPR void *end() noexcept { MDBX_CONSTEXPR_ASSERT(is_freestanding()); return const_cast(slice_.end()); @@ -2744,8 +2714,7 @@ MDBX_EXTERN_API_TEMPLATE(LIBMDBX_API_TYPE, buffer); MDBX_EXTERN_API_TEMPLATE(LIBMDBX_API_TYPE, buffer); #endif /* __cpp_lib_memory_resource >= 201603L */ -/// \brief Combines data slice with boolean flag to represent result of certain -/// operations. +/// \brief Combines data slice with boolean flag to represent result of certain operations. struct value_result { slice value; bool done; @@ -2758,8 +2727,7 @@ struct value_result { } }; -/// \brief Combines pair of slices for key and value to represent result of -/// certain operations. +/// \brief Combines pair of slices for key and value to represent result of certain operations. struct pair { using stl_pair = std::pair; slice key, value; @@ -2919,8 +2887,7 @@ MDBX_CXX01_CONSTEXPR_ENUM bool is_reverse(key_mode mode) noexcept { MDBX_CXX01_CONSTEXPR_ENUM bool is_msgpack(key_mode mode) noexcept { return mode == key_mode::msgpack; } -/// \brief Kind of the values and sorted multi-values with corresponding -/// comparison. +/// \brief Kind of the values and sorted multi-values with corresponding comparison. enum class value_mode { single = MDBX_DB_DEFAULTS, ///< Usual single value for each key. In terms of ///< keys, they are unique. @@ -3000,8 +2967,7 @@ MDBX_CXX01_CONSTEXPR_ENUM bool is_reverse(value_mode mode) noexcept { MDBX_CXX01_CONSTEXPR_ENUM bool is_msgpack(value_mode mode) noexcept { return mode == value_mode::msgpack; } -/// \brief A handle for an individual table (aka key-value space, maps or -/// sub-database) in the environment. +/// \brief A handle for an individual table (aka key-value space, maps or sub-database) in the environment. /// \see txn::open_map() \see txn::create_map() /// \see txn::clear_map() \see txn::drop_map() /// \see txn::get_handle_info() \see txn::get_map_stat() @@ -3130,12 +3096,10 @@ public: /// environment). intptr_t size_upper{default_value}; - /// \brief The growth step in bytes, must be greater than zero to allow the - /// database to grow. + /// \brief The growth step in bytes, must be greater than zero to allow the database to grow. intptr_t growth_step{default_value}; - /// \brief The shrink threshold in bytes, must be greater than zero to allow - /// the database to shrink. + /// \brief The shrink threshold in bytes, must be greater than zero to allow the database to shrink. intptr_t shrink_threshold{default_value}; /// \brief The database page size for new database creation @@ -3270,47 +3234,34 @@ public: static inline size_t pagesize_min() noexcept; /// \brief Returns the maximal database page size in bytes. static inline size_t pagesize_max() noexcept; - /// \brief Returns the minimal database size in bytes for specified page - /// size. + /// \brief Returns the minimal database size in bytes for specified page size. static inline size_t dbsize_min(intptr_t pagesize); - /// \brief Returns the maximal database size in bytes for specified page - /// size. + /// \brief Returns the maximal database size in bytes for specified page size. static inline size_t dbsize_max(intptr_t pagesize); - /// \brief Returns the minimal key size in bytes for specified table - /// flags. + /// \brief Returns the minimal key size in bytes for specified table flags. static inline size_t key_min(MDBX_db_flags_t flags) noexcept; /// \brief Returns the minimal key size in bytes for specified keys mode. static inline size_t key_min(key_mode mode) noexcept; - /// \brief Returns the maximal key size in bytes for specified page size and - /// table flags. + /// \brief Returns the maximal key size in bytes for specified page size and table flags. static inline size_t key_max(intptr_t pagesize, MDBX_db_flags_t flags); - /// \brief Returns the maximal key size in bytes for specified page size and - /// keys mode. + /// \brief Returns the maximal key size in bytes for specified page size and keys mode. static inline size_t key_max(intptr_t pagesize, key_mode mode); - /// \brief Returns the maximal key size in bytes for given environment and - /// table flags. + /// \brief Returns the maximal key size in bytes for given environment and table flags. static inline size_t key_max(const env &, MDBX_db_flags_t flags); - /// \brief Returns the maximal key size in bytes for given environment and - /// keys mode. + /// \brief Returns the maximal key size in bytes for given environment and keys mode. static inline size_t key_max(const env &, key_mode mode); - /// \brief Returns the minimal values size in bytes for specified table - /// flags. + /// \brief Returns the minimal values size in bytes for specified table flags. static inline size_t value_min(MDBX_db_flags_t flags) noexcept; - /// \brief Returns the minimal values size in bytes for specified values - /// mode. + /// \brief Returns the minimal values size in bytes for specified values mode. static inline size_t value_min(value_mode) noexcept; - /// \brief Returns the maximal value size in bytes for specified page size - /// and table flags. + /// \brief Returns the maximal value size in bytes for specified page size and table flags. static inline size_t value_max(intptr_t pagesize, MDBX_db_flags_t flags); - /// \brief Returns the maximal value size in bytes for specified page size - /// and values mode. + /// \brief Returns the maximal value size in bytes for specified page size and values mode. static inline size_t value_max(intptr_t pagesize, value_mode); - /// \brief Returns the maximal value size in bytes for given environment and - /// table flags. + /// \brief Returns the maximal value size in bytes for given environment and table flags. static inline size_t value_max(const env &, MDBX_db_flags_t flags); - /// \brief Returns the maximal value size in bytes for specified page size - /// and values mode. + /// \brief Returns the maximal value size in bytes for specified page size and values mode. static inline size_t value_max(const env &, value_mode); /// \brief Returns maximal size of key-value pair to fit in a single page @@ -3390,13 +3341,11 @@ public: /// \brief Make sure that the environment is not being used by other /// processes, or return an error otherwise. ensure_unused = MDBX_ENV_ENSURE_UNUSED, - /// \brief Wait until other processes closes the environment before - /// deletion. + /// \brief Wait until other processes closes the environment before deletion. wait_for_unused = MDBX_ENV_WAIT_FOR_UNUSED }; - /// \brief Removes the environment's files in a proper and multiprocess-safe - /// way. + /// \brief Removes the environment's files in a proper and multiprocess-safe way. #ifdef MDBX_STD_FILESYSTEM_PATH static bool remove(const MDBX_STD_FILESYSTEM_PATH &pathname, const remove_mode mode = just_remove); #endif /* MDBX_STD_FILESYSTEM_PATH */ @@ -3422,12 +3371,10 @@ public: /// \brief Return snapshot information about the MDBX environment. inline info get_info() const; - /// \brief Return statistics about the MDBX environment accordingly to the - /// specified transaction. + /// \brief Return statistics about the MDBX environment accordingly to the specified transaction. inline stat get_stat(const txn &) const; - /// \brief Return information about the MDBX environment accordingly to the - /// specified transaction. + /// \brief Return information about the MDBX environment accordingly to the specified transaction. inline info get_info(const txn &) const; /// \brief Returns the file descriptor for the DXB file of MDBX environment. @@ -3439,8 +3386,7 @@ public: /// Returns environment flags. inline MDBX_env_flags_t get_flags() const; - /// \brief Returns the maximum number of threads/reader slots for the - /// environment. + /// \brief Returns the maximum number of threads/reader slots for the environment. /// \see extra_runtime_option::max_readers inline unsigned max_readers() const; @@ -3824,8 +3770,7 @@ public: /// volume of dirty pages) in bytes. size_t size_max() const { return env().transaction_size_max(); } - /// \brief Returns current write transaction size (i.e.summary volume of dirty - /// pages) in bytes. + /// \brief Returns current write transaction size (i.e.summary volume of dirty pages) in bytes. size_t size_current() const { assert(is_readwrite()); return size_t(get_info().txn_space_dirty); @@ -3984,42 +3929,32 @@ public: inline map_handle::info get_handle_info(map_handle map) const; using canary = ::MDBX_canary; - /// \brief Set integers markers (aka "canary") associated with the - /// environment. + /// \brief Set integers markers (aka "canary") associated with the environment. inline txn &put_canary(const canary &); - /// \brief Returns fours integers markers (aka "canary") associated with the - /// environment. + /// \brief Returns fours integers markers (aka "canary") associated with the environment. inline canary get_canary() const; - /// Reads sequence generator associated with a key-value map (aka - /// table). + /// Reads sequence generator associated with a key-value map (aka table). inline uint64_t sequence(map_handle map) const; - /// \brief Reads and increment sequence generator associated with a key-value - /// map (aka table). + /// \brief Reads and increment sequence generator associated with a key-value map (aka table). inline uint64_t sequence(map_handle map, uint64_t increment); - /// \brief Compare two keys according to a particular key-value map (aka - /// table). + /// \brief Compare two keys according to a particular key-value map (aka table). inline int compare_keys(map_handle map, const slice &a, const slice &b) const noexcept; - /// \brief Compare two values according to a particular key-value map (aka - /// table). + /// \brief Compare two values according to a particular key-value map (aka table). inline int compare_values(map_handle map, const slice &a, const slice &b) const noexcept; - /// \brief Compare keys of two pairs according to a particular key-value map - /// (aka table). + /// \brief Compare keys of two pairs according to a particular key-value map (aka table). inline int compare_keys(map_handle map, const pair &a, const pair &b) const noexcept; - /// \brief Compare values of two pairs according to a particular key-value map - /// (aka table). + /// \brief Compare values of two pairs according to a particular key-value map(aka table). inline int compare_values(map_handle map, const pair &a, const pair &b) const noexcept; /// \brief Get value by key from a key-value map (aka table). inline slice get(map_handle map, const slice &key) const; - /// \brief Get first of multi-value and values count by key from a key-value - /// multimap (aka table). + /// \brief Get first of multi-value and values count by key from a key-value multimap (aka table). inline slice get(map_handle map, slice key, size_t &values_count) const; /// \brief Get value by key from a key-value map (aka table). inline slice get(map_handle map, const slice &key, const slice &value_at_absence) const; - /// \brief Get first of multi-value and values count by key from a key-value - /// multimap (aka table). + /// \brief Get first of multi-value and values count by key from a key-value multimap (aka table). inline slice get(map_handle map, slice key, size_t &values_count, const slice &value_at_absence) const; /// \brief Get value for equal or great key from a table. /// \return Bundle of key-value pair and boolean flag, @@ -4518,12 +4453,10 @@ public: //---------------------------------------------------------------------------- - /// \brief Renew/bind a cursor with a new transaction and previously used - /// key-value map handle. + /// \brief Renew/bind a cursor with a new transaction and previously used key-value map handle. inline void renew(::mdbx::txn &txn); - /// \brief Bind/renew a cursor with a new transaction and specified key-value - /// map handle. + /// \brief Bind/renew a cursor with a new transaction and specified key-value map handle. inline void bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle); /// \brief Unbind cursor from a transaction. @@ -4556,12 +4489,10 @@ public: value_result try_insert(const pair &kv) { return try_insert(kv.key, kv.value); } void upsert(const pair &kv) { return upsert(kv.key, kv.value); } - /// \brief Removes single key-value pair or all multi-values at the current - /// cursor position. + /// \brief Removes single key-value pair or all multi-values at the current cursor position. inline bool erase(bool whole_multivalue = false); - /// \brief Seeks and removes first value or whole multi-value of the given - /// key. + /// \brief Seeks and removes first value or whole multi-value of the given key. /// \return `True` if the key is found and a value(s) is removed. inline bool erase(const slice &key, bool whole_multivalue = true); From e11d419d205732c2abe698c647883f2e7a51329c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:56:55 +0300 Subject: [PATCH 162/181] =?UTF-8?q?mdbx-tests:=20=D0=BF=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D1=85=D0=B2=D0=B0=D1=82=20=D0=B8=20=D0=BB=D0=BE=D0=B3=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B8=D1=81=D0=BA?= =?UTF-8?q?=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=B2=20extra-C++?= =?UTF-8?q?=20=D1=82=D0=B5=D1=81=D1=82=D0=B0=D1=85=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/crunched_delete.c++ | 19 +++++++++++++------ test/extra/cursor_closing.c++ | 19 +++++++++++++------ test/extra/dbi.c++ | 19 +++++++++++++------ test/extra/doubtless_positioning.c++ | 16 ++++++++++++---- test/extra/dupfix_addodd.c | 2 +- test/extra/dupfix_multiple.c++ | 7 +++---- test/extra/early_close_dbi.c++ | 17 +++++++++++++---- test/extra/hex_base64_base58.c++ | 16 ++++++++++++---- test/extra/maindb_ordinal.c++ | 18 +++++++++++++----- test/extra/open.c++ | 19 +++++++++++++------ test/extra/txn.c++ | 19 +++++++++++++------ 11 files changed, 119 insertions(+), 52 deletions(-) diff --git a/test/extra/crunched_delete.c++ b/test/extra/crunched_delete.c++ index 134dbafe..af2e6fad 100644 --- a/test/extra/crunched_delete.c++ +++ b/test/extra/crunched_delete.c++ @@ -349,12 +349,7 @@ bool simple(mdbx::env env) { return true; } -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - - mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); - +int doit() { mdbx::path db_filename = "test-crunched-del"; mdbx::env::remove(db_filename); @@ -392,3 +387,15 @@ int main(int argc, const char *argv[]) { std::cout << "OK\n"; return EXIT_SUCCESS; } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/cursor_closing.c++ b/test/extra/cursor_closing.c++ index 60749dbd..5f575c89 100644 --- a/test/extra/cursor_closing.c++ +++ b/test/extra/cursor_closing.c++ @@ -316,12 +316,7 @@ bool case1(mdbx::env env) { //-------------------------------------------------------------------------------------------- -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - - mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); - +int doit() { mdbx::path db_filename = "test-cursor-closing"; mdbx::env::remove(db_filename); @@ -339,3 +334,15 @@ int main(int argc, const char *argv[]) { return EXIT_FAILURE; } } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/dbi.c++ b/test/extra/dbi.c++ index fe238415..9aca25a5 100644 --- a/test/extra/dbi.c++ +++ b/test/extra/dbi.c++ @@ -11,12 +11,7 @@ static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int li fprintf(stdout, "%s:%u %s", function, line, msg); } -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - - mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); - +int doit() { mdbx::path db_filename = "test-dbi"; mdbx::env::remove(db_filename); @@ -71,3 +66,15 @@ int main(int argc, const char *argv[]) { std::cout << "OK\n"; return EXIT_SUCCESS; } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + mdbx_setup_debug_nofmt(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/doubtless_positioning.c++ b/test/extra/doubtless_positioning.c++ index ecc24daa..a7a50e41 100644 --- a/test/extra/doubtless_positioning.c++ +++ b/test/extra/doubtless_positioning.c++ @@ -211,10 +211,7 @@ static bool test(mdbx::txn txn, mdbx::map_handle dbi) { return ok; } -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - +int doit() { mdbx::path db_filename = "test-posi"; mdbx::env_managed::remove(db_filename); mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters(3)); @@ -243,3 +240,14 @@ int main(int argc, const char *argv[]) { std::cout << "OK\n"; return EXIT_SUCCESS; } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/dupfix_addodd.c b/test/extra/dupfix_addodd.c index 7d976f9b..4d79b27e 100644 --- a/test/extra/dupfix_addodd.c +++ b/test/extra/dupfix_addodd.c @@ -25,7 +25,7 @@ int main() { MDBX_val key, data; MDBX_txn *txn = NULL; - const char *db_filename = "./example-db"; + const char *db_filename = "./test-dupfix-addodd"; mdbx_env_delete(db_filename, MDBX_ENV_JUST_DELETE); rc = mdbx_env_create(&env); diff --git a/test/extra/dupfix_multiple.c++ b/test/extra/dupfix_multiple.c++ index ecc02bc7..f4aa94be 100644 --- a/test/extra/dupfix_multiple.c++ +++ b/test/extra/dupfix_multiple.c++ @@ -9,7 +9,7 @@ using buffer = mdbx::default_buffer; bool case1_ordering(mdbx::env env) { auto txn = env.start_write(); - auto map = txn.create_map(nullptr, mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal); + auto map = txn.create_map("case1", mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal); txn.insert(map, buffer::key_from_u64(21), buffer::key_from_u64(18)); txn.insert(map, buffer::key_from_u64(7), buffer::key_from_u64(19)); @@ -175,7 +175,7 @@ bool case1_ordering(mdbx::env env) { bool case2_batch_read(mdbx::env env) { auto txn = env.start_write(); - auto map = txn.create_map(nullptr, mdbx::key_mode::usual, mdbx::value_mode::multi_samelength); + auto map = txn.create_map("case2", mdbx::key_mode::usual, mdbx::value_mode::multi_samelength); txn.upsert(map, mdbx::slice("key1"), mdbx::slice("val1")); txn.upsert(map, mdbx::pair("key1", "val2")); txn.upsert(map, mdbx::pair("key1", "val3")); @@ -270,7 +270,7 @@ bool case3_put_a_lot(mdbx::env env) { int doit() { mdbx::path db_filename = "test-dupfix-multiple"; mdbx::env_managed::remove(db_filename); - mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters(1)); + mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters(3)); bool ok = case1_ordering(env); ok = case2_batch_read(env) && ok; @@ -288,7 +288,6 @@ int doit() { int main(int argc, const char *argv[]) { (void)argc; (void)argv; - try { return doit(); } catch (const std::exception &ex) { diff --git a/test/extra/early_close_dbi.c++ b/test/extra/early_close_dbi.c++ index 3eeea42c..cb5d1b6d 100644 --- a/test/extra/early_close_dbi.c++ +++ b/test/extra/early_close_dbi.c++ @@ -1,13 +1,11 @@ #include "mdbx.h++" #include +#include static const char *const testkey = "testkey"; static uint64_t testval = 11; -int main(int argc, char *argv[]) { - (void)argc; - (void)argv; - +int doit() { mdbx::path db_filename = "test-early_close_dbi"; mdbx::env_managed::remove(db_filename); @@ -126,3 +124,14 @@ int main(int argc, char *argv[]) { return 0; } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/hex_base64_base58.c++ b/test/extra/hex_base64_base58.c++ index 972673e9..6196d348 100644 --- a/test/extra/hex_base64_base58.c++ +++ b/test/extra/hex_base64_base58.c++ @@ -75,10 +75,7 @@ static bool basic() { return ok; } -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - +int doit() { auto ok = basic(); for (size_t n = 0; n < 1000; ++n) { for (size_t length = 0; ok && length < 111; ++length) { @@ -108,3 +105,14 @@ int main(int argc, const char *argv[]) { std::cout << "OK\n"; return EXIT_SUCCESS; } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/maindb_ordinal.c++ b/test/extra/maindb_ordinal.c++ index 9e6bd7ef..359cff89 100644 --- a/test/extra/maindb_ordinal.c++ +++ b/test/extra/maindb_ordinal.c++ @@ -4,11 +4,8 @@ #include "mdbx.h++" #include -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - - mdbx::path db_filename = "test-dupfix-multiple"; +static int doit() { + mdbx::path db_filename = "test-maindb-ordinal"; mdbx::env_managed::remove(db_filename); mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(), mdbx::env::operate_parameters()); @@ -51,3 +48,14 @@ int main(int argc, const char *argv[]) { return EXIT_SUCCESS; #endif /* __cpp_lib_string_view >= 201606L */ } + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} diff --git a/test/extra/open.c++ b/test/extra/open.c++ index 459ca708..353b848e 100644 --- a/test/extra/open.c++ +++ b/test/extra/open.c++ @@ -25,12 +25,7 @@ static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int li fprintf(stdout, "%s:%u %s", function, line, msg); } -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - - mdbx_setup_debug_nofmt(MDBX_LOG_VERBOSE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); - +int doit() { mdbx::path path = "test-open"; mdbx::env::remove(path); @@ -86,4 +81,16 @@ int main(int argc, const char *argv[]) { return EXIT_SUCCESS; } +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + mdbx_setup_debug_nofmt(MDBX_LOG_VERBOSE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} + #endif /* __cpp_lib_latch */ diff --git a/test/extra/txn.c++ b/test/extra/txn.c++ index e1abb1e6..583328cf 100644 --- a/test/extra/txn.c++ +++ b/test/extra/txn.c++ @@ -308,12 +308,7 @@ bool case2(const mdbx::path &path, bool no_sticky_threads) { return true; } -int main(int argc, const char *argv[]) { - (void)argc; - (void)argv; - - mdbx_setup_debug_nofmt(MDBX_LOG_VERBOSE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); - +int doit() { mdbx::path path = "test-txn"; mdbx::env::remove(path); @@ -326,4 +321,16 @@ int main(int argc, const char *argv[]) { return ok ? EXIT_SUCCESS : EXIT_FAILURE; } +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + mdbx_setup_debug_nofmt(MDBX_LOG_VERBOSE, MDBX_DBG_ASSERT, logger_nofmt, log_buffer, sizeof(log_buffer)); + try { + return doit(); + } catch (const std::exception &ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + return EXIT_FAILURE; + } +} + #endif /* __cpp_lib_latch */ From 3a0dbee58ca54dbdb008c132df0e9a12c1f03d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:57:38 +0300 Subject: [PATCH 163/181] =?UTF-8?q?mdbx-tests:=20=D1=83=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B5=D0=B2=D1=8B?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BD=D0=B5=D0=BD=D0=BD=D0=BE=D0=B3=D0=BE=20?= =?UTF-8?q?=D0=B4=D0=BE=D1=81=D1=82=D1=83=D0=BF=D0=B0=20=D0=B2=20extra/clo?= =?UTF-8?q?se-dbi=20=D0=B4=D0=BB=D1=8F=20UBSAN=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/early_close_dbi.c++ | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/extra/early_close_dbi.c++ b/test/extra/early_close_dbi.c++ index cb5d1b6d..0ed94fb6 100644 --- a/test/extra/early_close_dbi.c++ +++ b/test/extra/early_close_dbi.c++ @@ -65,13 +65,13 @@ int doit() { assert(err == MDBX_SUCCESS); err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval); assert(err == MDBX_SUCCESS); - assert(testval == *reinterpret_cast(mdbxval.iov_base)); + assert(testval == mdbx::slice(mdbxval).as_uint64()); err = mdbx_put(transaction, textindex, &mdbxkey, &mdbxput, MDBX_NOOVERWRITE); assert(err == MDBX_KEYEXIST); err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval); assert(err == MDBX_SUCCESS); - assert(testval == *reinterpret_cast(mdbxval.iov_base)); + assert(testval == mdbx::slice(mdbxval).as_uint64()); err = mdbx_dbi_flags_ex(transaction, textindex, &dbi_flags, &dbi_state); assert(err == MDBX_SUCCESS); @@ -87,7 +87,7 @@ int doit() { assert(err == MDBX_SUCCESS); err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval); assert(err == MDBX_SUCCESS); - assert(testval == *reinterpret_cast(mdbxval.iov_base)); + assert(testval == mdbx::slice(mdbxval).as_uint64()); err = mdbx_dbi_close(environment, textindex); assert(err == MDBX_SUCCESS); From 3c3628c7989f75a343e48d50c868e2f60c3220d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 01:58:02 +0300 Subject: [PATCH 164/181] =?UTF-8?q?mdbx-tests:=20=D0=BA=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D0=BD=D0=BE=D0=B5=20=D1=81=D0=BE=D0=BA=D1=80=D0=B0=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B8=D1=82=D0=B5=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B9=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=20=D0=B2=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=81=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D0=B8=20?= =?UTF-8?q?=D0=BE=D1=82=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=D1=83=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8=20Valgrind/Debug/CI=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/CMakeLists.txt | 4 ++-- test/extra/crunched_delete.c++ | 18 +++++++++++++----- test/extra/cursor_closing.c++ | 34 +++++++++++++++++++++++++--------- test/extra/dupfix_multiple.c++ | 24 +++++++++++++++++++----- test/extra/txn.c++ | 16 +++++++++++++++- 5 files changed, 74 insertions(+), 22 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d4dfc086..dda4a909 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -300,10 +300,10 @@ else() endif() if(MDBX_BUILD_CXX) if(NOT WIN32 OR NOT MDBX_CXX_STANDARD LESS 17) - add_extra_test(cursor_closing) + add_extra_test(cursor_closing TIMEOUT 10800) add_extra_test(early_close_dbi) add_extra_test(maindb_ordinal) - add_extra_test(dupfix_multiple) + add_extra_test(dupfix_multiple TIMEOUT 10800) add_extra_test(doubtless_positioning TIMEOUT 10800) add_extra_test(crunched_delete TIMEOUT 10800) add_extra_test(dbi) diff --git a/test/extra/crunched_delete.c++ b/test/extra/crunched_delete.c++ index af2e6fad..4b740664 100644 --- a/test/extra/crunched_delete.c++ +++ b/test/extra/crunched_delete.c++ @@ -5,13 +5,21 @@ #include #include -#if MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) -#define NN 1024 -#elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul -#define NN 4096 +#if defined(ENABLE_MEMCHECK) || defined(MDBX_CI) +#if MDBX_DEBUG || !defined(NDEBUG) +#define RELIEF_FACTOR 16 #else -#define NN 2048 +#define RELIEF_FACTOR 8 #endif +#elif MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) +#define RELIEF_FACTOR 4 +#elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul +#define RELIEF_FACTOR 2 +#else +#define RELIEF_FACTOR 1 +#endif + +#define NN (2048 / RELIEF_FACTOR) std::string format_va(const char *fmt, va_list ap) { va_list ones; diff --git a/test/extra/cursor_closing.c++ b/test/extra/cursor_closing.c++ index 5f575c89..24633560 100644 --- a/test/extra/cursor_closing.c++ +++ b/test/extra/cursor_closing.c++ @@ -9,6 +9,22 @@ #include #endif +#if defined(ENABLE_MEMCHECK) || defined(MDBX_CI) +#if MDBX_DEBUG || !defined(NDEBUG) +#define RELIEF_FACTOR 16 +#else +#define RELIEF_FACTOR 8 +#endif +#elif MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) +#define RELIEF_FACTOR 4 +#elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul +#define RELIEF_FACTOR 2 +#else +#define RELIEF_FACTOR 1 +#endif + +#define NN (1000 / RELIEF_FACTOR) + static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg, unsigned length) noexcept { (void)length; @@ -113,10 +129,10 @@ void case1_shuffle_pool(std::vector &pool) { void case1_read_pool(std::vector &pool) { for (auto c : pool) if (flipcoin()) - mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(1000)), mdbx::slice::wrap(prng(1000)), false); + mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(NN)), mdbx::slice::wrap(prng(NN)), false); for (auto c : pool) if (flipcoin()) - mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(1000)), mdbx::slice::wrap(prng(1000)), false); + mdbx::cursor(c).find_multivalue(mdbx::slice::wrap(prng(NN)), mdbx::slice::wrap(prng(NN)), false); } MDBX_cursor *case1_try_unbind(MDBX_cursor *cursor) { @@ -224,9 +240,9 @@ void case1_write_cycle(mdbx::txn_managed txn, std::deque &dbi, pre.unbind(); if (!pre.txn()) pre.bind(txn, dbi[prng(dbi.size())]); - for (auto i = 0; i < 1000; ++i) { - auto k = mdbx::default_buffer::wrap(prng(1000)); - auto v = mdbx::default_buffer::wrap(prng(1000)); + for (auto i = 0; i < NN; ++i) { + auto k = mdbx::default_buffer::wrap(prng(NN)); + auto v = mdbx::default_buffer::wrap(prng(NN)); if (pre.find_multivalue(k, v, false)) pre.erase(); else @@ -246,8 +262,8 @@ void case1_write_cycle(mdbx::txn_managed txn, std::deque &dbi, bool case1_thread(mdbx::env env, std::deque dbi, mdbx::cursor pre) { salt = size_t(std::chrono::high_resolution_clock::now().time_since_epoch().count()); std::vector pool; - for (auto loop = 0; loop < 333; ++loop) { - for (auto read = 0; read < 333; ++read) { + for (auto loop = 0; loop < 333 / RELIEF_FACTOR; ++loop) { + for (auto read = 0; read < 333 / RELIEF_FACTOR; ++read) { auto txn = env.start_read(); case1_read_cycle(txn, dbi, pool, pre); if (flipcoin()) @@ -280,8 +296,8 @@ bool case1(mdbx::env env) { auto txn = env.start_write(); auto table = txn.create_map(std::to_string(t), mdbx::key_mode::ordinal, mdbx::value_mode::multi_samelength); auto cursor = txn.open_cursor(table); - for (size_t i = 0; i < 10000; ++i) - cursor.upsert(mdbx::default_buffer::wrap(prng(1000)), mdbx::default_buffer::wrap(prng(1000))); + for (size_t i = 0; i < NN * 11; ++i) + cursor.upsert(mdbx::default_buffer::wrap(prng(NN)), mdbx::default_buffer::wrap(prng(NN))); txn.commit(); cursors.push_back(std::move(cursor)); diff --git a/test/extra/dupfix_multiple.c++ b/test/extra/dupfix_multiple.c++ index f4aa94be..a18ebfc8 100644 --- a/test/extra/dupfix_multiple.c++ +++ b/test/extra/dupfix_multiple.c++ @@ -5,6 +5,20 @@ #include #include +#if defined(ENABLE_MEMCHECK) || defined(MDBX_CI) +#if MDBX_DEBUG || !defined(NDEBUG) +#define RELIEF_FACTOR 16 +#else +#define RELIEF_FACTOR 8 +#endif +#elif MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) +#define RELIEF_FACTOR 4 +#elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul +#define RELIEF_FACTOR 2 +#else +#define RELIEF_FACTOR 1 +#endif + using buffer = mdbx::default_buffer; bool case1_ordering(mdbx::env env) { @@ -224,7 +238,7 @@ static size_t prng() { static inline size_t prng(size_t range) { return prng() % range; } static mdbx::default_buffer_pair prng_kv(size_t n, size_t space) { - space = (space + !space) * 1024 * 32; + space = (space + !space) * 1024 * 32 / RELIEF_FACTOR; const size_t w = (n ^ 1455614549) * 1664525 + 1013904223; const size_t k = (prng(42 + w % space) ^ 1725278851) * 433750991; const size_t v = prng(); @@ -235,11 +249,11 @@ bool case3_put_a_lot(mdbx::env env) { salt = size_t(std::chrono::high_resolution_clock::now().time_since_epoch().count()); auto txn = env.start_write(); auto map = txn.create_map("case3", mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal); - for (size_t n = 0; n < 5555555; ++n) + for (size_t n = 0; n < 5555555 / RELIEF_FACTOR; ++n) txn.upsert(map, prng_kv(n, 1)); txn.commit(); - for (size_t t = 0; t < 555; ++t) { + for (size_t t = 0; t < 555 / RELIEF_FACTOR; ++t) { txn = env.start_write(); auto cursor = txn.open_cursor(map); for (size_t n = 0; n < 111; ++n) { @@ -247,7 +261,7 @@ bool case3_put_a_lot(mdbx::env env) { const auto r = 1 + prng(3); if (r & 1) { const auto k = prng_kv(n + t, 2).key; - for (size_t i = prng(42 + prng(111) * prng(111)); i > 0; --i) + for (size_t i = prng(42 + prng(111) * prng(111 / RELIEF_FACTOR)); i > 0; --i) v.push_back(prng()); txn.put_multiple_samelength(map, k, v, mdbx::upsert); } @@ -255,7 +269,7 @@ bool case3_put_a_lot(mdbx::env env) { const auto k = prng_kv(n + t, 2).key; if (cursor.seek(k)) { v.clear(); - for (size_t i = prng(42 + prng(111) * prng(111)); i > 0; --i) + for (size_t i = prng(42 + prng(111) * prng(111 / RELIEF_FACTOR)); i > 0; --i) v.push_back(prng()); cursor.put_multiple_samelength(k, v, mdbx::upsert); } diff --git a/test/extra/txn.c++ b/test/extra/txn.c++ index 583328cf..40f9ab0b 100644 --- a/test/extra/txn.c++ +++ b/test/extra/txn.c++ @@ -3,6 +3,20 @@ #include +#if defined(ENABLE_MEMCHECK) || defined(MDBX_CI) +#if MDBX_DEBUG || !defined(NDEBUG) +#define RELIEF_FACTOR 16 +#else +#define RELIEF_FACTOR 8 +#endif +#elif MDBX_DEBUG || !defined(NDEBUG) || defined(__APPLE__) || defined(_WIN32) +#define RELIEF_FACTOR 4 +#elif UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul +#define RELIEF_FACTOR 2 +#else +#define RELIEF_FACTOR 1 +#endif + #if !defined(__cpp_lib_latch) && __cpp_lib_latch < 201907L int main(int argc, const char *argv[]) { @@ -295,7 +309,7 @@ bool case2(const mdbx::path &path, bool no_sticky_threads) { for (size_t n = 0; n < 8; ++n) l.push_back(std::thread([&]() { s.wait(); - for (size_t i = 0; i < 1000000; ++i) { + for (size_t i = 0; i < 1000000 / RELIEF_FACTOR; ++i) { auto txn = env.start_read(); txn.abort(); } From 8157d07b009650e18e45b32d1e4d60ac30bbf3c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 13:53:47 +0300 Subject: [PATCH 165/181] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B0=D0=BB=D0=B8=D1=87=D0=B8=D0=B8=20`EREMOTEI?= =?UTF-8?q?O`=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20`ENOTBLK`=20=D0=B2?= =?UTF-8?q?=20=D0=BA=D0=B0=D1=87=D0=B5=D1=81=D1=82=D0=B2=D0=B5=20`MDBX=5FE?= =?UTF-8?q?REMOTE`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mdbx.h b/mdbx.h index a6cdb7de..f515eae1 100644 --- a/mdbx.h +++ b/mdbx.h @@ -2006,7 +2006,12 @@ typedef enum MDBX_error { MDBX_EPERM = EPERM, MDBX_EINTR = EINTR, MDBX_ENOFILE = ENOENT, +#if defined(EREMOTEIO) || defined(DOXYGEN) + /** Cannot use the database on a network file system or when exporting it via NFS. */ + MDBX_EREMOTE = EREMOTEIO, +#else MDBX_EREMOTE = ENOTBLK, +#endif /* EREMOTEIO */ MDBX_EDEADLK = EDEADLK #endif /* !Windows */ } MDBX_error_t; From 35349cf5388217ccdbd6c81eb6bcdffa83c8d02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 13:55:07 +0300 Subject: [PATCH 166/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20=D1=81=D0=B1=D0=BE=D1=80=D0=BA=D0=B8=20`MDBX=5FENABLE=5FNON?= =?UTF-8?q?=5FREADONLY=5FEXPORT`=20=D0=B8=20=D0=BB=D0=BE=D0=B3=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=81=D0=BE=D0=BE=D1=82?= =?UTF-8?q?=D0=B2=D0=B5=D1=82=D1=81=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B8?= =?UTF-8?q?=D1=85=20=D1=81=D0=B8=D1=82=D1=83=D0=B0=D1=86=D0=B8=D0=B9=20(ba?= =?UTF-8?q?ckport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Закрывает [запрос](https://gitflic.ru/project/erthink/libmdbx/issue/16). --- src/dxb.c | 2 +- src/lck.c | 5 +++-- src/options.h | 8 ++++++++ src/osal.c | 45 ++++++++++++++++++++++++++++++++------------- src/osal.h | 3 ++- 5 files changed, 46 insertions(+), 17 deletions(-) diff --git a/src/dxb.c b/src/dxb.c index fa3b8f6e..29df1ee6 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -681,7 +681,7 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit !(env->flags & MDBX_NORDAHEAD) && mdbx_is_readahead_reasonable(used_bytes, 0) == MDBX_RESULT_TRUE; err = osal_mmap(env->flags, &env->dxb_mmap, env->geo_in_bytes.now, env->geo_in_bytes.upper, - (lck_rc && env->stuck_meta < 0) ? MMAP_OPTION_TRUNCATE : 0); + (lck_rc && env->stuck_meta < 0) ? MMAP_OPTION_TRUNCATE : 0, env->pathname.dxb); if (unlikely(err != MDBX_SUCCESS)) return err; diff --git a/src/lck.c b/src/lck.c index 0bb3205c..0e19b29c 100644 --- a/src/lck.c +++ b/src/lck.c @@ -62,8 +62,9 @@ __cold static int lck_setup_locked(MDBX_env *env) { } env->max_readers = (maxreaders <= MDBX_READERS_LIMIT) ? (unsigned)maxreaders : (unsigned)MDBX_READERS_LIMIT; - err = osal_mmap((env->flags & MDBX_EXCLUSIVE) | MDBX_WRITEMAP, &env->lck_mmap, (size_t)size, (size_t)size, - lck_seize_rc ? MMAP_OPTION_TRUNCATE | MMAP_OPTION_SEMAPHORE : MMAP_OPTION_SEMAPHORE); + err = + osal_mmap((env->flags & MDBX_EXCLUSIVE) | MDBX_WRITEMAP, &env->lck_mmap, (size_t)size, (size_t)size, + lck_seize_rc ? MMAP_OPTION_TRUNCATE | MMAP_OPTION_SEMAPHORE : MMAP_OPTION_SEMAPHORE, env->pathname.lck); if (unlikely(err != MDBX_SUCCESS)) return err; diff --git a/src/options.h b/src/options.h index 9449fed9..7ea12ac8 100644 --- a/src/options.h +++ b/src/options.h @@ -257,6 +257,14 @@ #error MDBX_HAVE_BUILTIN_CPU_SUPPORTS must be defined as 0 or 1 #endif /* MDBX_HAVE_BUILTIN_CPU_SUPPORTS */ +/** if enabled then instead of the returned error `MDBX_REMOTE`, only a warning is issued, when + * the database being opened in non-read-only mode is located in a file system exported via NFS. */ +#ifndef MDBX_ENABLE_NON_READONLY_EXPORT +#define MDBX_ENABLE_NON_READONLY_EXPORT 0 +#elif !(MDBX_ENABLE_NON_READONLY_EXPORT == 0 || MDBX_ENABLE_NON_READONLY_EXPORT == 1) +#error MDBX_ENABLE_NON_READONLY_EXPORT must be defined as 0 or 1 +#endif /* MDBX_ENABLE_NON_READONLY_EXPORT */ + //------------------------------------------------------------------------------ /** Win32 File Locking API for \ref MDBX_LOCKING */ diff --git a/src/osal.c b/src/osal.c index d4f4b03a..ec2e0d7c 100644 --- a/src/osal.c +++ b/src/osal.c @@ -1760,7 +1760,7 @@ static int osal_check_fs_local(mdbx_filehandle_t handle, int flags) { if ((RemoteProtocolInfo.Flags & REMOTE_PROTOCOL_INFO_FLAG_OFFLINE) && !(flags & MDBX_RDONLY)) return ERROR_FILE_OFFLINE; if (!(RemoteProtocolInfo.Flags & REMOTE_PROTOCOL_INFO_FLAG_LOOPBACK) && !(flags & MDBX_EXCLUSIVE)) - return ERROR_REMOTE_STORAGE_MEDIA_ERROR; + return MDBX_EREMOTE; } } @@ -1779,7 +1779,7 @@ static int osal_check_fs_local(mdbx_filehandle_t handle, int flags) { 0, &GetExternalBacking_OutputBuffer, sizeof(GetExternalBacking_OutputBuffer)); if (NT_SUCCESS(rc)) { if (!(flags & MDBX_EXCLUSIVE)) - return ERROR_REMOTE_STORAGE_MEDIA_ERROR; + return MDBX_EREMOTE; } else if (rc != STATUS_OBJECT_NOT_EXTERNALLY_BACKED && rc != STATUS_INVALID_DEVICE_REQUEST && rc != STATUS_NOT_SUPPORTED) return ntstatus2errcode(rc); @@ -1800,7 +1800,7 @@ static int osal_check_fs_local(mdbx_filehandle_t handle, int flags) { if ((flags & MDBX_RDONLY) == 0) { if (FileSystemFlags & (FILE_SEQUENTIAL_WRITE_ONCE | FILE_READ_ONLY_VOLUME | FILE_VOLUME_IS_COMPRESSED)) { - rc = ERROR_REMOTE_STORAGE_MEDIA_ERROR; + rc = MDBX_EREMOTE; goto bailout; } } @@ -1808,7 +1808,7 @@ static int osal_check_fs_local(mdbx_filehandle_t handle, int flags) { if (imports.GetFinalPathNameByHandleW(handle, PathBuffer, INT16_MAX, FILE_NAME_NORMALIZED | VOLUME_NAME_NT)) { if (_wcsnicmp(PathBuffer, L"\\Device\\Mup\\", 12) == 0) { if (!(flags & MDBX_EXCLUSIVE)) { - rc = ERROR_REMOTE_STORAGE_MEDIA_ERROR; + rc = MDBX_EREMOTE; goto bailout; } } @@ -1836,7 +1836,7 @@ static int osal_check_fs_local(mdbx_filehandle_t handle, int flags) { case DRIVE_REMOTE: default: if (!(flags & MDBX_EXCLUSIVE)) - rc = ERROR_REMOTE_STORAGE_MEDIA_ERROR; + rc = MDBX_EREMOTE; // fall through case DRIVE_REMOVABLE: case DRIVE_FIXED: @@ -1968,11 +1968,11 @@ static int osal_check_fs_local(mdbx_filehandle_t handle, int flags) { #endif /* ST/MNT_LOCAL */ #ifdef ST_EXPORTED - if ((st_flags & ST_EXPORTED) != 0 && !(flags & MDBX_RDONLY)) - return MDBX_EREMOTE; + if ((st_flags & ST_EXPORTED) != 0 && !(flags & (MDBX_RDONLY | MDBX_EXCLUSIVE)))) + return MDBX_RESULT_TRUE; #elif defined(MNT_EXPORTED) - if ((mnt_flags & MNT_EXPORTED) != 0 && !(flags & MDBX_RDONLY)) - return MDBX_EREMOTE; + if ((mnt_flags & MNT_EXPORTED) != 0 && !(flags & (MDBX_RDONLY | MDBX_EXCLUSIVE))) + return MDBX_RESULT_TRUE; #endif /* ST/MNT_EXPORTED */ switch (type) { @@ -2023,8 +2023,8 @@ static int check_mmap_limit(const size_t limit) { return MDBX_SUCCESS; } -MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, - const unsigned options) { +MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options, + const pathchar_t *pathname4logging) { assert(size <= limit); map->limit = 0; map->current = 0; @@ -2035,8 +2035,27 @@ MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, cons #endif /* Windows */ int err = osal_check_fs_local(map->fd, flags); - if (unlikely(err != MDBX_SUCCESS)) - return err; + if (unlikely(err != MDBX_SUCCESS)) { +#if defined(_WIN32) || defined(_WIN64) + if (globals.running_under_Wine) + NOTICE("%s", "Please use native Linux application or WSL at least, instead of trouble-full Wine!"); +#endif /* Windows */ + switch (err) { + case MDBX_RESULT_TRUE: +#if MDBX_ENABLE_NON_READONLY_EXPORT + WARNING("%" MDBX_PRIsPATH " is exported via NFS, avoid using the file on a remote side!", pathname4logging); + break; +#else + ERROR("%" MDBX_PRIsPATH " is exported via NFS", pathname4logging); + return MDBX_EREMOTE; +#endif /* MDBX_PROHIBIT_NON_READONLY_EXPORT */ + case MDBX_EREMOTE: + ERROR("%" MDBX_PRIsPATH " is on a remote file system, the %s is required", pathname4logging, "MDBX_EXCLUSIVE"); + __fallthrough /* fall through */; + default: + return err; + } + } err = check_mmap_limit(limit); if (unlikely(err != MDBX_SUCCESS)) diff --git a/src/osal.h b/src/osal.h index 8f0d020c..484bbab8 100644 --- a/src/osal.h +++ b/src/osal.h @@ -464,7 +464,8 @@ MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait); #define MMAP_OPTION_TRUNCATE 1 #define MMAP_OPTION_SEMAPHORE 2 -MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options); +MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options, + const pathchar_t *pathname4logging); MDBX_INTERNAL int osal_munmap(osal_mmap_t *map); #define MDBX_MRESIZE_MAY_MOVE 0x00000100 #define MDBX_MRESIZE_MAY_UNMAP 0x00000200 From 7eb7931a23b1d1d02cc6efbe3133b509175a7876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 14:11:49 +0300 Subject: [PATCH 167/181] =?UTF-8?q?mdbx-tests:=20=D0=BA=D0=BE=D1=80=D1=80?= =?UTF-8?q?=D0=B5=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B5=D1=80=D1=8B=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B0=20=D0=BF=D0=BE=D1=81=D1=80=D0=B5=D0=B4=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D0=BE=D0=BC=20`SIGTERM`/`SIGINT`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/osal-unix.c++ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/osal-unix.c++ b/test/osal-unix.c++ index f440aeca..b7233d03 100644 --- a/test/osal-unix.c++ +++ b/test/osal-unix.c++ @@ -562,7 +562,7 @@ int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) { continue; } - if (pid == 0) + if (pid == 0 || sigbreak) break; if (err != EINTR) From 1e0a1014a4527998f72f4193b77e78592d483412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 14:23:19 +0300 Subject: [PATCH 168/181] =?UTF-8?q?mdbx-tests:=20=D0=BA=D0=BE=D1=80=D1=80?= =?UTF-8?q?=D0=B5=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B5=D1=80=D1=8B=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B0=20=D0=BF=D0=BE=D1=81=D1=80=D0=B5=D0=B4=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D0=BE=D0=BC=20`SIGTERM`/`SIGINT`=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/osal-unix.c++ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/osal-unix.c++ b/test/osal-unix.c++ index f440aeca..b7233d03 100644 --- a/test/osal-unix.c++ +++ b/test/osal-unix.c++ @@ -562,7 +562,7 @@ int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) { continue; } - if (pid == 0) + if (pid == 0 || sigbreak) break; if (err != EINTR) From 06f8573f5f3085c027fd644bc44dc33c2a550657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 17:07:36 +0300 Subject: [PATCH 169/181] =?UTF-8?q?mdbx:=20=D1=83=D1=81=D0=B8=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB?= =?UTF-8?q?=D1=8F=20=D1=81=D0=B8=D0=B3=D0=BD=D0=B0=D1=82=D1=83=D1=80=20?= =?UTF-8?q?=D0=BA=D1=83=D1=80=D1=81=D0=BE=D1=80=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/txn.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/txn.c b/src/txn.c index e2cc53f3..a61266f3 100644 --- a/src/txn.c +++ b/src/txn.c @@ -34,8 +34,10 @@ int txn_shadow_cursors(const MDBX_txn *parent, const size_t dbi) { MDBX_cursor *next = nullptr; do { next = cursor->next; - if (cursor->signature != cur_signature_live) + if (cursor->signature != cur_signature_live) { + ENSURE(parent->env, cursor->signature == cur_signature_wait4eot); continue; + } tASSERT(parent, cursor->txn == parent && dbi == cursor_dbi(cursor)); int err = cursor_shadow(cursor, txn, dbi); From 5d9fb63fb8f512915e2000929c594c9abc86b896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 18:00:44 +0300 Subject: [PATCH 170/181] =?UTF-8?q?mdbx:=20=D1=83=D1=81=D0=B8=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB?= =?UTF-8?q?=D1=8F=20=D1=81=D0=B8=D0=B3=D0=BD=D0=B0=D1=82=D1=83=D1=80=20?= =?UTF-8?q?=D0=BA=D1=83=D1=80=D1=81=D0=BE=D1=80=D0=BE=D0=B2=20(backport).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cursor.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cursor.c b/src/cursor.c index be82940f..8b6541dd 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -189,9 +189,11 @@ int cursor_shadow(MDBX_cursor *mc, MDBX_txn *nested, const size_t dbi) { const size_t size = mc->subcur ? sizeof(MDBX_cursor) + sizeof(subcur_t) : sizeof(MDBX_cursor); for (MDBX_cursor *bk; mc; mc = bk->next) { cASSERT(mc, mc != mc->next); - bk = mc; - if (mc->signature != cur_signature_live) + if (mc->signature != cur_signature_live) { + ENSURE(nested->env, mc->signature == cur_signature_wait4eot); + bk = mc; continue; + } bk = osal_malloc(size); if (unlikely(!bk)) return MDBX_ENOMEM; @@ -228,7 +230,7 @@ MDBX_cursor *cursor_eot(MDBX_cursor *mc, MDBX_txn *txn, const bool merge) { tASSERT(txn, bk->txn == txn->parent); /* Zap: Using uninitialized memory '*mc->backup'. */ MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(6001); - ENSURE(mc->txn->env, bk->signature == cur_signature_live); + ENSURE(txn->env, bk->signature == cur_signature_live); tASSERT(txn, mx == bk->subcur); if (merge) { /* Update pointers to parent txn */ From 999f8644f67df16cf9314633ecb54124afdad74a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 18:02:00 +0300 Subject: [PATCH 171/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 3d4634e3..a8e7c46f 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -10,9 +10,33 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx Благодарности: - - [Erigon](https://docs.erigon.tech/) за спонсорство. + - [Erigon](https://erigon.tech/) за спонсорство. - [Илье Михееву](https://t.me/IlyaMkhv) за сообщения о недочетах и тестирование. + - [Alex Sharov](https://github.com/AskAlexSharov) за сообщение об ошибках и тестирование. - [maxc0d3r](https://gitflic.ru/user/maxc0d3r) for bug reporting and testing. + - [Alain Picard](https://github.com/castortech) for support [Java bindings](https://github.com/castortech/mdbxjni) and MacOS universal binaries patch for CMake build scenario, + also for bug reporting (put-`MDBX_MULTIPLE` regression). Big thank for assistance with debugging and testing. + + +Новое: + + - Добавлена опция сборки `MDBX_ENABLE_NON_READONLY_EXPORT` позволяющая использовать в режиме чтения-записи БД расположенных в файловых системах экспортированных через NFS. + По-умолчанию опция выключена и при открытии в неэксклюзивном режиме чтения-записи БД расположенных файловых системах доступных извне по NFS будет возвращаться ошибка `MDBX_EREMOTE`. + Включение опции позволяет открывать БД в описанных выше ситуациях, но риск чтения неверных данных на удалённой стороне ложится на пользователя. + + - Поддержка MacOS universal binaries при сборке посредством CMake. + + - Для закрытия или отсоединения всех курсоров с получением их количества в API добавлена функция `mdbx_txn_release_all_cursors_ex()`. + + - Добавлена операция `MDBX_SEEK_AND_GET_MULTIPLE` в API курсора, позволяющая за одну операцию выполнить позиционирование + курсора на конкретное значение и начать чтение multi-значений в пакетном режиме. + + - Добавлены методы `mdbx::cursor::put_multiple_samelength()`, `mdbx::cursor::seek_multiple_samelength()`, `mdbx::cursor_managed::withdraw_handle()`. + + - В политику управления выделением для `mdbx::buffer` добавлен параметр `inplace_storage_size_rounding`. + Одновременно с этим переработан внутренний union-тип `mdbx::buffer::silo::bin` для возможности увеличения без пенальти встроенного в экземпляр буфера места под данные. + + - В API добавлена функция `mdbx_cursor_close2()` возвращающая код ошибки. Исправления: @@ -39,13 +63,75 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx - Устранена причина попыток рекурсивного захвата мьютекса при работе `mdbx_chk -w` в сборах с поддержкой Valring/ASAN и под управлением этих инструментов. - - Проверка владельца потока владеющего транзакцией только при `MDBX_TXN_CHECKOWNER=ON`. + - Устранены проверки потока владеющего транзакцией при сборке с опцией `MDBX_TXN_CHECKOWNER=OFF`. + + - Устранена вероятность ситуации гонки в `tbl_setup(MDBX_DUPFIXED | MDBX_INTEGERDUP)` при работе в разных потоках. + В реальных сценариях вероятность проявления проблемы была близка к нулю. + Для подробностей смотрите комментарий коммита `3e91500fac475947f5b58268d5edd3c9cc4f77f6`. + + - Устранён регресс затенения курсоров во вложенных транзакциях. + При реализации отложенной/ленивой инициализации dbi-дескрипторов также было реализовано отложенное затенение курсоров (создание копии состояния для отката при прерывании транзакции), + что существенно уменьшало накладные расходы при старте и завершении вложенных транзакций в сценариях с большим количеством курсоров. + Однако, была допущена логическая ошибка, вследствие которой отложенная инициализация и затенение выполнялись при использовании dbi-дескрипторов, но не курсора открытого в родительской транзакции. + В результате, родительские курсоры во вложенных транзакциях могли не затеняться, что приводило к неконсистентному состоянию в случае + прерывания/откате вложенной транзакции и в соответствующей таблицы были изменения в рамках прерванной вложенной транзакции. + Проблема не реализовывалась в тестовых сценариях и не была замечена при эксплуатации, но была обнаружена при расширении тестов. + Ошибка присутствует в версиях 0.13.x и последующих, начиная с коммита `e6af7d7c53428ca2892bcbf7eec1c2acee06fd44` от 2023-11-05. + + - Устранён регресс в пути обработки операции `MDBX_MULTIPLE`. + Пакетная вставка значений посредством `MDBX_MULTIPLE` могла приводить к падениям и повреждению структуры БД. Ошибка оставалось не + замеченной из-за специфических условий проявления, которые не реализовались в тестах. + Проблема присутствовала во всех выпусках начиная с v0.13.1, но соответствующая ошибка не связана с конкретным коммита в истории, а + является следствием нескольких доработок (шагов рефакторинга), которые суммарно привели к регрессу. + Технически ошибка обусловлена не-обнулением переменной, чего не происходило в некотором пути выполнения, так как исходно не требовалось. + Однако, такое обнуление потребовалось после ряда этапов оптимизации и рефакторинга смежных участков кода. + Для подробностей смотрите комментарий коммита `23a417fe19614481c6546845995d6dc845baf797`. + + - Скорректировано описание ошибки `MDBX_MVCC_RETARDED` и текста соответствующего сообщения. + + - В C++ API добавлена упущенная проверка `__cpp_concepts >= 202002` для использования концептов C++. Изменение поведения: - Функция `mdbx_txn_release_all_cursors()` возвращает только код ошибки, не смешивая его с количеством обработанных/закрытых курсоров. Для аналогичных действий с получением количества закрытых курсоров в API добавлена функция `mdbx_txn_release_all_cursors_ex()`. + - Использование системного кода ошибки `EREMOTEIO` ("Remote I/O error") вместо `ENOTBLK` ("Block device required") в качестве `MDBX_EREMOTE` для индикации ошибочной ситуации открытия БД расположенной на сетевом носителе. + + - Для основных вариантов использования шаблона `mdbx::buffer<>` теперь явно инстанцируются внутри библиотеки, + одновременно соответствующие специализации шаблона помечены как `external` для предотвращения повторного инстанцирования в пользовательском коде. + + - Запрещена отвязка/открепление курсоров во вложенных транзакциях, т.е. вызовы `mdbx_cursor_unbind()` и + `mdbx_txn_release_all_cursors(unbind=true)` для курсоров открытых в одной из родительских транзакций. + Причина в том, что в случае отмены вложенной транзакции возникает неконструктивная неопределенность + — следует ли восстанавливать состояние курсоров. Если не восстанавливать, то получается что вложенная транзакция может + поломать родительскую, сделав её продолжение невозможным. Если восстанавливать, то также следует «воскрешать» закрытые + курсоры, что неизбежно приведет к путанице, утечкам памяти и использованию после освобождения. + + - В C++ API отменён вброс исключения при запросе транзакции у отсоединённого курсора посредством вывоза `mdbx::cursor::txn()`. + +Прочие доработки: + + - Доработка использования LTO в CMake-сценариях: использование `-flto=auto` для GCC >= 11.4, + расслабление условий для включения LTO для CLANG на Linux, расширение поиска `LLVMgold.so` в относительных lib-директориях. + + - Добавлены дополнительные проверки сигнатур курсоров при итерации связанных списков. + + - Кратное сокращение итераций тестов в зависимости от конфигурации Valgrind/Debug/CI. + + - Устранены предупреждения UBASN о невыравненном доступе в тесте extra/close-dbi. + + - Добавлен перехват и логирование исключений в extra-тестах на C++. + + - Расширены тесты extra/dupfix-multiple, extra/cursor-closing и extra/txn. + + - В утилиту тестирования добавлена поддержка режима/опции `MDBX_VALIDATION` и поддержка значений `on`/`off` для опций командной строки. + + - Добавлены doxygen-описания для doubtless-positioning констант. + + - Переработана проверка курсоров на входе в API-функций с добавлением `cursor_check()`, `cursor_reset()` и `cursor_drown()`. + + - Отключено использование C23 `[[атрибутов]]` для версий CLANG меньше 20. -------------------------------------------------------------------------------- From 00917f8c96b620dec650585a319dde8d0624dcaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 17:44:49 +0300 Subject: [PATCH 172/181] =?UTF-8?q?mdbx:=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20ChangeLog.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 141b0b65..7250dc72 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -10,7 +10,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx Благодарности: - - [Erigon](https://docs.erigon.tech/) за спонсорство. + - [Erigon](https://erigon.tech/) за спонсорство. - [Alain Picard](https://github.com/castortech) for support [Java bindings](https://github.com/castortech/mdbxjni) and MacOS universal binaries patch for CMake build scenario, also for bug reporting (put-`MDBX_MULTIPLE` regression). Big thank for assistance with debugging and testing. - [Alex Sharov](https://github.com/AskAlexSharov) за сообщение об ошибках и тестирование. From 2e4962a2f3f3b0a0b18e712a345a94826b18a81d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Thu, 20 Mar 2025 21:50:53 +0300 Subject: [PATCH 173/181] =?UTF-8?q?mdbx-docs:=20=D0=B8=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20``=20=D0=B8=20meta-titl?= =?UTF-8?q?e=20=D0=B2=20index.html?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GNUmakefile | 2 +- docs/header.html | 4 ++++ docs/title | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 docs/title diff --git a/GNUmakefile b/GNUmakefile index 46e0d5f7..e14c17bf 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -639,7 +639,7 @@ doxygen: docs/Doxyfile docs/overall.md docs/intro.md docs/usage.md mdbx.h mdbx.h $(QUIET)rm -rf docs/html && \ cat mdbx.h | tr '\n' '\r' | $(SED) -e 's/LIBMDBX_INLINE_API\s*(\s*\([^,]\+\),\s*\([^,]\+\),\s*(\s*\([^)]\+\)\s*)\s*)\s*{/inline \1 \2(\3) {/g' | tr '\r' '\n' >docs/mdbx.h && \ cp mdbx.h++ src/options.h ChangeLog.md docs/ && (cd docs && doxygen Doxyfile $(HUSH)) && cp COPYRIGHT LICENSE NOTICE docs/favicon.ico docs/manifest.webmanifest docs/html/ && \ - $(SED) -i docs/html/index.html -e '/\/MathJax.js"><\/script>/r docs/ld+json' + $(SED) -i docs/html/index.html -e '/\/MathJax.js"><\/script>/r docs/ld+json' -e 's/<title>libmdbx: Overall<\/title>//;T;r docs/title' mdbx++-dylib.o: src/config.h src/mdbx.c++ mdbx.h mdbx.h++ $(lastword $(MAKEFILE_LIST)) @echo ' CC $@' diff --git a/docs/header.html b/docs/header.html index f6827f4e..b39b6664 100644 --- a/docs/header.html +++ b/docs/header.html @@ -8,6 +8,10 @@ <link rel="icon" href="favicon.ico"> <link rel="icon" href="img/bear.png" type="image/png"> <link rel="apple-touch-icon" href="img/bear.png"> +<meta property="og:type" content="article"/> +<meta property="og:url" content="https://libmdbx.dqdkfa.ru/"/> +<meta name="twitter:title" content="One of the fastest embeddable key-value engine"/> +<meta name="twitter:description" content="MDBX surpasses the legendary LMDB in terms of reliability, features and performance. For now libmdbx is chosen by all modern Ethereum frontiers as a storage engine."/> <!--BEGIN PROJECT_NAME--><title>$projectname: $title $title diff --git a/docs/title b/docs/title new file mode 100644 index 00000000..81a24d60 --- /dev/null +++ b/docs/title @@ -0,0 +1,2 @@ +libmdbx: One of the fastest embeddable key-value engine + From 4e33bad6e732ac902de520ddc56e326749d78981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 21 Mar 2025 00:31:54 +0300 Subject: [PATCH 174/181] =?UTF-8?q?mdbx:=20=D0=BE=D1=82=D1=81=D0=B5=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=85=D0=B2=D0=BE=D1=81=D1=82=D0=B0?= =?UTF-8?q?=20ChangeLog=20=D1=81=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=B2=20ChangeLog-01.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChangeLog-01.md | 1067 ++++++++++++++++++++++++++++++++++++++++++++++ ChangeLog.md | 1072 +---------------------------------------------- 2 files changed, 1068 insertions(+), 1071 deletions(-) create mode 100644 ChangeLog-01.md diff --git a/ChangeLog-01.md b/ChangeLog-01.md new file mode 100644 index 00000000..4f3316f5 --- /dev/null +++ b/ChangeLog-01.md @@ -0,0 +1,1067 @@ + + +## v0.11.14 "Sergey Kapitsa" at 2023-02-14 + +The stable bugfix release in memory of [Sergey Kapitsa](https://en.wikipedia.org/wiki/Sergey_Kapitsa) on his 95th birthday. + +``` +22 files changed, 250 insertions(+), 174 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Fixes: + - backport: Fixed insignificant typo of `||` inside `#if` byte-order condition. + - backport: Fixed `SIGSEGV` or an erroneous call to `free()` in situations where + errors occur when reopening by `mdbx_env_open()` of a previously used + environment. + - backport: Fixed `cursor_put_nochecklen()` internals for case when dupsort'ed named subDb + contains a single key with multiple values (aka duplicates), which are replaced + with a single value by put-operation with the `MDBX_UPSERT+MDBX_ALLDUPS` flags. + In this case, the database becomes completely empty, without any pages. + However exactly this condition was not considered and thus wasn't handled correctly. + See [issue#8](https://gitflic.ru/project/erthink/libmdbx/issue/8) for more information. + - backport: Fixed extra assertion inside `override_meta()`, which could + lead to false-positive failing of the assertion in a debug builds during + DB recovery and auto-rollback. + - backport: Refined the `__cold`/`__hot` macros to avoid the + `error: inlining failed in call to ‘always_inline FOO(...)’: target specific option mismatch` + issue during build using GCC >10.x for SH4 arch. + +Minors: + + - backport: Using the https://libmdbx.dqdkfa.ru/dead-github + for resources deleted by the Github' administration. + - backport: Fixed English typos. + - backport: Fixed proto of `__asan_default_options()`. + - backport: Fixed doxygen-description of C++ API, especially of C++20 concepts. + - backport: Refined `const` and `noexcept` for few C++ API methods. + - backport: Fixed copy&paste typo of "Getting started". + - backport: Update MithrilDB status. + - backport: Resolve false-posirive `used uninitialized` warning from GCC >10.x + while build for SH4 arch. + + +-------------------------------------------------------------------------------- + + +## v0.11.13 at "Swashplate" 2022-11-10 + +The stable bugfix release in memory of [Boris Yuryev](https://ru.wikipedia.org/wiki/Юрьев,_Борис_Николаевич) on his 133rd birthday. + +``` +30 files changed, 405 insertions(+), 136 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Fixes: + + - Fixed builds with older libc versions after using `fcntl64()` (backport). + - Fixed builds with older `stdatomic.h` versions, + where the `ATOMIC_*_LOCK_FREE` macros mistakenly redefined using functions (backport). + - Added workaround for `mremap()` defect to avoid assertion failure (backport). + - Workaround for `encryptfs` bug(s) in the `copy_file_range` implementation (backport). + - Fixed unexpected `MDBX_BUSY` from `mdbx_env_set_option()`, `mdbx_env_set_syncbytes()` + and `mdbx_env_set_syncperiod()` (backport). + - CMake requirements lowered to version 3.0.2 (backport). + +Minors: + + - Minor clarification output of `--help` for `mdbx_test` (backport). + - Added admonition of insecure for RISC-V (backport). + - Stochastic scripts and CMake files synchronized with the `devel` branch. + - Use `--dont-check-ram-size` for small-tests make-targets (backport). + + +-------------------------------------------------------------------------------- + + +## v0.11.12 "Эребуни" at 2022-10-12 + +The stable bugfix release. + +``` +11 files changed, 96 insertions(+), 49 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Fixes: + + - Fixed static assertion failure on platforms where the `off_t` type is wider + than corresponding fields of `struct flock` used for file locking (backport). + Now _libmdbx_ will use `fcntl64(F_GETLK64/F_SETLK64/F_SETLKW64)` if available. + - Fixed assertion check inside `page_retire_ex()` (backport). + +Minors: + + - Fixed `-Wint-to-pointer-cast` warnings while casting to `mdbx_tid_t` (backport). + - Removed needless `LockFileEx()` inside `mdbx_env_copy()` (backport). + + +-------------------------------------------------------------------------------- + + +## v0.11.11 "Тендра-1790" at 2022-09-11 + +The stable bugfix release. + +``` +10 files changed, 38 insertions(+), 21 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Fixes: + + - Fixed an extra check for `MDBX_APPENDDUP` inside `mdbx_cursor_put()` which could result in returning `MDBX_EKEYMISMATCH` for valid cases. + - Fixed an extra ensure/assertion check of `oldest_reader` inside `mdbx_txn_end()`. + - Fixed derived C++ builds by removing `MDBX_INTERNAL_FUNC` for `mdbx_w2mb()` and `mdbx_mb2w()`. + + +-------------------------------------------------------------------------------- + + +## v0.11.10 "the TriColor" at 2022-08-22 + +The stable bugfix release. + +``` +14 files changed, 263 insertions(+), 252 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +New: + + - The C++ API has been refined to simplify support for `wchar_t` in path names. + - Added explicit error message for Buildroot's Microblaze toolchain maintainers. + +Fixes: + + - Never use modern `__cxa_thread_atexit()` on Apple's OSes. + - Use `MultiByteToWideChar(CP_THREAD_ACP)` instead of `mbstowcs()`. + - Don't check owner for finished transactions. + - Fixed typo in `MDBX_EINVAL` which breaks MingGW builds with CLANG. + +Minors: + + - Fixed variable name typo. + - Using `ldd` to check used dso. + - Added `MDBX_WEAK_IMPORT_ATTRIBUTE` macro. + - Use current transaction geometry for untouched parameters when `env_set_geometry()` called within a write transaction. + - Minor clarified `iov_page()` failure case. + + +-------------------------------------------------------------------------------- + + +## v0.11.9 "Чирчик-1992" at 2022-08-02 + +The stable bugfix release. + +``` +18 files changed, 318 insertions(+), 178 deletions(-) +Signed-off-by: Леонид Юрьев (Leonid Yuriev) +``` + +Acknowledgments: + + - [Alex Sharov](https://github.com/AskAlexSharov) and Erigon team for reporting and testing. + - [Andrew Ashikhmin](https://gitflic.ru/user/yperbasis) for contributing. + +New: + + - Ability to customise `MDBX_LOCK_SUFFIX`, `MDBX_DATANAME`, `MDBX_LOCKNAME` just by predefine ones during build. + - Added to [`mdbx::env_managed`](https://libmdbx.dqdkfa.ru/group__cxx__api.html#classmdbx_1_1env__managed)'s methods a few overloads with `const char* pathname` parameter (C++ API). + +Fixes: + + - Fixed hang copy-with-compactification of a corrupted DB + or in case the volume of output pages is a multiple of `MDBX_ENVCOPY_WRITEBUF`. + - Fixed standalone non-CMake build on MacOS (`#include AvailabilityMacros.h>`). + - Fixed unexpected `MDBX_PAGE_FULL` error in rare cases with large database page sizes. + +Minors: + + - Minor fixes Doxygen references, comments, descriptions, etc. + - Fixed copy&paste typo inside `meta_checktxnid()`. + - Minor fix `meta_checktxnid()` to avoid assertion in debug mode. + - Minor fix `mdbx_env_set_geometry()` to avoid returning `EINVAL` in particular rare cases. + - Minor refine/fix batch-get testcase for large page size. + - Added `--pagesize NN` option to long-stotastic test script. + - Updated Valgrind-suppressions file for modern GCC. + - Fixed `has no symbols` warning from Apple's ranlib. + + +-------------------------------------------------------------------------------- + + +## v0.11.8 "Baked Apple" at 2022-06-12 + +The stable release with an important fixes and workaround for the critical macOS thread-local-storage issue. + +Acknowledgments: + + - [Masatoshi Fukunaga](https://github.com/mah0x211) for [Lua bindings](https://github.com/mah0x211/lua-libmdbx). + +New: + + - Added most of transactions flags to the public API. + - Added `MDBX_NOSUCCESS_EMPTY_COMMIT` build option to return non-success result (`MDBX_RESULT_TRUE`) on empty commit. + - Reworked validation and import of DBI-handles into a transaction. + Assumes these changes will be invisible to most users, but will cause fewer surprises in complex DBI cases. + - Added ability to open DB in without-LCK (exclusive read-only) mode in case no permissions to create/write LCK-file. + +Fixes: + + - A series of fixes and improvements for automatically generated documentation (Doxygen). + - Fixed copy&paste bug with could lead to `SIGSEGV` (nullptr dereference) in the exclusive/no-lck mode. + - Fixed minor warnings from modern Apple's CLANG 13. + - Fixed minor warnings from CLANG 14 and in-development CLANG 15. + - Fixed `SIGSEGV` regression in without-LCK (exclusive read-only) mode. + - Fixed `mdbx_check_fs_local()` for CDROM case on Windows. + - Fixed nasty typo of typename which caused false `MDBX_CORRUPTED` error in a rare execution path, + when the size of the thread-ID type not equal to 8. + - Fixed Elbrus/E2K LCC 1.26 compiler warnings (memory model for atomic operations, etc). + - Fixed write-after-free memory corruption on latest `macOS` during finalization/cleanup of thread(s) that executed read transaction(s). + > The issue was suddenly discovered by a [CI](https://en.wikipedia.org/wiki/Continuous_integration) + > after adding an iteration with macOS 11 "Big Sur", and then reproduced on recent release of macOS 12 "Monterey". + > The issue was never noticed nor reported on macOS 10 "Catalina" nor others. + > Analysis shown that the problem caused by a change in the behavior of the system library (internals of dyld and pthread) + > during thread finalization/cleanup: now a memory allocated for a `__thread` variable(s) is released + > before execution of the registered Thread-Local-Storage destructor(s), + > thus a TLS-destructor will write-after-free just by legitime dereference any `__thread` variable. + > This is unexpected crazy-like behavior since the order of resources releasing/destroying + > is not the reverse of ones acquiring/construction order. Nonetheless such surprise + > is now workarounded by using atomic compare-and-swap operations on a 64-bit signatures/cookies. + +Minors: + + - Refined `release-assets` GNU Make target. + - Added logging to `mdbx_fetch_sdb()` to help debugging complex DBI-handels use cases. + - Added explicit error message from probe of no-support for `std::filesystem`. + - Added contributors "score" table by `git fame` to generated docs. + - Added `mdbx_assert_fail()` to public API (mostly for backtracing). + - Now C++20 concepts used/enabled only when `__cpp_lib_concepts >= 202002`. + - Don't provide nor report package information if used as a CMake subproject. + + +-------------------------------------------------------------------------------- + + +## v0.11.7 "Resurrected Sarmat" at 2022-04-22 + +The stable risen release after the Github's intentional malicious disaster. + +#### We have migrated to a reliable trusted infrastructure +The origin for now is at [GitFlic](https://gitflic.ru/project/erthink/libmdbx) +since on 2022-04-15 the Github administration, without any warning nor +explanation, deleted _libmdbx_ along with a lot of other projects, +simultaneously blocking access for many developers. +For the same reason ~~Github~~ is blacklisted forever. + +GitFlic already support Russian and English languages, plan to support more, +including 和 中文. You are welcome! + +New: + + - Added the `tools-static` make target to build statically linked MDBX tools. + - Support for Microsoft Visual Studio 2022. + - Support build by MinGW' make from command line without CMake. + - Added `mdbx::filesystem` C++ API namespace that corresponds to `std::filesystem` or `std::experimental::filesystem`. + - Created [website](https://libmdbx.dqdkfa.ru/) for online auto-generated documentation. + - Used `https://web.archive.org/web/https://github.com/erthink/libmdbx` for dead (or temporarily lost) resources deleted by ~~Github~~. + - Added `--loglevel=` command-line option to the `mdbx_test` tool. + - Added few fast smoke-like tests into CMake builds. + +Fixes: + + - Fixed a race between starting a transaction and creating a DBI descriptor that could lead to `SIGSEGV` in the cursor tracking code. + - Clarified description of `MDBX_EPERM` error returned from `mdbx_env_set_geometry()`. + - Fixed non-promoting the parent transaction to be dirty in case the undo of the geometry update failed during abortion of a nested transaction. + - Resolved linking issues with `libstdc++fs`/`libc++fs`/`libc++experimental` for C++ `std::filesystem` or `std::experimental::filesystem` for legacy compilers. + - Added workaround for GNU Make 3.81 and earlier. + - Added workaround for Elbrus/LCC 1.25 compiler bug of class inline `static constexpr` member field. + - [Fixed](https://github.com/ledgerwatch/erigon/issues/3874) minor assertion regression (only debug builds were affected). + - Fixed detection of `C++20` concepts accessibility. + - Fixed detection of Clang's LTO availability for Android. + - Fixed extra definition of `_FILE_OFFSET_BITS=64` for Android that is problematic for 32-bit Bionic. + - Fixed build for ARM/ARM64 by MSVC. + - Fixed non-x86 Windows builds with `MDBX_WITHOUT_MSVC_CRT=ON` and `MDBX_BUILD_SHARED_LIBRARY=ON`. + +Minors: + + - Resolve minor MSVC warnings: avoid `/INCREMENTAL[:YES]` with `/LTCG`, `/W4` with `/W3`, the `C5105` warning. + - Switched to using `MDBX_EPERM` instead of `MDBX_RESULT_TRUE` to indicate that the geometry cannot be updated. + - Added `NULL` checking during memory allocation inside `mdbx_chk`. + - Resolved all warnings from MinGW while used without CMake. + - Added inheritable `target_include_directories()` to `CMakeLists.txt` for easy integration. + - Added build-time checks and paranoid runtime assertions for the `off_t` arguments of `fcntl()` which are used for locking. + - Added `-Wno-lto-type-mismatch` to avoid false-positive warnings from old GCC during LTO-enabled builds. + - Added checking for TID (system thread id) to avoid hang on 32-bit Bionic/Android within `pthread_mutex_lock()`. + - Reworked `MDBX_BUILD_TARGET` of CMake builds. + - Added `CMAKE_HOST_ARCH` and `CMAKE_HOST_CAN_RUN_EXECUTABLES_BUILT_FOR_TARGET`. + + +-------------------------------------------------------------------------------- + + +## v0.11.6 at 2022-03-24 + +The stable release with the complete workaround for an incoherence flaw of Linux unified page/buffer cache. +Nonetheless the cause for this trouble may be an issue of Intel CPU cache/MESI. +See [issue#269](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for more information. + +Acknowledgments: + + - [David Bouyssié](https://github.com/david-bouyssie) for [Scala bindings](https://github.com/david-bouyssie/mdbx4s). + - [Michelangelo Riccobene](https://github.com/mriccobene) for reporting and testing. + +Fixes: + + - [Added complete workaround](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for an incoherence flaw of Linux unified page/buffer cache. + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/272) cursor reusing for read-only transactions. + - Fixed copy&paste typo inside `mdbx::cursor::find_multivalue()`. + +Minors: + + - Minor refine C++ API for convenience. + - Minor internals refines. + - Added `lib-static` and `lib-shared` targets for make. + - Added minor workaround for AppleClang 13.3 bug. + - Clarified error messages of a signature/version mismatch. + + +-------------------------------------------------------------------------------- + + +## v0.11.5 at 2022-02-23 + +The release with the temporary hotfix for a flaw of Linux unified page/buffer cache. +See [issue#269](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for more information. + +Acknowledgments: + + - [Simon Leier](https://github.com/leisim) for reporting and testing. + - [Kai Wetlesen](https://github.com/kaiwetlesen) for [RPMs](http://copr.fedorainfracloud.org/coprs/kwetlesen/libmdbx/). + - [Tullio Canepa](https://github.com/canepat) for reporting C++ API issue and contributing. + +Fixes: + + - [Added hotfix](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for a flaw of Linux unified page/buffer cache. + - [Fixed/Reworked](https://libmdbx.dqdkfa.ru/dead-github/pull/270) move-assignment operators for "managed" classes of C++ API. + - Fixed potential `SIGSEGV` while open DB with overrided non-default page size. + - [Made](https://libmdbx.dqdkfa.ru/dead-github/issues/267) `mdbx_env_open()` idempotence in failure cases. + - Refined/Fixed pages reservation inside `mdbx_update_gc()` to avoid non-reclamation in a rare cases. + - Fixed typo in a retained space calculation for the hsr-callback. + +Minors: + + - Reworked functions for meta-pages, split-off non-volatile. + - Disentangled C11-atomic fences/barriers and pure-functions (with `__attribute__((__pure__))`) to avoid compiler misoptimization. + - Fixed hypotetic unaligned access to 64-bit dwords on ARM with `__ARM_FEATURE_UNALIGNED` defined. + - Reasonable paranoia that makes clarity for code readers. + - Minor fixes Doxygen references, comments, descriptions, etc. + + +-------------------------------------------------------------------------------- + + +## v0.11.4 at 2022-02-02 + +The stable release with fixes for large and huge databases sized of 4..128 TiB. + +Acknowledgments: + + - [Ledgerwatch](https://github.com/ledgerwatch), [Binance](https://github.com/binance-chain) and [Positive Technologies](https://www.ptsecurity.com/) teams for reporting, assistance in investigation and testing. + - [Alex Sharov](https://github.com/AskAlexSharov) for reporting, testing and provide resources for remote debugging/investigation. + - [Kris Zyp](https://github.com/kriszyp) for [Deno](https://deno.land/) support. + +New features, extensions and improvements: + + - Added treating the `UINT64_MAX` value as maximum for given option inside `mdbx_env_set_option()`. + - Added `to_hex/to_base58/to_base64::output(std::ostream&)` overloads without using temporary string objects as buffers. + - Added `--geometry-jitter=YES|no` option to the test framework. + - Added support for [Deno](https://deno.land/) support by [Kris Zyp](https://github.com/kriszyp). + +Fixes: + + - Fixed handling `MDBX_opt_rp_augment_limit` for GC's records from huge transactions (Erigon/Akula/Ethereum). + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/258) build on Android (avoid including `sys/sem.h`). + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/pull/261) missing copy assignment operator for `mdbx::move_result`. + - Fixed missing `&` for `std::ostream &operator<<()` overloads. + - Fixed unexpected `EXDEV` (Cross-device link) error from `mdbx_env_copy()`. + - Fixed base64 encoding/decoding bugs in auxillary C++ API. + - Fixed overflow of `pgno_t` during checking PNL on 64-bit platforms. + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/260) excessive PNL checking after sort for spilling. + - Reworked checking `MAX_PAGENO` and DB upper-size geometry limit. + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/265) build for some combinations of versions of MSVC and Windows SDK. + +Minors: + + - Added workaround for CLANG bug [D79919/PR42445](https://reviews.llvm.org/D79919). + - Fixed build test on Android (using `pthread_barrier_t` stub). + - Disabled C++20 concepts for CLANG < 14 on Android. + - Fixed minor `unused parameter` warning. + - Added CI for Android. + - Refine/cleanup internal logging. + - Refined line splitting inside hex/base58/base64 encoding to avoid `\n` at the end. + - Added workaround for modern libstdc++ with CLANG < 4.x + - Relaxed txn-check rules for auxiliary functions. + - Clarified a comments and descriptions, etc. + - Using the `-fno-semantic interposition` option to reduce the overhead to calling self own public functions. + + +-------------------------------------------------------------------------------- + + +## v0.11.3 at 2021-12-31 + +Acknowledgments: + + - [gcxfd ](https://github.com/gcxfd) for reporting, contributing and testing. + - [장세연 (Чан Се Ен)](https://github.com/sasgas) for reporting and testing. + - [Alex Sharov](https://github.com/AskAlexSharov) for reporting, testing and provide resources for remote debugging/investigation. + +New features, extensions and improvements: + + - [Added](https://libmdbx.dqdkfa.ru/dead-github/issues/236) `mdbx_cursor_get_batch()`. + - [Added](https://libmdbx.dqdkfa.ru/dead-github/issues/250) `MDBX_SET_UPPERBOUND`. + - C++ API is finalized now. + - The GC update stage has been [significantly speeded](https://libmdbx.dqdkfa.ru/dead-github/issues/254) when fixing huge Erigon's transactions (Ethereum ecosystem). + +Fixes: + + - Disabled C++20 concepts for stupid AppleClang 13.x + - Fixed internal collision of `MDBX_SHRINK_ALLOWED` with `MDBX_ACCEDE`. + +Minors: + + - Fixed returning `MDBX_RESULT_TRUE` (unexpected -1) from `mdbx_env_set_option()`. + - Added `mdbx_env_get_syncbytes()` and `mdbx_env_get_syncperiod()`. + - [Clarified](https://libmdbx.dqdkfa.ru/dead-github/pull/249) description of `MDBX_INTEGERKEY`. + - Reworked/simplified `mdbx_env_sync_internal()`. + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/248) extra assertion inside `mdbx_cursor_put()` for `MDBX_DUPFIXED` cases. + - Avoiding extra looping inside `mdbx_env_info_ex()`. + - Explicitly enabled core dumps from stochastic tests scripts on Linux. + - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/253) `mdbx_override_meta()` to avoid false-positive assertions. + - For compatibility reverted returning `MDBX_ENODATA`for some cases. + + +-------------------------------------------------------------------------------- + + +## v0.11.2 at 2021-12-02 + +Acknowledgments: + + - [장세연 (Чан Се Ен)](https://github.com/sasgas) for contributing to C++ API. + - [Alain Picard](https://github.com/castortech) for [Java bindings](https://github.com/castortech/mdbxjni). + - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing. + - [Kris Zyp](https://github.com/kriszyp) for reporting and testing. + - [Artem Vorotnikov](https://github.com/vorot93) for support [Rust wrapper](https://github.com/vorot93/libmdbx-rs). + +Fixes: + + - [Fixed compilation](https://libmdbx.dqdkfa.ru/dead-github/pull/239) with `devtoolset-9` on CentOS/RHEL 7. + - [Fixed unexpected `MDBX_PROBLEM` error](https://libmdbx.dqdkfa.ru/dead-github/issues/242) because of update an obsolete meta-page. + - [Fixed returning `MDBX_NOTFOUND` error](https://libmdbx.dqdkfa.ru/dead-github/issues/243) in case an inexact value found for `MDBX_GET_BOTH` operation. + - [Fixed compilation](https://libmdbx.dqdkfa.ru/dead-github/issues/245) without kernel/libc-devel headers. + +Minors: + + - Fixed `constexpr`-related macros for legacy compilers. + - Allowed to define 'CMAKE_CXX_STANDARD` using an environment variable. + - Simplified collection statistics of page operation . + - Added `MDBX_FORCE_BUILD_AS_MAIN_PROJECT` cmake option. + - Remove unneeded `#undef P_DIRTY`. + + +-------------------------------------------------------------------------------- + + +## v0.11.1 at 2021-10-23 + +### Backward compatibility break: + +The database format signature has been changed to prevent +forward-interoperability with an previous releases, which may lead to a +[false positive diagnosis of database corruption](https://libmdbx.dqdkfa.ru/dead-github/issues/238) +due to flaws of an old library versions. + +This change is mostly invisible: + + - previously versions are unable to read/write a new DBs; + - but the new release is able to handle an old DBs and will silently upgrade ones. + +Acknowledgments: + + - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing. + + +******************************************************************************** + + +## v0.10.5 at 2021-10-13 (obsolete, please use v0.11.1) + +Unfortunately, the `v0.10.5` accidentally comes not full-compatible with previous releases: + + - `v0.10.5` can read/processing DBs created by previous releases, i.e. the backward-compatibility is provided; + - however, previous releases may lead to false-corrupted state with DB that was touched by `v0.10.5`, i.e. the forward-compatibility is broken for `v0.10.4` and earlier. + +This cannot be fixed, as it requires fixing past versions, which as a result we will just get a current version. +Therefore, it is recommended to use `v0.11.1` instead of `v0.10.5`. + +Acknowledgments: + + - [Noel Kuntze](https://github.com/Thermi) for immediately bug reporting. + +Fixes: + + - Fixed unaligned access regression after the `#pragma pack` fix for modern compilers. + - Added UBSAN-test to CI to avoid a regression(s) similar to lately fixed. + - Fixed possibility of meta-pages clashing after manually turn to a particular meta-page using `mdbx_chk` utility. + +Minors: + + - Refined handling of weak or invalid meta-pages while a DB opening. + - Refined providing information for the `@MAIN` and `@GC` sub-databases of a last committed modification transaction's ID. + + +-------------------------------------------------------------------------------- + + +## v0.10.4 at 2021-10-10 + +Acknowledgments: + + - [Artem Vorotnikov](https://github.com/vorot93) for support [Rust wrapper](https://github.com/vorot93/libmdbx-rs). + - [Andrew Ashikhmin](https://github.com/yperbasis) for contributing to C++ API. + +Fixes: + + - Fixed possibility of looping update GC during transaction commit (no public issue since the problem was discovered inside [Positive Technologies](https://www.ptsecurity.ru)). + - Fixed `#pragma pack` to avoid provoking some compilers to generate code with [unaligned access](https://libmdbx.dqdkfa.ru/dead-github/issues/235). + - Fixed `noexcept` for potentially throwing `txn::put()` of C++ API. + +Minors: + + - Added stochastic test script for checking small transactions cases. + - Removed extra transaction commit/restart inside test framework. + - In debugging builds fixed a too small (single page) by default DB shrink threshold. + + +-------------------------------------------------------------------------------- + + +## v0.10.3 at 2021-08-27 + +Acknowledgments: + + - [Francisco Vallarino](https://github.com/fjvallarino) for [Haskell bindings for libmdbx](https://hackage.haskell.org/package/libmdbx). + - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing. + - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for contributing. + +Extensions and improvements: + + - Added `cursor::erase()` overloads for `key` and for `key-value`. + - Resolve minor Coverity Scan issues (no fixes but some hint/comment were added). + - Resolve minor UndefinedBehaviorSanitizer issues (no fixes but some workaround were added). + +Fixes: + + - Always setup `madvise` while opening DB (fixes https://libmdbx.dqdkfa.ru/dead-github/issues/231). + - Fixed checking legacy `P_DIRTY` flag (`0x10`) for nested/sub-pages. + +Minors: + + - Fixed getting revision number from middle of history during amalgamation (GNU Makefile). + - Fixed search GCC tools for LTO (CMake scripts). + - Fixed/reorder dirs list for search CLANG tools for LTO (CMake scripts). + - Fixed/workarounds for CLANG < 9.x + - Fixed CMake warning about compatibility with 3.8.2 + + +-------------------------------------------------------------------------------- + + +## v0.10.2 at 2021-07-26 + +Acknowledgments: + + - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing. + - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for reporting bugs. + - [Lionel Debroux](https://github.com/debrouxl) for fuzzing tests and reporting bugs. + - [Sergey Fedotov](https://github.com/SergeyFromHell/) for [`node-mdbx` NodeJS bindings](https://www.npmjs.com/package/node-mdbx). + - [Kris Zyp](https://github.com/kriszyp) for [`lmdbx-store` NodeJS bindings](https://github.com/kriszyp/lmdbx-store). + - [Noel Kuntze](https://github.com/Thermi) for [draft Python bindings](https://libmdbx.dqdkfa.ru/dead-github/commits/python-bindings). + +New features, extensions and improvements: + + - [Allow to predefine/override `MDBX_BUILD_TIMESTAMP` for builds reproducibility](https://libmdbx.dqdkfa.ru/dead-github/issues/201). + - Added options support for `long-stochastic` script. + - Avoided `MDBX_TXN_FULL` error for large transactions when possible. + - The `MDBX_READERS_LIMIT` increased to `32767`. + - Raise `MDBX_TOO_LARGE` under Valgrind/ASAN if being opened DB is 100 larger than RAM (to avoid hangs and OOM). + - Minimized the size of poisoned/unpoisoned regions to avoid Valgrind/ASAN stuck. + - Added more workarounds for QEMU for testing builds for 32-bit platforms, Alpha and Sparc architectures. + - `mdbx_chk` now skips iteration & checking of DB' records if corresponding page-tree is corrupted (to avoid `SIGSEGV`, ASAN failures, etc). + - Added more checks for [rare/fuzzing corruption cases](https://libmdbx.dqdkfa.ru/dead-github/issues/217). + +Backward compatibility break: + + - Use file `VERSION.txt` for version information instead of `VERSION` to avoid collision with `#include `. + - Rename `slice::from/to_FOO_bytes()` to `slice::envisage_from/to_FOO_length()'. + - Rename `MDBX_TEST_EXTRA` make's variable to `MDBX_SMOKE_EXTRA`. + - Some details of the C++ API have been changed for subsequent freezing. + +Fixes: + + - Fixed excess meta-pages checks in case `mdbx_chk` is called to check the DB for a specific meta page and thus could prevent switching to the selected meta page, even if the check passed without errors. + - Fixed [recursive use of SRW-lock on Windows cause by `MDBX_NOTLS` option](https://libmdbx.dqdkfa.ru/dead-github/issues/203). + - Fixed [log a warning during a new DB creation](https://libmdbx.dqdkfa.ru/dead-github/issues/205). + - Fixed [false-negative `mdbx_cursor_eof()` result](https://libmdbx.dqdkfa.ru/dead-github/issues/207). + - Fixed [`make install` with non-GNU `install` utility (OSX, BSD)](https://libmdbx.dqdkfa.ru/dead-github/issues/208). + - Fixed [installation by `CMake` in special cases by complete use `GNUInstallDirs`'s variables](https://libmdbx.dqdkfa.ru/dead-github/issues/209). + - Fixed [C++ Buffer issue with `std::string` and alignment](https://libmdbx.dqdkfa.ru/dead-github/issues/191). + - Fixed `safe64_reset()` for platforms without atomic 64-bit compare-and-swap. + - Fixed hang/shutdown on big-endian platforms without `__cxa_thread_atexit()`. + - Fixed [using bad meta-pages if DB was partially/recoverable corrupted](https://libmdbx.dqdkfa.ru/dead-github/issues/217). + - Fixed extra `noexcept` for `buffer::&assign_reference()`. + - Fixed `bootid` generation on Windows for case of change system' time. + - Fixed [test framework keygen-related issue](https://libmdbx.dqdkfa.ru/dead-github/issues/127). + + +-------------------------------------------------------------------------------- + + +## v0.10.1 at 2021-06-01 + +Acknowledgments: + + - [Alexey Akhunov](https://github.com/AlexeyAkhunov) and [Alex Sharov](https://github.com/AskAlexSharov) for bug reporting and testing. + - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for bug reporting and testing related to WSL2. + +New features: + + - Added `-p` option to `mdbx_stat` utility for printing page operations statistic. + - Added explicit checking for and warning about using unfit github's archives. + - Added fallback from [OFD locking](https://bit.ly/3yFRtYC) to legacy non-OFD POSIX file locks on an `EINVAL` error. + - Added [Plan 9](https://en.wikipedia.org/wiki/9P_(protocol)) network file system to the whitelist for an ability to open a DB in exclusive mode. + - Support for opening from WSL2 environment a DB hosted on Windows drive and mounted via [DrvFs](https://docs.microsoft.com/it-it/archive/blogs/wsl/wsl-file-system-support#drvfs) (i.e by Plan 9 noted above). + +Fixes: + + - Fixed minor "foo not used" warnings from modern C++ compilers when building the C++ part of the library. + - Fixed confusing/messy errors when build library from unfit github's archives (https://libmdbx.dqdkfa.ru/dead-github/issues/197). + - Fixed `#​e​l​s​i​f` typo. + - Fixed rare unexpected `MDBX_PROBLEM` error during altering data in huge transactions due to wrong spilling/oust of dirty pages (https://libmdbx.dqdkfa.ru/dead-github/issues/195). + - Re-Fixed WSL1/WSL2 detection with distinguishing (https://libmdbx.dqdkfa.ru/dead-github/issues/97). + + +-------------------------------------------------------------------------------- + + +## v0.10.0 at 2021-05-09 + +Acknowledgments: + + - [Mahlon E. Smith](https://github.com/mahlonsmith) for [Ruby bindings](https://rubygems.org/gems/mdbx/). + - [Alex Sharov](https://github.com/AskAlexSharov) for [mdbx-go](https://github.com/torquem-ch/mdbx-go), bug reporting and testing. + - [Artem Vorotnikov](https://github.com/vorot93) for bug reporting and PR. + - [Paolo Rebuffo](https://www.linkedin.com/in/paolo-rebuffo-8255766/), [Alexey Akhunov](https://github.com/AlexeyAkhunov) and Mark Grosberg for donations. + - [Noel Kuntze](https://github.com/Thermi) for preliminary [Python bindings](https://github.com/Thermi/libmdbx/tree/python-bindings) + +New features: + + - Added `mdbx_env_set_option()` and `mdbx_env_get_option()` for controls + various runtime options for an environment (announce of this feature was missed in a previous news). + - Added `MDBX_DISABLE_PAGECHECKS` build option to disable some checks to reduce an overhead + and detection probability of database corruption to a values closer to the LMDB. + The `MDBX_DISABLE_PAGECHECKS=1` provides a performance boost of about 10% in CRUD scenarios, + and conjointly with the `MDBX_ENV_CHECKPID=0` and `MDBX_TXN_CHECKOWNER=0` options can yield + up to 30% more performance compared to LMDB. + - Using float point (exponential quantized) representation for internal 16-bit values + of grow step and shrink threshold when huge ones (https://libmdbx.dqdkfa.ru/dead-github/issues/166). + To minimize the impact on compatibility, only the odd values inside the upper half + of the range (i.e. 32769..65533) are used for the new representation. + - Added the `mdbx_drop` similar to LMDB command-line tool to purge or delete (sub)database(s). + - [Ruby bindings](https://rubygems.org/gems/mdbx/) is available now by [Mahlon E. Smith](https://github.com/mahlonsmith). + - Added `MDBX_ENABLE_MADVISE` build option which controls the use of POSIX `madvise()` hints and friends. + - The internal node sizes were refined, resulting in a reduction in large/overflow pages in some use cases + and a slight increase in limits for a keys size to ≈½ of page size. + - Added to `mdbx_chk` output number of keys/items on pages. + - Added explicit `install-strip` and `install-no-strip` targets to the `Makefile` (https://libmdbx.dqdkfa.ru/dead-github/pull/180). + - Major rework page splitting (af9b7b560505684249b76730997f9e00614b8113) for + - An "auto-appending" feature upon insertion for both ascending and + descending key sequences. As a result, the optimality of page filling + increases significantly (more densely, less slackness) while + inserting ordered sequences of keys, + - A "splitting at middle" to make page tree more balanced on average. + - Added `mdbx_get_sysraminfo()` to the API. + - Added guessing a reasonable maximum DB size for the default upper limit of geometry (https://libmdbx.dqdkfa.ru/dead-github/issues/183). + - Major rework internal labeling of a dirty pages (958fd5b9479f52f2124ab7e83c6b18b04b0e7dda) for + a "transparent spilling" feature with the gist to make a dirty pages + be ready to spilling (writing to a disk) without further altering ones. + Thus in the `MDBX_WRITEMAP` mode the OS kernel able to oust dirty pages + to DB file without further penalty during transaction commit. + As a result, page swapping and I/O could be significantly reduced during extra large transactions and/or lack of memory. + - Minimized reading leaf-pages during dropping subDB(s) and nested trees. + - Major rework a spilling of dirty pages to support [LRU](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)) + policy and prioritization for a large/overflow pages. + - Statistics of page operations (split, merge, copy, spill, etc) now available through `mdbx_env_info_ex()`. + - Auto-setup limit for length of dirty pages list (`MDBX_opt_txn_dp_limit` option). + - Support `make options` to list available build options. + - Support `make help` to list available make targets. + - Silently `make`'s build by default. + - Preliminary [Python bindings](https://github.com/Thermi/libmdbx/tree/python-bindings) is available now + by [Noel Kuntze](https://github.com/Thermi) (https://libmdbx.dqdkfa.ru/dead-github/issues/147). + +Backward compatibility break: + + - The `MDBX_AVOID_CRT` build option was renamed to `MDBX_WITHOUT_MSVC_CRT`. + This option is only relevant when building for Windows. + - The `mdbx_env_stat()` always, and `mdbx_env_stat_ex()` when called with the zeroed transaction parameter, + now internally start temporary read transaction and thus may returns `MDBX_BAD_RSLOT` error. + So, just never use deprecated `mdbx_env_stat()' and call `mdbx_env_stat_ex()` with transaction parameter. + - The build option `MDBX_CONFIG_MANUAL_TLS_CALLBACK` was removed and now just a non-zero value of + the `MDBX_MANUAL_MODULE_HANDLER` macro indicates the requirement to manually call `mdbx_module_handler()` + when loading libraries and applications uses statically linked libmdbx on an obsolete Windows versions. + +Fixes: + + - Fixed performance regression due non-optimal C11 atomics usage (https://libmdbx.dqdkfa.ru/dead-github/issues/160). + - Fixed "reincarnation" of subDB after it deletion (https://libmdbx.dqdkfa.ru/dead-github/issues/168). + - Fixed (disallowing) implicit subDB deletion via operations on `@MAIN`'s DBI-handle. + - Fixed a crash of `mdbx_env_info_ex()` in case of a call for a non-open environment (https://libmdbx.dqdkfa.ru/dead-github/issues/171). + - Fixed the selecting/adjustment values inside `mdbx_env_set_geometry()` for implicit out-of-range cases (https://libmdbx.dqdkfa.ru/dead-github/issues/170). + - Fixed `mdbx_env_set_option()` for set initial and limit size of dirty page list ((https://libmdbx.dqdkfa.ru/dead-github/issues/179). + - Fixed an unreasonably huge default upper limit for DB geometry (https://libmdbx.dqdkfa.ru/dead-github/issues/183). + - Fixed `constexpr` specifier for the `slice::invalid()`. + - Fixed (no)readahead auto-handling (https://libmdbx.dqdkfa.ru/dead-github/issues/164). + - Fixed non-alloy build for Windows. + - Switched to using Heap-functions instead of LocalAlloc/LocalFree on Windows. + - Fixed `mdbx_env_stat_ex()` to returning statistics of the whole environment instead of MainDB only (https://libmdbx.dqdkfa.ru/dead-github/issues/190). + - Fixed building by GCC 4.8.5 (added workaround for a preprocessor's bug). + - Fixed building C++ part for iOS <= 13.0 (unavailability of `std::filesystem::path`). + - Fixed building for Windows target versions prior to Windows Vista (`WIN32_WINNT < 0x0600`). + - Fixed building by MinGW for Windows (https://libmdbx.dqdkfa.ru/dead-github/issues/155). + + +******************************************************************************** + + +## v0.9.3 at 2021-02-02 + +Acknowledgments: + + - [Mahlon E. Smith](http://www.martini.nu/) for [FreeBSD port of libmdbx](https://svnweb.freebsd.org/ports/head/databases/mdbx/). + - [장세연](http://www.castis.com) for bug fixing and PR. + - [Clément Renault](https://github.com/Kerollmops/heed) for [Heed](https://github.com/Kerollmops/heed) fully typed Rust wrapper. + - [Alex Sharov](https://github.com/AskAlexSharov) for bug reporting. + - [Noel Kuntze](https://github.com/Thermi) for bug reporting. + +Removed options and features: + + - Drop `MDBX_HUGE_TRANSACTIONS` build-option (now no longer required). + +New features: + + - Package for FreeBSD is available now by Mahlon E. Smith. + - New API functions to get/set various options (https://libmdbx.dqdkfa.ru/dead-github/issues/128): + - the maximum number of named databases for the environment; + - the maximum number of threads/reader slots; + - threshold (since the last unsteady commit) to force flush the data buffers to disk; + - relative period (since the last unsteady commit) to force flush the data buffers to disk; + - limit to grow a list of reclaimed/recycled page's numbers for finding a sequence of contiguous pages for large data items; + - limit to grow a cache of dirty pages for reuse in the current transaction; + - limit of a pre-allocated memory items for dirty pages; + - limit of dirty pages for a write transaction; + - initial allocation size for dirty pages list of a write transaction; + - maximal part of the dirty pages may be spilled when necessary; + - minimal part of the dirty pages should be spilled when necessary; + - how much of the parent transaction dirty pages will be spilled while start each child transaction; + - Unlimited/Dynamic size of retired and dirty page lists (https://libmdbx.dqdkfa.ru/dead-github/issues/123). + - Added `-p` option (purge subDB before loading) to `mdbx_load` tool. + - Reworked spilling of large transaction and committing of nested transactions: + - page spilling code reworked to avoid the flaws and bugs inherited from LMDB; + - limit for number of dirty pages now is controllable at runtime; + - a spilled pages, including overflow/large pages, now can be reused and refunded/compactified in nested transactions; + - more effective refunding/compactification especially for the loosed page cache. + - Added `MDBX_ENABLE_REFUND` and `MDBX_PNL_ASCENDING` internal/advanced build options. + - Added `mdbx_default_pagesize()` function. + - Better support architectures with a weak/relaxed memory consistency model (ARM, AARCH64, PPC, MIPS, RISC-V, etc) by means [C11 atomics](https://en.cppreference.com/w/c/atomic). + - Speed up page number lists and dirty page lists (https://libmdbx.dqdkfa.ru/dead-github/issues/132). + - Added `LIBMDBX_NO_EXPORTS_LEGACY_API` build option. + +Fixes: + + - Fixed missing cleanup (null assigned) in the C++ commit/abort (https://libmdbx.dqdkfa.ru/dead-github/pull/143). + - Fixed `mdbx_realloc()` for case of nullptr and `MDBX_WITHOUT_MSVC_CRT=ON` for Windows. + - Fixed the possibility to use invalid and renewed (closed & re-opened, dropped & re-created) DBI-handles (https://libmdbx.dqdkfa.ru/dead-github/issues/146). + - Fixed 4-byte aligned access to 64-bit integers, including access to the `bootid` meta-page's field (https://libmdbx.dqdkfa.ru/dead-github/issues/153). + - Fixed minor/potential memory leak during page flushing and unspilling. + - Fixed handling states of cursors's and subDBs's for nested transactions. + - Fixed page leak in extra rare case the list of retired pages changed during update GC on transaction commit. + - Fixed assertions to avoid false-positive UB detection by CLANG/LLVM (https://libmdbx.dqdkfa.ru/dead-github/issues/153). + - Fixed `MDBX_TXN_FULL` and regressive `MDBX_KEYEXIST` during large transaction commit with `MDBX_LIFORECLAIM` (https://libmdbx.dqdkfa.ru/dead-github/issues/123). + - Fixed auto-recovery (`weak->steady` with the same boot-id) when Database size at last weak checkpoint is large than at last steady checkpoint. + - Fixed operation on systems with unusual small/large page size, including PowerPC (https://libmdbx.dqdkfa.ru/dead-github/issues/157). + + +-------------------------------------------------------------------------------- + + +## v0.9.2 at 2020-11-27 + +Acknowledgments: + + - Jens Alfke (Mobile Architect at [Couchbase](https://www.couchbase.com/)) for [NimDBX](https://github.com/snej/nimdbx). + - Clément Renault (CTO at [MeiliSearch](https://www.meilisearch.com/)) for [mdbx-rs](https://github.com/Kerollmops/mdbx-rs). + - Alex Sharov (Go-Lang Teach Lead at [TurboGeth/Ethereum](https://ethereum.org/)) for an extreme test cases and bug reporting. + - George Hazan (CTO at [Miranda NG](https://www.miranda-ng.org/)) for bug reporting. + - [Positive Technologies](https://www.ptsecurity.com/) for funding and [The Standoff](https://standoff365.com/). + +Added features: + + - Provided package for [buildroot](https://buildroot.org/). + - Binding for Nim is [available](https://github.com/snej/nimdbx) now by Jens Alfke. + - Added `mdbx_env_delete()` for deletion an environment files in a proper and multiprocess-safe way. + - Added `mdbx_txn_commit_ex()` with collecting latency information. + - Fast completion pure nested transactions. + - Added `LIBMDBX_INLINE_API` macro and inline versions of some API functions. + - Added `mdbx_cursor_copy()` function. + - Extended tests for checking cursor tracking. + - Added `MDBX_SET_LOWERBOUND` operation for `mdbx_cursor_get()`. + +Fixes: + + - Fixed missing installation of `mdbx.h++`. + - Fixed use of obsolete `__noreturn`. + - Fixed use of `yield` instruction on ARM if unsupported. + - Added pthread workaround for buggy toolchain/cmake/buildroot. + - Fixed use of `pthread_yield()` for non-GLIBC. + - Fixed use of `RegGetValueA()` on Windows 2000/XP. + - Fixed use of `GetTickCount64()` on Windows 2000/XP. + - Fixed opening DB on a network shares (in the exclusive mode). + - Fixed copy&paste typos. + - Fixed minor false-positive GCC warning. + - Added workaround for broken `DEFINE_ENUM_FLAG_OPERATORS` from Windows SDK. + - Fixed cursor state after multimap/dupsort repeated deletes (https://libmdbx.dqdkfa.ru/dead-github/issues/121). + - Added `SIGPIPE` suppression for internal thread during `mdbx_env_copy()`. + - Fixed extra-rare `MDBX_KEY_EXIST` error during `mdbx_commit()` (https://libmdbx.dqdkfa.ru/dead-github/issues/131). + - Fixed spilled pages checking (https://libmdbx.dqdkfa.ru/dead-github/issues/126). + - Fixed `mdbx_load` for 'plain text' and without `-s name` cases (https://libmdbx.dqdkfa.ru/dead-github/issues/136). + - Fixed save/restore/commit of cursors for nested transactions. + - Fixed cursors state in rare/special cases (move next beyond end-of-data, after deletion and so on). + - Added workaround for MSVC 19.28 (Visual Studio 16.8) (but may still hang during compilation). + - Fixed paranoidal Clang C++ UB for bitwise operations with flags defined by enums. + - Fixed large pages checking (for compatibility and to avoid false-positive errors from `mdbx_chk`). + - Added workaround for Wine (https://github.com/miranda-ng/miranda-ng/issues/1209). + - Fixed `ERROR_NOT_SUPPORTED` while opening DB by UNC pathnames (https://github.com/miranda-ng/miranda-ng/issues/2627). + - Added handling `EXCEPTION_POSSIBLE_DEADLOCK` condition for Windows. + + +-------------------------------------------------------------------------------- + + +## v0.9.1 2020-09-30 + +Added features: + + - Preliminary C++ API with support for C++17 polymorphic allocators. + - [Online C++ API reference](https://libmdbx.dqdkfa.ru/) by Doxygen. + - Quick reference for Insert/Update/Delete operations. + - Explicit `MDBX_SYNC_DURABLE` to sync modes for API clarity. + - Explicit `MDBX_ALLDUPS` and `MDBX_UPSERT` for API clarity. + - Support for read transactions preparation (`MDBX_TXN_RDONLY_PREPARE` flag). + - Support for cursor preparation/(pre)allocation and reusing (`mdbx_cursor_create()` and `mdbx_cursor_bind()` functions). + - Support for checking database using specified meta-page (see `mdbx_chk -h`). + - Support for turn to the specific meta-page after checking (see `mdbx_chk -h`). + - Support for explicit reader threads (de)registration. + - The `mdbx_txn_break()` function to explicitly mark a transaction as broken. + - Improved handling of corrupted databases by `mdbx_chk` utility and `mdbx_walk_tree()` function. + - Improved DB corruption detection by checking parent-page-txnid. + - Improved opening large DB (> 4Gb) from 32-bit code. + - Provided `pure-function` and `const-function` attributes to C API. + - Support for user-settable context for transactions & cursors. + - Revised API and documentation related to Handle-Slow-Readers callback feature. + +Deprecated functions and flags: + + - For clarity and API simplification the `MDBX_MAPASYNC` flag is deprecated. + Just use `MDBX_SAFE_NOSYNC` or `MDBX_UTTERLY_NOSYNC` instead of it. + - `MDBX_oom_func`, `mdbx_env_set_oomfunc()` and `mdbx_env_get_oomfunc()` + replaced with `MDBX_hsr_func`, `mdbx_env_get_hsr` and `mdbx_env_get_hsr()`. + +Fixes: + + - Fix `mdbx_strerror()` for `MDBX_BUSY` error (no error description is returned). + - Fix update internal meta-geo information in read-only mode (`EACCESS` or `EBADFD` error). + - Fix `mdbx_page_get()` null-defer when DB corrupted (crash by `SIGSEGV`). + - Fix `mdbx_env_open()` for re-opening after non-fatal errors (`mdbx_chk` unexpected failures). + - Workaround for MSVC 19.27 `static_assert()` bug. + - Doxygen descriptions and refinement. + - Update Valgrind's suppressions. + - Workaround to avoid infinite loop of 'nested' testcase on MIPS under QEMU. + - Fix a lot of typos & spelling (Thanks to Josh Soref for PR). + - Fix `getopt()` messages for Windows (Thanks to Andrey Sporaw for reporting). + - Fix MSVC compiler version requirements (Thanks to Andrey Sporaw for reporting). + - Workarounds for QEMU's bugs to run tests for cross-built[A library under QEMU. + - Now C++ compiler optional for building by CMake. + + +-------------------------------------------------------------------------------- + + +## v0.9.0 2020-07-31 (not a release, but API changes) + +Added features: + + - [Online C API reference](https://libmdbx.dqdkfa.ru/) by Doxygen. + - Separated enums for environment, sub-databases, transactions, copying and data-update flags. + +Deprecated functions and flags: + + - Usage of custom comparators and the `mdbx_dbi_open_ex()` are deprecated, since such databases couldn't be checked by the `mdbx_chk` utility. + Please use the value-to-key functions to provide keys that are compatible with the built-in libmdbx comparators. + + +******************************************************************************** + + +## 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. + - Added key-to-value, `mdbx_get_keycmp()` and `mdbx_get_datacmp()` functions (helpful to avoid using custom comparators). + - Added `ENABLE_UBSAN` CMake option to enabling the UndefinedBehaviorSanitizer from GCC/CLANG. + - Workaround for [CLANG bug](https://bugs.llvm.org/show_bug.cgi?id=43275). + - Returning `MDBX_CORRUPTED` in case all meta-pages are weak and no other error. + - Refined mode bits while auto-creating LCK-file. + - Avoids unnecessary database file re-mapping in case geometry changed by another process(es). + From the user's point of view, the `MDBX_UNABLE_EXTEND_MAPSIZE` error will now be returned less frequently and only when using the DB in the current process really requires it to be reopened. + - Remapping on-the-fly and of the database file was implemented. + Now remapping with a change of address is performed automatically if there are no dependent readers in the current process. + + +## 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. + - Fix `mdbx_env_set_geometry()` for case it is called from an opened environment outside of a write transaction. + - Add support for huge transactions and `MDBX_HUGE_TRANSACTIONS` build-option (default `OFF`). + - Refine LTO (link time optimization) for clang. + - Force enabling exceptions handling for MSVC (`/EHsc` option). + + +## 2020-06-05 + + - Support for Android/Bionic. + - Support for iOS. + - Auto-handling `MDBX_NOSUBDIR` while opening for any existing database. + - Engage github-actions to make release-assets. + - Clarify API description. + - Extended keygen-cases in stochastic test. + - Fix fetching of first/lower key from LEAF2-page during page merge. + - Fix missing comma in array of error messages. + - Fix div-by-zero while copy-with-compaction for non-resizable environments. + - Fixes & enhancements for custom-comparators. + - Fix `MDBX_WITHOUT_MSVC_CRT` option and missing `ntdll.def`. + - Fix `mdbx_env_close()` to work correctly called concurrently from several threads. + - Fix null-deref in an ASAN-enabled builds while opening the environment with error and/or read-only. + - Fix AddressSanitizer errors after closing the environment. + - Fix/workaround to avoid GCC 10.x pedantic warnings. + - Fix using `ENODATA` for FreeBSD. + - Avoid invalidation of DBI-handle(s) when it just closes. + - Avoid using `pwritev()` for single-writes (up to 10% speedup for some kernels & scenarios). + - Avoiding `MDBX_UTTERLY_NOSYNC` as result of flags merge. + - Add `mdbx_dbi_dupsort_depthmask()` function. + - Add `MDBX_CP_FORCE_RESIZABLE` option. + - Add deprecated `MDBX_MAP_RESIZED` for compatibility. + - Add `MDBX_BUILD_TOOLS` option (default `ON`). + - Refine `mdbx_dbi_open_ex()` to safe concurrently opening the same handle from different threads. + - Truncate clk-file during environment closing. So a zero-length lck-file indicates that the environment was closed properly. + - Refine `mdbx_update_gc()` for huge transactions with small sizes of database page. + - Extends dump/load to support all MDBX attributes. + - Avoid upsertion the same key-value data, fix related assertions. + - Rework min/max length checking for keys & values. + - Checking the order of keys on all pages during checking. + - Support `CFLAGS_EXTRA` make-option for convenience. + - Preserve the last txnid while copying with compactification. + - Auto-reset running transaction in mdbx_txn_renew(). + - Automatically abort errored transaction in mdbx_txn_commit(). + - Auto-choose page size for large databases. + - Rearrange source files, rework build, options-support by CMake. + - Crutch for WSL1 (Windows subsystem for Linux). + - Refine install/uninstall targets. + - Support for Valgrind 3.14 and later. + - Add check-analyzer check-ubsan check-asan check-leak targets to Makefile. + - Minor fix/workaround to avoid UBSAN traps for `memcpy(ptr, NULL, 0)`. + - Avoid some GCC-analyzer false-positive warnings. + + +## 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. + - Speedup runtime checks in debug/checked builds. + - Added checking for read/write transactions overlapping for the same thread, added `MDBX_TXN_OVERLAPPING` error and `MDBX_DBG_LEGACY_OVERLAP` option. + - Added `mdbx_key_from_jsonInteger()`, `mdbx_key_from_double()`, `mdbx_key_from_float()`, `mdbx_key_from_int64()` and `mdbx_key_from_int32()` functions. See `mdbx.h` for description. + - Fix compatibility (use zero for invalid DBI). + - Refine/clarify error messages. + - Avoids extra error messages "bad txn" from mdbx_chk when DB is corrupted. + + +## 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. + - Refine/fix handling `STATUS_CONFLICTING_ADDRESSES`. + - Rework `MDBX_DBG_DUMP` option to avoid disk I/O performance degradation. + - Add built-in help to test tool. + - Fix `mdbx_env_set_geometry()` for large page size. + - Fix env_set_geometry() for large pagesize. + - Clarify API description & comments, fix typos. + + +## 2019-12-31 + + - Fix returning MDBX_RESULT_TRUE from page_alloc(). + - Fix false-positive ASAN issue. + - Fix assertion for `MDBX_NOTLS` option. + - Rework `MADV_DONTNEED` threshold. + - Fix `mdbx_chk` utility for don't checking some numbers if walking on the B-tree was disabled. + - Use page's mp_txnid for basic integrity checking. + - Add `MDBX_FORCE_ASSERTIONS` build-time option. + - Rework `MDBX_DBG_DUMP` to avoid performance degradation. + - Rename `MDBX_NOSYNC` to `MDBX_SAFE_NOSYNC` for clarity. + - Interpret `ERROR_ACCESS_DENIED` from `OpenProcess()` as 'process exists'. + - Avoid using `FILE_FLAG_NO_BUFFERING` for compatibility with small database pages. + - Added install section for CMake. + + +## 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. + - Add `MDBX_ACCEDE` flag for database opening. + - Using OFD-locks and tracking for in-process multi-opening. + - Hot backup into pipe. + - Support for cmake & amalgamated sources. + - Fastest internal sort implementation. + - New internal dirty-list implementation with lazy sorting. + - Support for lazy-sync-to-disk with polling. + - Extended key length. + - Last update transaction number for each sub-database. + - Automatic read ahead enabling/disabling. + - More auto-compactification. + - Using -fsanitize=undefined and -Wpedantic options. + - Rework page merging. + - Nested transactions. + - API description. + - Checking for non-local filesystems to avoid DB corruption. + + diff --git a/ChangeLog.md b/ChangeLog.md index bf15663a..a4911bfb 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1717,1076 +1717,6 @@ Fixes: Not a release but preparation for changing feature set and API. - ******************************************************************************** - -## v0.11.14 "Sergey Kapitsa" at 2023-02-14 - -The stable bugfix release in memory of [Sergey Kapitsa](https://en.wikipedia.org/wiki/Sergey_Kapitsa) on his 95th birthday. - -``` -22 files changed, 250 insertions(+), 174 deletions(-) -Signed-off-by: Леонид Юрьев (Leonid Yuriev) -``` - -Fixes: - - backport: Fixed insignificant typo of `||` inside `#if` byte-order condition. - - backport: Fixed `SIGSEGV` or an erroneous call to `free()` in situations where - errors occur when reopening by `mdbx_env_open()` of a previously used - environment. - - backport: Fixed `cursor_put_nochecklen()` internals for case when dupsort'ed named subDb - contains a single key with multiple values (aka duplicates), which are replaced - with a single value by put-operation with the `MDBX_UPSERT+MDBX_ALLDUPS` flags. - In this case, the database becomes completely empty, without any pages. - However exactly this condition was not considered and thus wasn't handled correctly. - See [issue#8](https://gitflic.ru/project/erthink/libmdbx/issue/8) for more information. - - backport: Fixed extra assertion inside `override_meta()`, which could - lead to false-positive failing of the assertion in a debug builds during - DB recovery and auto-rollback. - - backport: Refined the `__cold`/`__hot` macros to avoid the - `error: inlining failed in call to ‘always_inline FOO(...)’: target specific option mismatch` - issue during build using GCC >10.x for SH4 arch. - -Minors: - - - backport: Using the https://libmdbx.dqdkfa.ru/dead-github - for resources deleted by the Github' administration. - - backport: Fixed English typos. - - backport: Fixed proto of `__asan_default_options()`. - - backport: Fixed doxygen-description of C++ API, especially of C++20 concepts. - - backport: Refined `const` and `noexcept` for few C++ API methods. - - backport: Fixed copy&paste typo of "Getting started". - - backport: Update MithrilDB status. - - backport: Resolve false-posirive `used uninitialized` warning from GCC >10.x - while build for SH4 arch. - - --------------------------------------------------------------------------------- - - -## v0.11.13 at "Swashplate" 2022-11-10 - -The stable bugfix release in memory of [Boris Yuryev](https://ru.wikipedia.org/wiki/Юрьев,_Борис_Николаевич) on his 133rd birthday. - -``` -30 files changed, 405 insertions(+), 136 deletions(-) -Signed-off-by: Леонид Юрьев (Leonid Yuriev) -``` - -Fixes: - - - Fixed builds with older libc versions after using `fcntl64()` (backport). - - Fixed builds with older `stdatomic.h` versions, - where the `ATOMIC_*_LOCK_FREE` macros mistakenly redefined using functions (backport). - - Added workaround for `mremap()` defect to avoid assertion failure (backport). - - Workaround for `encryptfs` bug(s) in the `copy_file_range` implementation (backport). - - Fixed unexpected `MDBX_BUSY` from `mdbx_env_set_option()`, `mdbx_env_set_syncbytes()` - and `mdbx_env_set_syncperiod()` (backport). - - CMake requirements lowered to version 3.0.2 (backport). - -Minors: - - - Minor clarification output of `--help` for `mdbx_test` (backport). - - Added admonition of insecure for RISC-V (backport). - - Stochastic scripts and CMake files synchronized with the `devel` branch. - - Use `--dont-check-ram-size` for small-tests make-targets (backport). - - --------------------------------------------------------------------------------- - - -## v0.11.12 "Эребуни" at 2022-10-12 - -The stable bugfix release. - -``` -11 files changed, 96 insertions(+), 49 deletions(-) -Signed-off-by: Леонид Юрьев (Leonid Yuriev) -``` - -Fixes: - - - Fixed static assertion failure on platforms where the `off_t` type is wider - than corresponding fields of `struct flock` used for file locking (backport). - Now _libmdbx_ will use `fcntl64(F_GETLK64/F_SETLK64/F_SETLKW64)` if available. - - Fixed assertion check inside `page_retire_ex()` (backport). - -Minors: - - - Fixed `-Wint-to-pointer-cast` warnings while casting to `mdbx_tid_t` (backport). - - Removed needless `LockFileEx()` inside `mdbx_env_copy()` (backport). - - --------------------------------------------------------------------------------- - - -## v0.11.11 "Тендра-1790" at 2022-09-11 - -The stable bugfix release. - -``` -10 files changed, 38 insertions(+), 21 deletions(-) -Signed-off-by: Леонид Юрьев (Leonid Yuriev) -``` - -Fixes: - - - Fixed an extra check for `MDBX_APPENDDUP` inside `mdbx_cursor_put()` which could result in returning `MDBX_EKEYMISMATCH` for valid cases. - - Fixed an extra ensure/assertion check of `oldest_reader` inside `mdbx_txn_end()`. - - Fixed derived C++ builds by removing `MDBX_INTERNAL_FUNC` for `mdbx_w2mb()` and `mdbx_mb2w()`. - - --------------------------------------------------------------------------------- - - -## v0.11.10 "the TriColor" at 2022-08-22 - -The stable bugfix release. - -``` -14 files changed, 263 insertions(+), 252 deletions(-) -Signed-off-by: Леонид Юрьев (Leonid Yuriev) -``` - -New: - - - The C++ API has been refined to simplify support for `wchar_t` in path names. - - Added explicit error message for Buildroot's Microblaze toolchain maintainers. - -Fixes: - - - Never use modern `__cxa_thread_atexit()` on Apple's OSes. - - Use `MultiByteToWideChar(CP_THREAD_ACP)` instead of `mbstowcs()`. - - Don't check owner for finished transactions. - - Fixed typo in `MDBX_EINVAL` which breaks MingGW builds with CLANG. - -Minors: - - - Fixed variable name typo. - - Using `ldd` to check used dso. - - Added `MDBX_WEAK_IMPORT_ATTRIBUTE` macro. - - Use current transaction geometry for untouched parameters when `env_set_geometry()` called within a write transaction. - - Minor clarified `iov_page()` failure case. - - --------------------------------------------------------------------------------- - - -## v0.11.9 "Чирчик-1992" at 2022-08-02 - -The stable bugfix release. - -``` -18 files changed, 318 insertions(+), 178 deletions(-) -Signed-off-by: Леонид Юрьев (Leonid Yuriev) -``` - -Acknowledgments: - - - [Alex Sharov](https://github.com/AskAlexSharov) and Erigon team for reporting and testing. - - [Andrew Ashikhmin](https://gitflic.ru/user/yperbasis) for contributing. - -New: - - - Ability to customise `MDBX_LOCK_SUFFIX`, `MDBX_DATANAME`, `MDBX_LOCKNAME` just by predefine ones during build. - - Added to [`mdbx::env_managed`](https://libmdbx.dqdkfa.ru/group__cxx__api.html#classmdbx_1_1env__managed)'s methods a few overloads with `const char* pathname` parameter (C++ API). - -Fixes: - - - Fixed hang copy-with-compactification of a corrupted DB - or in case the volume of output pages is a multiple of `MDBX_ENVCOPY_WRITEBUF`. - - Fixed standalone non-CMake build on MacOS (`#include AvailabilityMacros.h>`). - - Fixed unexpected `MDBX_PAGE_FULL` error in rare cases with large database page sizes. - -Minors: - - - Minor fixes Doxygen references, comments, descriptions, etc. - - Fixed copy&paste typo inside `meta_checktxnid()`. - - Minor fix `meta_checktxnid()` to avoid assertion in debug mode. - - Minor fix `mdbx_env_set_geometry()` to avoid returning `EINVAL` in particular rare cases. - - Minor refine/fix batch-get testcase for large page size. - - Added `--pagesize NN` option to long-stotastic test script. - - Updated Valgrind-suppressions file for modern GCC. - - Fixed `has no symbols` warning from Apple's ranlib. - - --------------------------------------------------------------------------------- - - -## v0.11.8 "Baked Apple" at 2022-06-12 - -The stable release with an important fixes and workaround for the critical macOS thread-local-storage issue. - -Acknowledgments: - - - [Masatoshi Fukunaga](https://github.com/mah0x211) for [Lua bindings](https://github.com/mah0x211/lua-libmdbx). - -New: - - - Added most of transactions flags to the public API. - - Added `MDBX_NOSUCCESS_EMPTY_COMMIT` build option to return non-success result (`MDBX_RESULT_TRUE`) on empty commit. - - Reworked validation and import of DBI-handles into a transaction. - Assumes these changes will be invisible to most users, but will cause fewer surprises in complex DBI cases. - - Added ability to open DB in without-LCK (exclusive read-only) mode in case no permissions to create/write LCK-file. - -Fixes: - - - A series of fixes and improvements for automatically generated documentation (Doxygen). - - Fixed copy&paste bug with could lead to `SIGSEGV` (nullptr dereference) in the exclusive/no-lck mode. - - Fixed minor warnings from modern Apple's CLANG 13. - - Fixed minor warnings from CLANG 14 and in-development CLANG 15. - - Fixed `SIGSEGV` regression in without-LCK (exclusive read-only) mode. - - Fixed `mdbx_check_fs_local()` for CDROM case on Windows. - - Fixed nasty typo of typename which caused false `MDBX_CORRUPTED` error in a rare execution path, - when the size of the thread-ID type not equal to 8. - - Fixed Elbrus/E2K LCC 1.26 compiler warnings (memory model for atomic operations, etc). - - Fixed write-after-free memory corruption on latest `macOS` during finalization/cleanup of thread(s) that executed read transaction(s). - > The issue was suddenly discovered by a [CI](https://en.wikipedia.org/wiki/Continuous_integration) - > after adding an iteration with macOS 11 "Big Sur", and then reproduced on recent release of macOS 12 "Monterey". - > The issue was never noticed nor reported on macOS 10 "Catalina" nor others. - > Analysis shown that the problem caused by a change in the behavior of the system library (internals of dyld and pthread) - > during thread finalization/cleanup: now a memory allocated for a `__thread` variable(s) is released - > before execution of the registered Thread-Local-Storage destructor(s), - > thus a TLS-destructor will write-after-free just by legitime dereference any `__thread` variable. - > This is unexpected crazy-like behavior since the order of resources releasing/destroying - > is not the reverse of ones acquiring/construction order. Nonetheless such surprise - > is now workarounded by using atomic compare-and-swap operations on a 64-bit signatures/cookies. - -Minors: - - - Refined `release-assets` GNU Make target. - - Added logging to `mdbx_fetch_sdb()` to help debugging complex DBI-handels use cases. - - Added explicit error message from probe of no-support for `std::filesystem`. - - Added contributors "score" table by `git fame` to generated docs. - - Added `mdbx_assert_fail()` to public API (mostly for backtracing). - - Now C++20 concepts used/enabled only when `__cpp_lib_concepts >= 202002`. - - Don't provide nor report package information if used as a CMake subproject. - - --------------------------------------------------------------------------------- - - -## v0.11.7 "Resurrected Sarmat" at 2022-04-22 - -The stable risen release after the Github's intentional malicious disaster. - -#### We have migrated to a reliable trusted infrastructure -The origin for now is at [GitFlic](https://gitflic.ru/project/erthink/libmdbx) -since on 2022-04-15 the Github administration, without any warning nor -explanation, deleted _libmdbx_ along with a lot of other projects, -simultaneously blocking access for many developers. -For the same reason ~~Github~~ is blacklisted forever. - -GitFlic already support Russian and English languages, plan to support more, -including 和 中文. You are welcome! - -New: - - - Added the `tools-static` make target to build statically linked MDBX tools. - - Support for Microsoft Visual Studio 2022. - - Support build by MinGW' make from command line without CMake. - - Added `mdbx::filesystem` C++ API namespace that corresponds to `std::filesystem` or `std::experimental::filesystem`. - - Created [website](https://libmdbx.dqdkfa.ru/) for online auto-generated documentation. - - Used `https://web.archive.org/web/https://github.com/erthink/libmdbx` for dead (or temporarily lost) resources deleted by ~~Github~~. - - Added `--loglevel=` command-line option to the `mdbx_test` tool. - - Added few fast smoke-like tests into CMake builds. - -Fixes: - - - Fixed a race between starting a transaction and creating a DBI descriptor that could lead to `SIGSEGV` in the cursor tracking code. - - Clarified description of `MDBX_EPERM` error returned from `mdbx_env_set_geometry()`. - - Fixed non-promoting the parent transaction to be dirty in case the undo of the geometry update failed during abortion of a nested transaction. - - Resolved linking issues with `libstdc++fs`/`libc++fs`/`libc++experimental` for C++ `std::filesystem` or `std::experimental::filesystem` for legacy compilers. - - Added workaround for GNU Make 3.81 and earlier. - - Added workaround for Elbrus/LCC 1.25 compiler bug of class inline `static constexpr` member field. - - [Fixed](https://github.com/ledgerwatch/erigon/issues/3874) minor assertion regression (only debug builds were affected). - - Fixed detection of `C++20` concepts accessibility. - - Fixed detection of Clang's LTO availability for Android. - - Fixed extra definition of `_FILE_OFFSET_BITS=64` for Android that is problematic for 32-bit Bionic. - - Fixed build for ARM/ARM64 by MSVC. - - Fixed non-x86 Windows builds with `MDBX_WITHOUT_MSVC_CRT=ON` and `MDBX_BUILD_SHARED_LIBRARY=ON`. - -Minors: - - - Resolve minor MSVC warnings: avoid `/INCREMENTAL[:YES]` with `/LTCG`, `/W4` with `/W3`, the `C5105` warning. - - Switched to using `MDBX_EPERM` instead of `MDBX_RESULT_TRUE` to indicate that the geometry cannot be updated. - - Added `NULL` checking during memory allocation inside `mdbx_chk`. - - Resolved all warnings from MinGW while used without CMake. - - Added inheritable `target_include_directories()` to `CMakeLists.txt` for easy integration. - - Added build-time checks and paranoid runtime assertions for the `off_t` arguments of `fcntl()` which are used for locking. - - Added `-Wno-lto-type-mismatch` to avoid false-positive warnings from old GCC during LTO-enabled builds. - - Added checking for TID (system thread id) to avoid hang on 32-bit Bionic/Android within `pthread_mutex_lock()`. - - Reworked `MDBX_BUILD_TARGET` of CMake builds. - - Added `CMAKE_HOST_ARCH` and `CMAKE_HOST_CAN_RUN_EXECUTABLES_BUILT_FOR_TARGET`. - - --------------------------------------------------------------------------------- - - -## v0.11.6 at 2022-03-24 - -The stable release with the complete workaround for an incoherence flaw of Linux unified page/buffer cache. -Nonetheless the cause for this trouble may be an issue of Intel CPU cache/MESI. -See [issue#269](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for more information. - -Acknowledgments: - - - [David Bouyssié](https://github.com/david-bouyssie) for [Scala bindings](https://github.com/david-bouyssie/mdbx4s). - - [Michelangelo Riccobene](https://github.com/mriccobene) for reporting and testing. - -Fixes: - - - [Added complete workaround](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for an incoherence flaw of Linux unified page/buffer cache. - - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/272) cursor reusing for read-only transactions. - - Fixed copy&paste typo inside `mdbx::cursor::find_multivalue()`. - -Minors: - - - Minor refine C++ API for convenience. - - Minor internals refines. - - Added `lib-static` and `lib-shared` targets for make. - - Added minor workaround for AppleClang 13.3 bug. - - Clarified error messages of a signature/version mismatch. - - --------------------------------------------------------------------------------- - - -## v0.11.5 at 2022-02-23 - -The release with the temporary hotfix for a flaw of Linux unified page/buffer cache. -See [issue#269](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for more information. - -Acknowledgments: - - - [Simon Leier](https://github.com/leisim) for reporting and testing. - - [Kai Wetlesen](https://github.com/kaiwetlesen) for [RPMs](http://copr.fedorainfracloud.org/coprs/kwetlesen/libmdbx/). - - [Tullio Canepa](https://github.com/canepat) for reporting C++ API issue and contributing. - -Fixes: - - - [Added hotfix](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for a flaw of Linux unified page/buffer cache. - - [Fixed/Reworked](https://libmdbx.dqdkfa.ru/dead-github/pull/270) move-assignment operators for "managed" classes of C++ API. - - Fixed potential `SIGSEGV` while open DB with overrided non-default page size. - - [Made](https://libmdbx.dqdkfa.ru/dead-github/issues/267) `mdbx_env_open()` idempotence in failure cases. - - Refined/Fixed pages reservation inside `mdbx_update_gc()` to avoid non-reclamation in a rare cases. - - Fixed typo in a retained space calculation for the hsr-callback. - -Minors: - - - Reworked functions for meta-pages, split-off non-volatile. - - Disentangled C11-atomic fences/barriers and pure-functions (with `__attribute__((__pure__))`) to avoid compiler misoptimization. - - Fixed hypotetic unaligned access to 64-bit dwords on ARM with `__ARM_FEATURE_UNALIGNED` defined. - - Reasonable paranoia that makes clarity for code readers. - - Minor fixes Doxygen references, comments, descriptions, etc. - - --------------------------------------------------------------------------------- - - -## v0.11.4 at 2022-02-02 - -The stable release with fixes for large and huge databases sized of 4..128 TiB. - -Acknowledgments: - - - [Ledgerwatch](https://github.com/ledgerwatch), [Binance](https://github.com/binance-chain) and [Positive Technologies](https://www.ptsecurity.com/) teams for reporting, assistance in investigation and testing. - - [Alex Sharov](https://github.com/AskAlexSharov) for reporting, testing and provide resources for remote debugging/investigation. - - [Kris Zyp](https://github.com/kriszyp) for [Deno](https://deno.land/) support. - -New features, extensions and improvements: - - - Added treating the `UINT64_MAX` value as maximum for given option inside `mdbx_env_set_option()`. - - Added `to_hex/to_base58/to_base64::output(std::ostream&)` overloads without using temporary string objects as buffers. - - Added `--geometry-jitter=YES|no` option to the test framework. - - Added support for [Deno](https://deno.land/) support by [Kris Zyp](https://github.com/kriszyp). - -Fixes: - - - Fixed handling `MDBX_opt_rp_augment_limit` for GC's records from huge transactions (Erigon/Akula/Ethereum). - - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/258) build on Android (avoid including `sys/sem.h`). - - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/pull/261) missing copy assignment operator for `mdbx::move_result`. - - Fixed missing `&` for `std::ostream &operator<<()` overloads. - - Fixed unexpected `EXDEV` (Cross-device link) error from `mdbx_env_copy()`. - - Fixed base64 encoding/decoding bugs in auxillary C++ API. - - Fixed overflow of `pgno_t` during checking PNL on 64-bit platforms. - - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/260) excessive PNL checking after sort for spilling. - - Reworked checking `MAX_PAGENO` and DB upper-size geometry limit. - - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/265) build for some combinations of versions of MSVC and Windows SDK. - -Minors: - - - Added workaround for CLANG bug [D79919/PR42445](https://reviews.llvm.org/D79919). - - Fixed build test on Android (using `pthread_barrier_t` stub). - - Disabled C++20 concepts for CLANG < 14 on Android. - - Fixed minor `unused parameter` warning. - - Added CI for Android. - - Refine/cleanup internal logging. - - Refined line splitting inside hex/base58/base64 encoding to avoid `\n` at the end. - - Added workaround for modern libstdc++ with CLANG < 4.x - - Relaxed txn-check rules for auxiliary functions. - - Clarified a comments and descriptions, etc. - - Using the `-fno-semantic interposition` option to reduce the overhead to calling self own public functions. - - --------------------------------------------------------------------------------- - - -## v0.11.3 at 2021-12-31 - -Acknowledgments: - - - [gcxfd ](https://github.com/gcxfd) for reporting, contributing and testing. - - [장세연 (Чан Се Ен)](https://github.com/sasgas) for reporting and testing. - - [Alex Sharov](https://github.com/AskAlexSharov) for reporting, testing and provide resources for remote debugging/investigation. - -New features, extensions and improvements: - - - [Added](https://libmdbx.dqdkfa.ru/dead-github/issues/236) `mdbx_cursor_get_batch()`. - - [Added](https://libmdbx.dqdkfa.ru/dead-github/issues/250) `MDBX_SET_UPPERBOUND`. - - C++ API is finalized now. - - The GC update stage has been [significantly speeded](https://libmdbx.dqdkfa.ru/dead-github/issues/254) when fixing huge Erigon's transactions (Ethereum ecosystem). - -Fixes: - - - Disabled C++20 concepts for stupid AppleClang 13.x - - Fixed internal collision of `MDBX_SHRINK_ALLOWED` with `MDBX_ACCEDE`. - -Minors: - - - Fixed returning `MDBX_RESULT_TRUE` (unexpected -1) from `mdbx_env_set_option()`. - - Added `mdbx_env_get_syncbytes()` and `mdbx_env_get_syncperiod()`. - - [Clarified](https://libmdbx.dqdkfa.ru/dead-github/pull/249) description of `MDBX_INTEGERKEY`. - - Reworked/simplified `mdbx_env_sync_internal()`. - - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/248) extra assertion inside `mdbx_cursor_put()` for `MDBX_DUPFIXED` cases. - - Avoiding extra looping inside `mdbx_env_info_ex()`. - - Explicitly enabled core dumps from stochastic tests scripts on Linux. - - [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/253) `mdbx_override_meta()` to avoid false-positive assertions. - - For compatibility reverted returning `MDBX_ENODATA`for some cases. - - --------------------------------------------------------------------------------- - - -## v0.11.2 at 2021-12-02 - -Acknowledgments: - - - [장세연 (Чан Се Ен)](https://github.com/sasgas) for contributing to C++ API. - - [Alain Picard](https://github.com/castortech) for [Java bindings](https://github.com/castortech/mdbxjni). - - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing. - - [Kris Zyp](https://github.com/kriszyp) for reporting and testing. - - [Artem Vorotnikov](https://github.com/vorot93) for support [Rust wrapper](https://github.com/vorot93/libmdbx-rs). - -Fixes: - - - [Fixed compilation](https://libmdbx.dqdkfa.ru/dead-github/pull/239) with `devtoolset-9` on CentOS/RHEL 7. - - [Fixed unexpected `MDBX_PROBLEM` error](https://libmdbx.dqdkfa.ru/dead-github/issues/242) because of update an obsolete meta-page. - - [Fixed returning `MDBX_NOTFOUND` error](https://libmdbx.dqdkfa.ru/dead-github/issues/243) in case an inexact value found for `MDBX_GET_BOTH` operation. - - [Fixed compilation](https://libmdbx.dqdkfa.ru/dead-github/issues/245) without kernel/libc-devel headers. - -Minors: - - - Fixed `constexpr`-related macros for legacy compilers. - - Allowed to define 'CMAKE_CXX_STANDARD` using an environment variable. - - Simplified collection statistics of page operation . - - Added `MDBX_FORCE_BUILD_AS_MAIN_PROJECT` cmake option. - - Remove unneeded `#undef P_DIRTY`. - - --------------------------------------------------------------------------------- - - -## v0.11.1 at 2021-10-23 - -### Backward compatibility break: - -The database format signature has been changed to prevent -forward-interoperability with an previous releases, which may lead to a -[false positive diagnosis of database corruption](https://libmdbx.dqdkfa.ru/dead-github/issues/238) -due to flaws of an old library versions. - -This change is mostly invisible: - - - previously versions are unable to read/write a new DBs; - - but the new release is able to handle an old DBs and will silently upgrade ones. - -Acknowledgments: - - - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing. - - -******************************************************************************** - - -## v0.10.5 at 2021-10-13 (obsolete, please use v0.11.1) - -Unfortunately, the `v0.10.5` accidentally comes not full-compatible with previous releases: - - - `v0.10.5` can read/processing DBs created by previous releases, i.e. the backward-compatibility is provided; - - however, previous releases may lead to false-corrupted state with DB that was touched by `v0.10.5`, i.e. the forward-compatibility is broken for `v0.10.4` and earlier. - -This cannot be fixed, as it requires fixing past versions, which as a result we will just get a current version. -Therefore, it is recommended to use `v0.11.1` instead of `v0.10.5`. - -Acknowledgments: - - - [Noel Kuntze](https://github.com/Thermi) for immediately bug reporting. - -Fixes: - - - Fixed unaligned access regression after the `#pragma pack` fix for modern compilers. - - Added UBSAN-test to CI to avoid a regression(s) similar to lately fixed. - - Fixed possibility of meta-pages clashing after manually turn to a particular meta-page using `mdbx_chk` utility. - -Minors: - - - Refined handling of weak or invalid meta-pages while a DB opening. - - Refined providing information for the `@MAIN` and `@GC` sub-databases of a last committed modification transaction's ID. - - --------------------------------------------------------------------------------- - - -## v0.10.4 at 2021-10-10 - -Acknowledgments: - - - [Artem Vorotnikov](https://github.com/vorot93) for support [Rust wrapper](https://github.com/vorot93/libmdbx-rs). - - [Andrew Ashikhmin](https://github.com/yperbasis) for contributing to C++ API. - -Fixes: - - - Fixed possibility of looping update GC during transaction commit (no public issue since the problem was discovered inside [Positive Technologies](https://www.ptsecurity.ru)). - - Fixed `#pragma pack` to avoid provoking some compilers to generate code with [unaligned access](https://libmdbx.dqdkfa.ru/dead-github/issues/235). - - Fixed `noexcept` for potentially throwing `txn::put()` of C++ API. - -Minors: - - - Added stochastic test script for checking small transactions cases. - - Removed extra transaction commit/restart inside test framework. - - In debugging builds fixed a too small (single page) by default DB shrink threshold. - - --------------------------------------------------------------------------------- - - -## v0.10.3 at 2021-08-27 - -Acknowledgments: - - - [Francisco Vallarino](https://github.com/fjvallarino) for [Haskell bindings for libmdbx](https://hackage.haskell.org/package/libmdbx). - - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing. - - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for contributing. - -Extensions and improvements: - - - Added `cursor::erase()` overloads for `key` and for `key-value`. - - Resolve minor Coverity Scan issues (no fixes but some hint/comment were added). - - Resolve minor UndefinedBehaviorSanitizer issues (no fixes but some workaround were added). - -Fixes: - - - Always setup `madvise` while opening DB (fixes https://libmdbx.dqdkfa.ru/dead-github/issues/231). - - Fixed checking legacy `P_DIRTY` flag (`0x10`) for nested/sub-pages. - -Minors: - - - Fixed getting revision number from middle of history during amalgamation (GNU Makefile). - - Fixed search GCC tools for LTO (CMake scripts). - - Fixed/reorder dirs list for search CLANG tools for LTO (CMake scripts). - - Fixed/workarounds for CLANG < 9.x - - Fixed CMake warning about compatibility with 3.8.2 - - --------------------------------------------------------------------------------- - - -## v0.10.2 at 2021-07-26 - -Acknowledgments: - - - [Alex Sharov](https://github.com/AskAlexSharov) for reporting and testing. - - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for reporting bugs. - - [Lionel Debroux](https://github.com/debrouxl) for fuzzing tests and reporting bugs. - - [Sergey Fedotov](https://github.com/SergeyFromHell/) for [`node-mdbx` NodeJS bindings](https://www.npmjs.com/package/node-mdbx). - - [Kris Zyp](https://github.com/kriszyp) for [`lmdbx-store` NodeJS bindings](https://github.com/kriszyp/lmdbx-store). - - [Noel Kuntze](https://github.com/Thermi) for [draft Python bindings](https://libmdbx.dqdkfa.ru/dead-github/commits/python-bindings). - -New features, extensions and improvements: - - - [Allow to predefine/override `MDBX_BUILD_TIMESTAMP` for builds reproducibility](https://libmdbx.dqdkfa.ru/dead-github/issues/201). - - Added options support for `long-stochastic` script. - - Avoided `MDBX_TXN_FULL` error for large transactions when possible. - - The `MDBX_READERS_LIMIT` increased to `32767`. - - Raise `MDBX_TOO_LARGE` under Valgrind/ASAN if being opened DB is 100 larger than RAM (to avoid hangs and OOM). - - Minimized the size of poisoned/unpoisoned regions to avoid Valgrind/ASAN stuck. - - Added more workarounds for QEMU for testing builds for 32-bit platforms, Alpha and Sparc architectures. - - `mdbx_chk` now skips iteration & checking of DB' records if corresponding page-tree is corrupted (to avoid `SIGSEGV`, ASAN failures, etc). - - Added more checks for [rare/fuzzing corruption cases](https://libmdbx.dqdkfa.ru/dead-github/issues/217). - -Backward compatibility break: - - - Use file `VERSION.txt` for version information instead of `VERSION` to avoid collision with `#include `. - - Rename `slice::from/to_FOO_bytes()` to `slice::envisage_from/to_FOO_length()'. - - Rename `MDBX_TEST_EXTRA` make's variable to `MDBX_SMOKE_EXTRA`. - - Some details of the C++ API have been changed for subsequent freezing. - -Fixes: - - - Fixed excess meta-pages checks in case `mdbx_chk` is called to check the DB for a specific meta page and thus could prevent switching to the selected meta page, even if the check passed without errors. - - Fixed [recursive use of SRW-lock on Windows cause by `MDBX_NOTLS` option](https://libmdbx.dqdkfa.ru/dead-github/issues/203). - - Fixed [log a warning during a new DB creation](https://libmdbx.dqdkfa.ru/dead-github/issues/205). - - Fixed [false-negative `mdbx_cursor_eof()` result](https://libmdbx.dqdkfa.ru/dead-github/issues/207). - - Fixed [`make install` with non-GNU `install` utility (OSX, BSD)](https://libmdbx.dqdkfa.ru/dead-github/issues/208). - - Fixed [installation by `CMake` in special cases by complete use `GNUInstallDirs`'s variables](https://libmdbx.dqdkfa.ru/dead-github/issues/209). - - Fixed [C++ Buffer issue with `std::string` and alignment](https://libmdbx.dqdkfa.ru/dead-github/issues/191). - - Fixed `safe64_reset()` for platforms without atomic 64-bit compare-and-swap. - - Fixed hang/shutdown on big-endian platforms without `__cxa_thread_atexit()`. - - Fixed [using bad meta-pages if DB was partially/recoverable corrupted](https://libmdbx.dqdkfa.ru/dead-github/issues/217). - - Fixed extra `noexcept` for `buffer::&assign_reference()`. - - Fixed `bootid` generation on Windows for case of change system' time. - - Fixed [test framework keygen-related issue](https://libmdbx.dqdkfa.ru/dead-github/issues/127). - - --------------------------------------------------------------------------------- - - -## v0.10.1 at 2021-06-01 - -Acknowledgments: - - - [Alexey Akhunov](https://github.com/AlexeyAkhunov) and [Alex Sharov](https://github.com/AskAlexSharov) for bug reporting and testing. - - [Andrea Lanfranchi](https://github.com/AndreaLanfranchi) for bug reporting and testing related to WSL2. - -New features: - - - Added `-p` option to `mdbx_stat` utility for printing page operations statistic. - - Added explicit checking for and warning about using unfit github's archives. - - Added fallback from [OFD locking](https://bit.ly/3yFRtYC) to legacy non-OFD POSIX file locks on an `EINVAL` error. - - Added [Plan 9](https://en.wikipedia.org/wiki/9P_(protocol)) network file system to the whitelist for an ability to open a DB in exclusive mode. - - Support for opening from WSL2 environment a DB hosted on Windows drive and mounted via [DrvFs](https://docs.microsoft.com/it-it/archive/blogs/wsl/wsl-file-system-support#drvfs) (i.e by Plan 9 noted above). - -Fixes: - - - Fixed minor "foo not used" warnings from modern C++ compilers when building the C++ part of the library. - - Fixed confusing/messy errors when build library from unfit github's archives (https://libmdbx.dqdkfa.ru/dead-github/issues/197). - - Fixed `#​e​l​s​i​f` typo. - - Fixed rare unexpected `MDBX_PROBLEM` error during altering data in huge transactions due to wrong spilling/oust of dirty pages (https://libmdbx.dqdkfa.ru/dead-github/issues/195). - - Re-Fixed WSL1/WSL2 detection with distinguishing (https://libmdbx.dqdkfa.ru/dead-github/issues/97). - - --------------------------------------------------------------------------------- - - -## v0.10.0 at 2021-05-09 - -Acknowledgments: - - - [Mahlon E. Smith](https://github.com/mahlonsmith) for [Ruby bindings](https://rubygems.org/gems/mdbx/). - - [Alex Sharov](https://github.com/AskAlexSharov) for [mdbx-go](https://github.com/torquem-ch/mdbx-go), bug reporting and testing. - - [Artem Vorotnikov](https://github.com/vorot93) for bug reporting and PR. - - [Paolo Rebuffo](https://www.linkedin.com/in/paolo-rebuffo-8255766/), [Alexey Akhunov](https://github.com/AlexeyAkhunov) and Mark Grosberg for donations. - - [Noel Kuntze](https://github.com/Thermi) for preliminary [Python bindings](https://github.com/Thermi/libmdbx/tree/python-bindings) - -New features: - - - Added `mdbx_env_set_option()` and `mdbx_env_get_option()` for controls - various runtime options for an environment (announce of this feature was missed in a previous news). - - Added `MDBX_DISABLE_PAGECHECKS` build option to disable some checks to reduce an overhead - and detection probability of database corruption to a values closer to the LMDB. - The `MDBX_DISABLE_PAGECHECKS=1` provides a performance boost of about 10% in CRUD scenarios, - and conjointly with the `MDBX_ENV_CHECKPID=0` and `MDBX_TXN_CHECKOWNER=0` options can yield - up to 30% more performance compared to LMDB. - - Using float point (exponential quantized) representation for internal 16-bit values - of grow step and shrink threshold when huge ones (https://libmdbx.dqdkfa.ru/dead-github/issues/166). - To minimize the impact on compatibility, only the odd values inside the upper half - of the range (i.e. 32769..65533) are used for the new representation. - - Added the `mdbx_drop` similar to LMDB command-line tool to purge or delete (sub)database(s). - - [Ruby bindings](https://rubygems.org/gems/mdbx/) is available now by [Mahlon E. Smith](https://github.com/mahlonsmith). - - Added `MDBX_ENABLE_MADVISE` build option which controls the use of POSIX `madvise()` hints and friends. - - The internal node sizes were refined, resulting in a reduction in large/overflow pages in some use cases - and a slight increase in limits for a keys size to ≈½ of page size. - - Added to `mdbx_chk` output number of keys/items on pages. - - Added explicit `install-strip` and `install-no-strip` targets to the `Makefile` (https://libmdbx.dqdkfa.ru/dead-github/pull/180). - - Major rework page splitting (af9b7b560505684249b76730997f9e00614b8113) for - - An "auto-appending" feature upon insertion for both ascending and - descending key sequences. As a result, the optimality of page filling - increases significantly (more densely, less slackness) while - inserting ordered sequences of keys, - - A "splitting at middle" to make page tree more balanced on average. - - Added `mdbx_get_sysraminfo()` to the API. - - Added guessing a reasonable maximum DB size for the default upper limit of geometry (https://libmdbx.dqdkfa.ru/dead-github/issues/183). - - Major rework internal labeling of a dirty pages (958fd5b9479f52f2124ab7e83c6b18b04b0e7dda) for - a "transparent spilling" feature with the gist to make a dirty pages - be ready to spilling (writing to a disk) without further altering ones. - Thus in the `MDBX_WRITEMAP` mode the OS kernel able to oust dirty pages - to DB file without further penalty during transaction commit. - As a result, page swapping and I/O could be significantly reduced during extra large transactions and/or lack of memory. - - Minimized reading leaf-pages during dropping subDB(s) and nested trees. - - Major rework a spilling of dirty pages to support [LRU](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)) - policy and prioritization for a large/overflow pages. - - Statistics of page operations (split, merge, copy, spill, etc) now available through `mdbx_env_info_ex()`. - - Auto-setup limit for length of dirty pages list (`MDBX_opt_txn_dp_limit` option). - - Support `make options` to list available build options. - - Support `make help` to list available make targets. - - Silently `make`'s build by default. - - Preliminary [Python bindings](https://github.com/Thermi/libmdbx/tree/python-bindings) is available now - by [Noel Kuntze](https://github.com/Thermi) (https://libmdbx.dqdkfa.ru/dead-github/issues/147). - -Backward compatibility break: - - - The `MDBX_AVOID_CRT` build option was renamed to `MDBX_WITHOUT_MSVC_CRT`. - This option is only relevant when building for Windows. - - The `mdbx_env_stat()` always, and `mdbx_env_stat_ex()` when called with the zeroed transaction parameter, - now internally start temporary read transaction and thus may returns `MDBX_BAD_RSLOT` error. - So, just never use deprecated `mdbx_env_stat()' and call `mdbx_env_stat_ex()` with transaction parameter. - - The build option `MDBX_CONFIG_MANUAL_TLS_CALLBACK` was removed and now just a non-zero value of - the `MDBX_MANUAL_MODULE_HANDLER` macro indicates the requirement to manually call `mdbx_module_handler()` - when loading libraries and applications uses statically linked libmdbx on an obsolete Windows versions. - -Fixes: - - - Fixed performance regression due non-optimal C11 atomics usage (https://libmdbx.dqdkfa.ru/dead-github/issues/160). - - Fixed "reincarnation" of subDB after it deletion (https://libmdbx.dqdkfa.ru/dead-github/issues/168). - - Fixed (disallowing) implicit subDB deletion via operations on `@MAIN`'s DBI-handle. - - Fixed a crash of `mdbx_env_info_ex()` in case of a call for a non-open environment (https://libmdbx.dqdkfa.ru/dead-github/issues/171). - - Fixed the selecting/adjustment values inside `mdbx_env_set_geometry()` for implicit out-of-range cases (https://libmdbx.dqdkfa.ru/dead-github/issues/170). - - Fixed `mdbx_env_set_option()` for set initial and limit size of dirty page list ((https://libmdbx.dqdkfa.ru/dead-github/issues/179). - - Fixed an unreasonably huge default upper limit for DB geometry (https://libmdbx.dqdkfa.ru/dead-github/issues/183). - - Fixed `constexpr` specifier for the `slice::invalid()`. - - Fixed (no)readahead auto-handling (https://libmdbx.dqdkfa.ru/dead-github/issues/164). - - Fixed non-alloy build for Windows. - - Switched to using Heap-functions instead of LocalAlloc/LocalFree on Windows. - - Fixed `mdbx_env_stat_ex()` to returning statistics of the whole environment instead of MainDB only (https://libmdbx.dqdkfa.ru/dead-github/issues/190). - - Fixed building by GCC 4.8.5 (added workaround for a preprocessor's bug). - - Fixed building C++ part for iOS <= 13.0 (unavailability of `std::filesystem::path`). - - Fixed building for Windows target versions prior to Windows Vista (`WIN32_WINNT < 0x0600`). - - Fixed building by MinGW for Windows (https://libmdbx.dqdkfa.ru/dead-github/issues/155). - - -******************************************************************************** - - -## v0.9.3 at 2021-02-02 - -Acknowledgments: - - - [Mahlon E. Smith](http://www.martini.nu/) for [FreeBSD port of libmdbx](https://svnweb.freebsd.org/ports/head/databases/mdbx/). - - [장세연](http://www.castis.com) for bug fixing and PR. - - [Clément Renault](https://github.com/Kerollmops/heed) for [Heed](https://github.com/Kerollmops/heed) fully typed Rust wrapper. - - [Alex Sharov](https://github.com/AskAlexSharov) for bug reporting. - - [Noel Kuntze](https://github.com/Thermi) for bug reporting. - -Removed options and features: - - - Drop `MDBX_HUGE_TRANSACTIONS` build-option (now no longer required). - -New features: - - - Package for FreeBSD is available now by Mahlon E. Smith. - - New API functions to get/set various options (https://libmdbx.dqdkfa.ru/dead-github/issues/128): - - the maximum number of named databases for the environment; - - the maximum number of threads/reader slots; - - threshold (since the last unsteady commit) to force flush the data buffers to disk; - - relative period (since the last unsteady commit) to force flush the data buffers to disk; - - limit to grow a list of reclaimed/recycled page's numbers for finding a sequence of contiguous pages for large data items; - - limit to grow a cache of dirty pages for reuse in the current transaction; - - limit of a pre-allocated memory items for dirty pages; - - limit of dirty pages for a write transaction; - - initial allocation size for dirty pages list of a write transaction; - - maximal part of the dirty pages may be spilled when necessary; - - minimal part of the dirty pages should be spilled when necessary; - - how much of the parent transaction dirty pages will be spilled while start each child transaction; - - Unlimited/Dynamic size of retired and dirty page lists (https://libmdbx.dqdkfa.ru/dead-github/issues/123). - - Added `-p` option (purge subDB before loading) to `mdbx_load` tool. - - Reworked spilling of large transaction and committing of nested transactions: - - page spilling code reworked to avoid the flaws and bugs inherited from LMDB; - - limit for number of dirty pages now is controllable at runtime; - - a spilled pages, including overflow/large pages, now can be reused and refunded/compactified in nested transactions; - - more effective refunding/compactification especially for the loosed page cache. - - Added `MDBX_ENABLE_REFUND` and `MDBX_PNL_ASCENDING` internal/advanced build options. - - Added `mdbx_default_pagesize()` function. - - Better support architectures with a weak/relaxed memory consistency model (ARM, AARCH64, PPC, MIPS, RISC-V, etc) by means [C11 atomics](https://en.cppreference.com/w/c/atomic). - - Speed up page number lists and dirty page lists (https://libmdbx.dqdkfa.ru/dead-github/issues/132). - - Added `LIBMDBX_NO_EXPORTS_LEGACY_API` build option. - -Fixes: - - - Fixed missing cleanup (null assigned) in the C++ commit/abort (https://libmdbx.dqdkfa.ru/dead-github/pull/143). - - Fixed `mdbx_realloc()` for case of nullptr and `MDBX_WITHOUT_MSVC_CRT=ON` for Windows. - - Fixed the possibility to use invalid and renewed (closed & re-opened, dropped & re-created) DBI-handles (https://libmdbx.dqdkfa.ru/dead-github/issues/146). - - Fixed 4-byte aligned access to 64-bit integers, including access to the `bootid` meta-page's field (https://libmdbx.dqdkfa.ru/dead-github/issues/153). - - Fixed minor/potential memory leak during page flushing and unspilling. - - Fixed handling states of cursors's and subDBs's for nested transactions. - - Fixed page leak in extra rare case the list of retired pages changed during update GC on transaction commit. - - Fixed assertions to avoid false-positive UB detection by CLANG/LLVM (https://libmdbx.dqdkfa.ru/dead-github/issues/153). - - Fixed `MDBX_TXN_FULL` and regressive `MDBX_KEYEXIST` during large transaction commit with `MDBX_LIFORECLAIM` (https://libmdbx.dqdkfa.ru/dead-github/issues/123). - - Fixed auto-recovery (`weak->steady` with the same boot-id) when Database size at last weak checkpoint is large than at last steady checkpoint. - - Fixed operation on systems with unusual small/large page size, including PowerPC (https://libmdbx.dqdkfa.ru/dead-github/issues/157). - - --------------------------------------------------------------------------------- - - -## v0.9.2 at 2020-11-27 - -Acknowledgments: - - - Jens Alfke (Mobile Architect at [Couchbase](https://www.couchbase.com/)) for [NimDBX](https://github.com/snej/nimdbx). - - Clément Renault (CTO at [MeiliSearch](https://www.meilisearch.com/)) for [mdbx-rs](https://github.com/Kerollmops/mdbx-rs). - - Alex Sharov (Go-Lang Teach Lead at [TurboGeth/Ethereum](https://ethereum.org/)) for an extreme test cases and bug reporting. - - George Hazan (CTO at [Miranda NG](https://www.miranda-ng.org/)) for bug reporting. - - [Positive Technologies](https://www.ptsecurity.com/) for funding and [The Standoff](https://standoff365.com/). - -Added features: - - - Provided package for [buildroot](https://buildroot.org/). - - Binding for Nim is [available](https://github.com/snej/nimdbx) now by Jens Alfke. - - Added `mdbx_env_delete()` for deletion an environment files in a proper and multiprocess-safe way. - - Added `mdbx_txn_commit_ex()` with collecting latency information. - - Fast completion pure nested transactions. - - Added `LIBMDBX_INLINE_API` macro and inline versions of some API functions. - - Added `mdbx_cursor_copy()` function. - - Extended tests for checking cursor tracking. - - Added `MDBX_SET_LOWERBOUND` operation for `mdbx_cursor_get()`. - -Fixes: - - - Fixed missing installation of `mdbx.h++`. - - Fixed use of obsolete `__noreturn`. - - Fixed use of `yield` instruction on ARM if unsupported. - - Added pthread workaround for buggy toolchain/cmake/buildroot. - - Fixed use of `pthread_yield()` for non-GLIBC. - - Fixed use of `RegGetValueA()` on Windows 2000/XP. - - Fixed use of `GetTickCount64()` on Windows 2000/XP. - - Fixed opening DB on a network shares (in the exclusive mode). - - Fixed copy&paste typos. - - Fixed minor false-positive GCC warning. - - Added workaround for broken `DEFINE_ENUM_FLAG_OPERATORS` from Windows SDK. - - Fixed cursor state after multimap/dupsort repeated deletes (https://libmdbx.dqdkfa.ru/dead-github/issues/121). - - Added `SIGPIPE` suppression for internal thread during `mdbx_env_copy()`. - - Fixed extra-rare `MDBX_KEY_EXIST` error during `mdbx_commit()` (https://libmdbx.dqdkfa.ru/dead-github/issues/131). - - Fixed spilled pages checking (https://libmdbx.dqdkfa.ru/dead-github/issues/126). - - Fixed `mdbx_load` for 'plain text' and without `-s name` cases (https://libmdbx.dqdkfa.ru/dead-github/issues/136). - - Fixed save/restore/commit of cursors for nested transactions. - - Fixed cursors state in rare/special cases (move next beyond end-of-data, after deletion and so on). - - Added workaround for MSVC 19.28 (Visual Studio 16.8) (but may still hang during compilation). - - Fixed paranoidal Clang C++ UB for bitwise operations with flags defined by enums. - - Fixed large pages checking (for compatibility and to avoid false-positive errors from `mdbx_chk`). - - Added workaround for Wine (https://github.com/miranda-ng/miranda-ng/issues/1209). - - Fixed `ERROR_NOT_SUPPORTED` while opening DB by UNC pathnames (https://github.com/miranda-ng/miranda-ng/issues/2627). - - Added handling `EXCEPTION_POSSIBLE_DEADLOCK` condition for Windows. - - --------------------------------------------------------------------------------- - - -## v0.9.1 2020-09-30 - -Added features: - - - Preliminary C++ API with support for C++17 polymorphic allocators. - - [Online C++ API reference](https://libmdbx.dqdkfa.ru/) by Doxygen. - - Quick reference for Insert/Update/Delete operations. - - Explicit `MDBX_SYNC_DURABLE` to sync modes for API clarity. - - Explicit `MDBX_ALLDUPS` and `MDBX_UPSERT` for API clarity. - - Support for read transactions preparation (`MDBX_TXN_RDONLY_PREPARE` flag). - - Support for cursor preparation/(pre)allocation and reusing (`mdbx_cursor_create()` and `mdbx_cursor_bind()` functions). - - Support for checking database using specified meta-page (see `mdbx_chk -h`). - - Support for turn to the specific meta-page after checking (see `mdbx_chk -h`). - - Support for explicit reader threads (de)registration. - - The `mdbx_txn_break()` function to explicitly mark a transaction as broken. - - Improved handling of corrupted databases by `mdbx_chk` utility and `mdbx_walk_tree()` function. - - Improved DB corruption detection by checking parent-page-txnid. - - Improved opening large DB (> 4Gb) from 32-bit code. - - Provided `pure-function` and `const-function` attributes to C API. - - Support for user-settable context for transactions & cursors. - - Revised API and documentation related to Handle-Slow-Readers callback feature. - -Deprecated functions and flags: - - - For clarity and API simplification the `MDBX_MAPASYNC` flag is deprecated. - Just use `MDBX_SAFE_NOSYNC` or `MDBX_UTTERLY_NOSYNC` instead of it. - - `MDBX_oom_func`, `mdbx_env_set_oomfunc()` and `mdbx_env_get_oomfunc()` - replaced with `MDBX_hsr_func`, `mdbx_env_get_hsr` and `mdbx_env_get_hsr()`. - -Fixes: - - - Fix `mdbx_strerror()` for `MDBX_BUSY` error (no error description is returned). - - Fix update internal meta-geo information in read-only mode (`EACCESS` or `EBADFD` error). - - Fix `mdbx_page_get()` null-defer when DB corrupted (crash by `SIGSEGV`). - - Fix `mdbx_env_open()` for re-opening after non-fatal errors (`mdbx_chk` unexpected failures). - - Workaround for MSVC 19.27 `static_assert()` bug. - - Doxygen descriptions and refinement. - - Update Valgrind's suppressions. - - Workaround to avoid infinite loop of 'nested' testcase on MIPS under QEMU. - - Fix a lot of typos & spelling (Thanks to Josh Soref for PR). - - Fix `getopt()` messages for Windows (Thanks to Andrey Sporaw for reporting). - - Fix MSVC compiler version requirements (Thanks to Andrey Sporaw for reporting). - - Workarounds for QEMU's bugs to run tests for cross-built[A library under QEMU. - - Now C++ compiler optional for building by CMake. - - --------------------------------------------------------------------------------- - - -## v0.9.0 2020-07-31 (not a release, but API changes) - -Added features: - - - [Online C API reference](https://libmdbx.dqdkfa.ru/) by Doxygen. - - Separated enums for environment, sub-databases, transactions, copying and data-update flags. - -Deprecated functions and flags: - - - Usage of custom comparators and the `mdbx_dbi_open_ex()` are deprecated, since such databases couldn't be checked by the `mdbx_chk` utility. - Please use the value-to-key functions to provide keys that are compatible with the built-in libmdbx comparators. - - -******************************************************************************** - - -## 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. - - Added key-to-value, `mdbx_get_keycmp()` and `mdbx_get_datacmp()` functions (helpful to avoid using custom comparators). - - Added `ENABLE_UBSAN` CMake option to enabling the UndefinedBehaviorSanitizer from GCC/CLANG. - - Workaround for [CLANG bug](https://bugs.llvm.org/show_bug.cgi?id=43275). - - Returning `MDBX_CORRUPTED` in case all meta-pages are weak and no other error. - - Refined mode bits while auto-creating LCK-file. - - Avoids unnecessary database file re-mapping in case geometry changed by another process(es). - From the user's point of view, the `MDBX_UNABLE_EXTEND_MAPSIZE` error will now be returned less frequently and only when using the DB in the current process really requires it to be reopened. - - Remapping on-the-fly and of the database file was implemented. - Now remapping with a change of address is performed automatically if there are no dependent readers in the current process. - - -## 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. - - Fix `mdbx_env_set_geometry()` for case it is called from an opened environment outside of a write transaction. - - Add support for huge transactions and `MDBX_HUGE_TRANSACTIONS` build-option (default `OFF`). - - Refine LTO (link time optimization) for clang. - - Force enabling exceptions handling for MSVC (`/EHsc` option). - - -## 2020-06-05 - - - Support for Android/Bionic. - - Support for iOS. - - Auto-handling `MDBX_NOSUBDIR` while opening for any existing database. - - Engage github-actions to make release-assets. - - Clarify API description. - - Extended keygen-cases in stochastic test. - - Fix fetching of first/lower key from LEAF2-page during page merge. - - Fix missing comma in array of error messages. - - Fix div-by-zero while copy-with-compaction for non-resizable environments. - - Fixes & enhancements for custom-comparators. - - Fix `MDBX_WITHOUT_MSVC_CRT` option and missing `ntdll.def`. - - Fix `mdbx_env_close()` to work correctly called concurrently from several threads. - - Fix null-deref in an ASAN-enabled builds while opening the environment with error and/or read-only. - - Fix AddressSanitizer errors after closing the environment. - - Fix/workaround to avoid GCC 10.x pedantic warnings. - - Fix using `ENODATA` for FreeBSD. - - Avoid invalidation of DBI-handle(s) when it just closes. - - Avoid using `pwritev()` for single-writes (up to 10% speedup for some kernels & scenarios). - - Avoiding `MDBX_UTTERLY_NOSYNC` as result of flags merge. - - Add `mdbx_dbi_dupsort_depthmask()` function. - - Add `MDBX_CP_FORCE_RESIZABLE` option. - - Add deprecated `MDBX_MAP_RESIZED` for compatibility. - - Add `MDBX_BUILD_TOOLS` option (default `ON`). - - Refine `mdbx_dbi_open_ex()` to safe concurrently opening the same handle from different threads. - - Truncate clk-file during environment closing. So a zero-length lck-file indicates that the environment was closed properly. - - Refine `mdbx_update_gc()` for huge transactions with small sizes of database page. - - Extends dump/load to support all MDBX attributes. - - Avoid upsertion the same key-value data, fix related assertions. - - Rework min/max length checking for keys & values. - - Checking the order of keys on all pages during checking. - - Support `CFLAGS_EXTRA` make-option for convenience. - - Preserve the last txnid while copying with compactification. - - Auto-reset running transaction in mdbx_txn_renew(). - - Automatically abort errored transaction in mdbx_txn_commit(). - - Auto-choose page size for large databases. - - Rearrange source files, rework build, options-support by CMake. - - Crutch for WSL1 (Windows subsystem for Linux). - - Refine install/uninstall targets. - - Support for Valgrind 3.14 and later. - - Add check-analyzer check-ubsan check-asan check-leak targets to Makefile. - - Minor fix/workaround to avoid UBSAN traps for `memcpy(ptr, NULL, 0)`. - - Avoid some GCC-analyzer false-positive warnings. - - -## 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. - - Speedup runtime checks in debug/checked builds. - - Added checking for read/write transactions overlapping for the same thread, added `MDBX_TXN_OVERLAPPING` error and `MDBX_DBG_LEGACY_OVERLAP` option. - - Added `mdbx_key_from_jsonInteger()`, `mdbx_key_from_double()`, `mdbx_key_from_float()`, `mdbx_key_from_int64()` and `mdbx_key_from_int32()` functions. See `mdbx.h` for description. - - Fix compatibility (use zero for invalid DBI). - - Refine/clarify error messages. - - Avoids extra error messages "bad txn" from mdbx_chk when DB is corrupted. - - -## 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. - - Refine/fix handling `STATUS_CONFLICTING_ADDRESSES`. - - Rework `MDBX_DBG_DUMP` option to avoid disk I/O performance degradation. - - Add built-in help to test tool. - - Fix `mdbx_env_set_geometry()` for large page size. - - Fix env_set_geometry() for large pagesize. - - Clarify API description & comments, fix typos. - - -## 2019-12-31 - - - Fix returning MDBX_RESULT_TRUE from page_alloc(). - - Fix false-positive ASAN issue. - - Fix assertion for `MDBX_NOTLS` option. - - Rework `MADV_DONTNEED` threshold. - - Fix `mdbx_chk` utility for don't checking some numbers if walking on the B-tree was disabled. - - Use page's mp_txnid for basic integrity checking. - - Add `MDBX_FORCE_ASSERTIONS` build-time option. - - Rework `MDBX_DBG_DUMP` to avoid performance degradation. - - Rename `MDBX_NOSYNC` to `MDBX_SAFE_NOSYNC` for clarity. - - Interpret `ERROR_ACCESS_DENIED` from `OpenProcess()` as 'process exists'. - - Avoid using `FILE_FLAG_NO_BUFFERING` for compatibility with small database pages. - - Added install section for CMake. - - -## 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. - - Add `MDBX_ACCEDE` flag for database opening. - - Using OFD-locks and tracking for in-process multi-opening. - - Hot backup into pipe. - - Support for cmake & amalgamated sources. - - Fastest internal sort implementation. - - New internal dirty-list implementation with lazy sorting. - - Support for lazy-sync-to-disk with polling. - - Extended key length. - - Last update transaction number for each sub-database. - - Automatic read ahead enabling/disabling. - - More auto-compactification. - - Using -fsanitize=undefined and -Wpedantic options. - - Rework page merging. - - Nested transactions. - - API description. - - Checking for non-local filesystems to avoid DB corruption. - - -******************************************************************************** - - -For early changes see the git commit history. +For early releases and changes see the ChangeLog-NN the git commit history. From 021d83b841adeed7e4ae13bd9dd9f6e4602a2a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 22 Mar 2025 19:08:52 +0300 Subject: [PATCH 175/181] =?UTF-8?q?mdbx:=20=D1=83=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B5=D0=B3=D1=80=D0=B5?= =?UTF-8?q?=D1=81=D1=81=D0=B0=20=D0=BF=D1=80=D0=B8=20=D0=B8=D1=81=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=BA=D1=83=D1=80=D1=81=D0=BE=D1=80=D0=BE=D0=B2=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20DBI=3D0=20=D0=B2=20=D1=87=D0=B8=D1=82=D0=B0=D1=8E?= =?UTF-8?q?=D1=89=D0=B8=D1=85=20=D1=82=D1=80=D0=B0=D0=BD=D0=B7=D0=B0=D0=BA?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=D1=85.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit В результате рефакторинга и ряда оптимизаций для завершения/гашения курсоров в читающих и пишущих транзакций стал использоваться общий код. Причем за основу, был взят соответствующий фрагмент относящийся к пишущим транзакциям, в которых пользователю не позволяется использоваться курсоры для DBI=0 и поэтому эта итераций пропускалась. В результате, при завершении читающих транзакциях, курсоры связанные с DBI=0 не завершались должным образом, а при их повторном использовании или явном закрытии после завершения читающей транзакции происходило обращение к уже освобожденной памяти. Если же такие курсоры отсоединялись или закрывались до завершения читающей транзакции, то ошибка не имела шансов на проявление. Спасибо Илье Михееву (https://github.com/JkLondon) и команде Erigon (https://erigon.tech) за сообщения о проблеме. --- src/txn.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/txn.c b/src/txn.c index a61266f3..5d553595 100644 --- a/src/txn.c +++ b/src/txn.c @@ -9,9 +9,8 @@ __hot txnid_t txn_snapshot_oldest(const MDBX_txn *const txn) { void txn_done_cursors(MDBX_txn *txn) { tASSERT(txn, txn->flags & txn_may_have_cursors); - tASSERT(txn, txn->cursors[FREE_DBI] == nullptr); - TXN_FOREACH_DBI_FROM(txn, i, /* skip FREE_DBI */ 1) { + TXN_FOREACH_DBI_ALL(txn, i) { MDBX_cursor *cursor = txn->cursors[i]; if (cursor) { txn->cursors[i] = nullptr; From f8e332a205082959f6b205c21f3ec3cab8383053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 22 Mar 2025 19:06:13 +0300 Subject: [PATCH 176/181] =?UTF-8?q?mdbx-test:=20=D1=80=D0=B0=D1=81=D1=88?= =?UTF-8?q?=D0=B8=D1=80=D0=B5=D0=BD=D0=B8=D0=B5=20extra/cursor-closing.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/extra/cursor_closing.c++ | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/extra/cursor_closing.c++ b/test/extra/cursor_closing.c++ index 24633560..4bd4b7ca 100644 --- a/test/extra/cursor_closing.c++ +++ b/test/extra/cursor_closing.c++ @@ -332,6 +332,27 @@ bool case1(mdbx::env env) { //-------------------------------------------------------------------------------------------- +bool case2(mdbx::env env) { + bool ok = true; + + auto txn = env.start_write(); + auto dbi = txn.create_map("case2", mdbx::key_mode::usual, mdbx::value_mode::single); + txn.commit_embark_read(); + auto cursor1 = txn.open_cursor(dbi); + auto cursor2 = txn.open_cursor(0); + cursor1.move(mdbx::cursor::next, false); + cursor2.move(mdbx::cursor::next, false); + txn.commit_embark_read(); + cursor2.bind(txn, dbi); + cursor1.bind(txn, 0); + cursor1.move(mdbx::cursor::last, false); + cursor2.move(mdbx::cursor::last, false); + + return ok; +} + +//-------------------------------------------------------------------------------------------- + int doit() { mdbx::path db_filename = "test-cursor-closing"; mdbx::env::remove(db_filename); @@ -341,6 +362,7 @@ int doit() { bool ok = case0(env); ok = case1(env) && ok; + ok = case2(env) && ok; if (ok) { std::cout << "OK\n"; From 94531a9cdceafcec588c74ca3183326c45852fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 22 Mar 2025 19:30:38 +0300 Subject: [PATCH 177/181] =?UTF-8?q?mdbx++:=20=D0=B2=D0=B1=D1=80=D0=BE?= =?UTF-8?q?=D1=81=20`std::invalid=5Fargument`=20=D1=81=20=D1=8F=D0=B2?= =?UTF-8?q?=D0=BD=D1=8B=D0=BC=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=D0=BC=20`"MDBX=5FEINVAL"`=20.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mdbx.c++ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mdbx.c++ b/src/mdbx.c++ index 565c79e9..6ae73d8a 100644 --- a/src/mdbx.c++ +++ b/src/mdbx.c++ @@ -373,7 +373,7 @@ __cold std::string error::message() const { __cold void error::throw_exception() const { switch (code()) { case MDBX_EINVAL: - throw std::invalid_argument("mdbx"); + throw std::invalid_argument("MDBX_EINVAL"); case MDBX_ENOMEM: throw std::bad_alloc(); case MDBX_SUCCESS: From 390490edf47e3c9cbbb9eaeac7825e9d13fda124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 22 Mar 2025 23:17:35 +0300 Subject: [PATCH 178/181] =?UTF-8?q?mdbx:=20=D1=83=D1=82=D0=BE=D1=87=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=82=D0=B8=D0=BF=D0=B0=20=D0=B0?= =?UTF-8?q?=D0=B4=D1=80=D0=B5=D1=81=D0=B0=20=D0=B4=D0=BB=D1=8F=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=BD=D0=B0=D1=82=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d3cd1c1b..39228e8e 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ > [5](https://libmdbx.dqdkfa.ru/tg-archive/messages5.html), [6](https://libmdbx.dqdkfa.ru/tg-archive/messages6.html), [7](https://libmdbx.dqdkfa.ru/tg-archive/messages7.html)). > See the [ChangeLog](https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md) for `NEWS` and latest updates. -> Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`. +> Donations are welcome to the Ethereum/ERC-20 `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`. > Всё будет хорошо! From b4e65f5d21f99766017173e2df7728bea39aaaa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sat, 22 Mar 2025 23:29:43 +0300 Subject: [PATCH 179/181] =?UTF-8?q?mdbx:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`NOTICE`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NOTICE | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/NOTICE b/NOTICE index 4df84dba..dd58a0b5 100644 --- a/NOTICE +++ b/NOTICE @@ -8,16 +8,32 @@ documentation, C++ API description and links to the original git repo with the source code. Questions, feedback and suggestions are welcome to the Telegram' group https://t.me/libmdbx. -Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`. +Donations are welcome to the Ethereum/ERC-20 `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`. Всё будет хорошо! Copyright 2015-2025 Леонид Юрьев aka Leonid Yuriev SPDX-License-Identifier: Apache-2.0 For notes about the license change, credits and acknowledgments, -please refer to the COPYRIGHT file within original libmdbx source code -repository https://gitflic.ru/project/erthink/libmdbx +please refer to the COPYRIGHT file within libmdbx source. -On 2022-04-15 the Github administration, without any warning nor -explanation, deleted _libmdbx_ along with a lot of other projects, -simultaneously blocking access for many developers. -For the same reason ~~Github~~ is blacklisted forever. +--- + +On 2022-04-15, without any warnings or following explanations, the +Github administration deleted _libmdbx_, my account and all other +projects (status 404). A few months later, without any involvement or +notification from/to me, the projects were restored/opened in the "public +read-only archive" status from some kind of incomplete backup. I regard +these actions of Github as malicious sabotage, and I consider the Github +service itself to have lost trust forever. + +As a result of what has happened, I will never, under any circumstances, +post the primary sources (aka origins) of my projects on Github, or rely +in any way on the Github infrastructure. + +Nevertheless, realizing that it is more convenient for users of +_libmdbx_ and other my projects to access ones on Github, I do not want +to restrict their freedom or create inconvenience, and therefore I place +mirrors (aka mirrors) of such repositories on Github since 2025. At the +same time, I would like to emphasize once again that these are only +mirrors that can be frozen, blocked or deleted at any time, as was the +case in 2022. From b308559dd9ced1187332addb09553f5ba10957e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 28 Mar 2025 15:12:10 +0300 Subject: [PATCH 180/181] =?UTF-8?q?mdbx:=20=D0=BF=D0=BE=D0=BD=D0=B8=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=83=D1=80=D0=BE=D0=B2=D0=BD=D1=8F?= =?UTF-8?q?=20=D0=BB=D0=BE=D0=B3=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B4=D0=BB=D1=8F=20"skip=20update=20meta".?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Спасибо [Илье Михееву](https://github.com/JkLondon) за сообщение о недочете. --- src/dxb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dxb.c b/src/dxb.c index c2568a1c..37ddcaa7 100644 --- a/src/dxb.c +++ b/src/dxb.c @@ -1157,7 +1157,8 @@ int dxb_sync_locked(MDBX_env *env, unsigned flags, meta_t *const pending, troika if (!head.is_steady && meta_is_steady(pending)) target = (meta_t *)head.ptr_c; else { - WARNING("%s", "skip update meta"); + NOTICE("skip update meta%" PRIaPGNO " for txn#%" PRIaTXN "since it is already steady", + data_page(head.ptr_c)->pgno, head.txnid); return MDBX_SUCCESS; } } else { From d8f46344b5a2aca3023fe84201ba83fa69bef76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Mon, 31 Mar 2025 00:51:23 +0300 Subject: [PATCH 181/181] =?UTF-8?q?mdbx:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20`MDBX=5FVERSION=5FUNSTABLE`=20?= =?UTF-8?q?=D0=B8=20=D0=BC=D0=B0=D1=80=D0=BA=D0=B8=D1=80=D0=BE=D0=B2=D0=BA?= =?UTF-8?q?=D0=B0=20`master`-=D0=B2=D0=B5=D1=82=D0=BA=D0=B8=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=BF=D1=80=D0=B5=D0=B4=D0=BE=D1=82=D0=B2=D1=80=D0=B0?= =?UTF-8?q?=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE?= =?UTF-8?q?=D0=BA=20=D1=81=D0=B1=D0=BE=D1=80=D0=BA=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mdbx.h | 3 ++- src/version.c.in | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mdbx.h b/mdbx.h index c43c0c46..bbfe68c5 100644 --- a/mdbx.h +++ b/mdbx.h @@ -581,7 +581,8 @@ typedef mode_t mdbx_mode_t; extern "C" { #endif -/* MDBX version 0.14.x */ +/* MDBX version 0.14.x, but it is unstable/under-development yet. */ +#define MDBX_VERSION_UNSTABLE #define MDBX_VERSION_MAJOR 0 #define MDBX_VERSION_MINOR 14 diff --git a/src/version.c.in b/src/version.c.in index 5c585eae..fdbfcb28 100644 --- a/src/version.c.in +++ b/src/version.c.in @@ -3,11 +3,16 @@ #include "internals.h" -#if MDBX_VERSION_MAJOR != ${MDBX_VERSION_MAJOR} || MDBX_VERSION_MINOR != ${MDBX_VERSION_MINOR} +#if !defined(MDBX_VERSION_UNSTABLE) && \ + (MDBX_VERSION_MAJOR != ${MDBX_VERSION_MAJOR} || MDBX_VERSION_MINOR != ${MDBX_VERSION_MINOR}) #error "API version mismatch! Had `git fetch --tags` done?" #endif -static const char sourcery[] = MDBX_STRINGIFY(MDBX_BUILD_SOURCERY); +static const char sourcery[] = +#ifdef MDBX_VERSION_UNSTABLE + "UNSTABLE@" +#endif + MDBX_STRINGIFY(MDBX_BUILD_SOURCERY); __dll_export #ifdef __attribute_used__