mdbxmou 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +32 -0
- package/.github/workflows/publish.yml +27 -0
- package/.gitmodules +3 -0
- package/CMakeLists.txt +53 -0
- package/LICENSE +201 -0
- package/README.md +639 -0
- package/build.js +11 -0
- package/deps/libmdbx/.clang-format +3 -0
- package/deps/libmdbx/.cmake-format.yaml +3 -0
- package/deps/libmdbx/.le.ini +40 -0
- package/deps/libmdbx/CMakeLists.txt +1269 -0
- package/deps/libmdbx/COPYRIGHT +159 -0
- package/deps/libmdbx/ChangeLog.md +2786 -0
- package/deps/libmdbx/GNUmakefile +950 -0
- package/deps/libmdbx/LICENSE +177 -0
- package/deps/libmdbx/Makefile +16 -0
- package/deps/libmdbx/NOTICE +39 -0
- package/deps/libmdbx/README.md +863 -0
- package/deps/libmdbx/TODO.md +43 -0
- package/deps/libmdbx/cmake/compiler.cmake +1221 -0
- package/deps/libmdbx/cmake/profile.cmake +58 -0
- package/deps/libmdbx/cmake/utils.cmake +524 -0
- package/deps/libmdbx/conanfile.py +323 -0
- package/deps/libmdbx/docs/Doxyfile.in +2734 -0
- package/deps/libmdbx/docs/_preface.md +47 -0
- package/deps/libmdbx/docs/_restrictions.md +248 -0
- package/deps/libmdbx/docs/_starting.md +245 -0
- package/deps/libmdbx/docs/_toc.md +34 -0
- package/deps/libmdbx/docs/header.html +96 -0
- package/deps/libmdbx/example/CMakeLists.txt +6 -0
- package/deps/libmdbx/example/README.md +1 -0
- package/deps/libmdbx/example/example-mdbx.c +154 -0
- package/deps/libmdbx/example/sample-bdb.txt +77 -0
- package/deps/libmdbx/mdbx.h +6655 -0
- package/deps/libmdbx/mdbx.h++ +6428 -0
- package/deps/libmdbx/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch +173 -0
- package/deps/libmdbx/src/alloy.c +54 -0
- package/deps/libmdbx/src/api-cold.c +543 -0
- package/deps/libmdbx/src/api-copy.c +912 -0
- package/deps/libmdbx/src/api-cursor.c +754 -0
- package/deps/libmdbx/src/api-dbi.c +315 -0
- package/deps/libmdbx/src/api-env.c +1434 -0
- package/deps/libmdbx/src/api-extra.c +165 -0
- package/deps/libmdbx/src/api-key-transform.c +197 -0
- package/deps/libmdbx/src/api-misc.c +286 -0
- package/deps/libmdbx/src/api-opts.c +575 -0
- package/deps/libmdbx/src/api-range-estimate.c +365 -0
- package/deps/libmdbx/src/api-txn-data.c +454 -0
- package/deps/libmdbx/src/api-txn.c +921 -0
- package/deps/libmdbx/src/atomics-ops.h +364 -0
- package/deps/libmdbx/src/atomics-types.h +97 -0
- package/deps/libmdbx/src/audit.c +109 -0
- package/deps/libmdbx/src/bits.md +34 -0
- package/deps/libmdbx/src/chk.c +1796 -0
- package/deps/libmdbx/src/cogs.c +309 -0
- package/deps/libmdbx/src/cogs.h +506 -0
- package/deps/libmdbx/src/coherency.c +170 -0
- package/deps/libmdbx/src/config.h.in +88 -0
- package/deps/libmdbx/src/cursor.c +2396 -0
- package/deps/libmdbx/src/cursor.h +391 -0
- package/deps/libmdbx/src/dbi.c +717 -0
- package/deps/libmdbx/src/dbi.h +142 -0
- package/deps/libmdbx/src/debug_begin.h +36 -0
- package/deps/libmdbx/src/debug_end.h +15 -0
- package/deps/libmdbx/src/dpl.c +486 -0
- package/deps/libmdbx/src/dpl.h +134 -0
- package/deps/libmdbx/src/dxb.c +1335 -0
- package/deps/libmdbx/src/env.c +607 -0
- package/deps/libmdbx/src/essentials.h +125 -0
- package/deps/libmdbx/src/gc-get.c +1345 -0
- package/deps/libmdbx/src/gc-put.c +970 -0
- package/deps/libmdbx/src/gc.h +40 -0
- package/deps/libmdbx/src/global.c +474 -0
- package/deps/libmdbx/src/internals.h +585 -0
- package/deps/libmdbx/src/layout-dxb.h +288 -0
- package/deps/libmdbx/src/layout-lck.h +289 -0
- package/deps/libmdbx/src/lck-posix.c +859 -0
- package/deps/libmdbx/src/lck-windows.c +607 -0
- package/deps/libmdbx/src/lck.c +174 -0
- package/deps/libmdbx/src/lck.h +110 -0
- package/deps/libmdbx/src/logging_and_debug.c +250 -0
- package/deps/libmdbx/src/logging_and_debug.h +159 -0
- package/deps/libmdbx/src/man1/mdbx_chk.1 +106 -0
- package/deps/libmdbx/src/man1/mdbx_copy.1 +95 -0
- package/deps/libmdbx/src/man1/mdbx_drop.1 +48 -0
- package/deps/libmdbx/src/man1/mdbx_dump.1 +101 -0
- package/deps/libmdbx/src/man1/mdbx_load.1 +105 -0
- package/deps/libmdbx/src/man1/mdbx_stat.1 +86 -0
- package/deps/libmdbx/src/mdbx.c++ +1837 -0
- package/deps/libmdbx/src/meta.c +656 -0
- package/deps/libmdbx/src/meta.h +168 -0
- package/deps/libmdbx/src/mvcc-readers.c +414 -0
- package/deps/libmdbx/src/node.c +365 -0
- package/deps/libmdbx/src/node.h +102 -0
- package/deps/libmdbx/src/ntdll.def +1246 -0
- package/deps/libmdbx/src/options.h +534 -0
- package/deps/libmdbx/src/osal.c +3485 -0
- package/deps/libmdbx/src/osal.h +587 -0
- package/deps/libmdbx/src/page-get.c +483 -0
- package/deps/libmdbx/src/page-iov.c +185 -0
- package/deps/libmdbx/src/page-iov.h +34 -0
- package/deps/libmdbx/src/page-ops.c +744 -0
- package/deps/libmdbx/src/page-ops.h +142 -0
- package/deps/libmdbx/src/pnl.c +236 -0
- package/deps/libmdbx/src/pnl.h +146 -0
- package/deps/libmdbx/src/preface.h +990 -0
- package/deps/libmdbx/src/proto.h +105 -0
- package/deps/libmdbx/src/refund.c +212 -0
- package/deps/libmdbx/src/sort.h +484 -0
- package/deps/libmdbx/src/spill.c +431 -0
- package/deps/libmdbx/src/spill.h +74 -0
- package/deps/libmdbx/src/table.c +107 -0
- package/deps/libmdbx/src/tls.c +551 -0
- package/deps/libmdbx/src/tls.h +43 -0
- package/deps/libmdbx/src/tools/chk.c +673 -0
- package/deps/libmdbx/src/tools/copy.c +166 -0
- package/deps/libmdbx/src/tools/drop.c +199 -0
- package/deps/libmdbx/src/tools/dump.c +515 -0
- package/deps/libmdbx/src/tools/load.c +831 -0
- package/deps/libmdbx/src/tools/stat.c +516 -0
- package/deps/libmdbx/src/tools/wingetopt.c +87 -0
- package/deps/libmdbx/src/tools/wingetopt.h +30 -0
- package/deps/libmdbx/src/tree-ops.c +1554 -0
- package/deps/libmdbx/src/tree-search.c +140 -0
- package/deps/libmdbx/src/txl.c +99 -0
- package/deps/libmdbx/src/txl.h +26 -0
- package/deps/libmdbx/src/txn.c +1083 -0
- package/deps/libmdbx/src/unaligned.h +205 -0
- package/deps/libmdbx/src/utils.c +32 -0
- package/deps/libmdbx/src/utils.h +76 -0
- package/deps/libmdbx/src/version.c.in +44 -0
- package/deps/libmdbx/src/walk.c +290 -0
- package/deps/libmdbx/src/walk.h +20 -0
- package/deps/libmdbx/src/windows-import.c +152 -0
- package/deps/libmdbx/src/windows-import.h +128 -0
- package/deps/libmdbx/test/CMakeLists.txt +317 -0
- package/deps/libmdbx/test/append.c++ +237 -0
- package/deps/libmdbx/test/base.h++ +92 -0
- package/deps/libmdbx/test/battery-tmux.sh +64 -0
- package/deps/libmdbx/test/cases.c++ +118 -0
- package/deps/libmdbx/test/chrono.c++ +134 -0
- package/deps/libmdbx/test/chrono.h++ +85 -0
- package/deps/libmdbx/test/config.c++ +643 -0
- package/deps/libmdbx/test/config.h++ +334 -0
- package/deps/libmdbx/test/copy.c++ +62 -0
- package/deps/libmdbx/test/dead.c++ +39 -0
- package/deps/libmdbx/test/dump-load.sh +40 -0
- package/deps/libmdbx/test/extra/crunched_delete.c++ +409 -0
- package/deps/libmdbx/test/extra/cursor_closing.c++ +410 -0
- package/deps/libmdbx/test/extra/dbi.c++ +229 -0
- package/deps/libmdbx/test/extra/doubtless_positioning.c++ +253 -0
- package/deps/libmdbx/test/extra/dupfix_addodd.c +94 -0
- package/deps/libmdbx/test/extra/dupfix_multiple.c++ +311 -0
- package/deps/libmdbx/test/extra/early_close_dbi.c++ +137 -0
- package/deps/libmdbx/test/extra/hex_base64_base58.c++ +118 -0
- package/deps/libmdbx/test/extra/maindb_ordinal.c++ +61 -0
- package/deps/libmdbx/test/extra/open.c++ +96 -0
- package/deps/libmdbx/test/extra/pcrf/README.md +2 -0
- package/deps/libmdbx/test/extra/pcrf/pcrf_test.c +380 -0
- package/deps/libmdbx/test/extra/probe.c++ +10 -0
- package/deps/libmdbx/test/extra/txn.c++ +407 -0
- package/deps/libmdbx/test/extra/upsert_alldups.c +193 -0
- package/deps/libmdbx/test/fork.c++ +263 -0
- package/deps/libmdbx/test/hill.c++ +447 -0
- package/deps/libmdbx/test/jitter.c++ +197 -0
- package/deps/libmdbx/test/keygen.c++ +393 -0
- package/deps/libmdbx/test/keygen.h++ +130 -0
- package/deps/libmdbx/test/log.c++ +358 -0
- package/deps/libmdbx/test/log.h++ +91 -0
- package/deps/libmdbx/test/main.c++ +706 -0
- package/deps/libmdbx/test/nested.c++ +318 -0
- package/deps/libmdbx/test/osal-unix.c++ +647 -0
- package/deps/libmdbx/test/osal-windows.c++ +440 -0
- package/deps/libmdbx/test/osal.h++ +41 -0
- package/deps/libmdbx/test/stochastic.sh +690 -0
- package/deps/libmdbx/test/stub/LICENSE +24 -0
- package/deps/libmdbx/test/stub/README.md +8 -0
- package/deps/libmdbx/test/stub/pthread_barrier.c +104 -0
- package/deps/libmdbx/test/stub/pthread_barrier.h +77 -0
- package/deps/libmdbx/test/test.c++ +1551 -0
- package/deps/libmdbx/test/test.h++ +298 -0
- package/deps/libmdbx/test/tmux.conf +3 -0
- package/deps/libmdbx/test/try.c++ +30 -0
- package/deps/libmdbx/test/ttl.c++ +240 -0
- package/deps/libmdbx/test/utils.c++ +203 -0
- package/deps/libmdbx/test/utils.h++ +326 -0
- package/deps/libmdbx/test/valgrind_suppress.txt +536 -0
- package/lib/mdbx_evn_async.js +211 -0
- package/lib/mdbx_worker.js +195 -0
- package/lib/nativemou.js +6 -0
- package/package.json +38 -0
- package/src/async/envmou_close.cpp +34 -0
- package/src/async/envmou_close.hpp +32 -0
- package/src/async/envmou_copy_to.cpp +29 -0
- package/src/async/envmou_copy_to.hpp +38 -0
- package/src/async/envmou_keys.cpp +201 -0
- package/src/async/envmou_keys.hpp +50 -0
- package/src/async/envmou_open.cpp +38 -0
- package/src/async/envmou_open.hpp +33 -0
- package/src/async/envmou_query.cpp +167 -0
- package/src/async/envmou_query.hpp +53 -0
- package/src/dbimou.cpp +522 -0
- package/src/dbimou.hpp +82 -0
- package/src/env_arg0.hpp +24 -0
- package/src/envmou.cpp +445 -0
- package/src/envmou.hpp +116 -0
- package/src/modulemou.cpp +113 -0
- package/src/querymou.cpp +177 -0
- package/src/querymou.hpp +93 -0
- package/src/txnmou.cpp +254 -0
- package/src/txnmou.hpp +122 -0
- package/src/typemou.hpp +239 -0
- package/src/valuemou.hpp +194 -0
- package/test/async.js +67 -0
- package/test/e3.js +38 -0
- package/test/e4.js +89 -0
- package/test/e5.js +162 -0
- package/test/test-batch-ops.js +243 -0
- package/test/test-cursor-mode.js +84 -0
- package/test/test-multi-mode.js +87 -0
|
@@ -0,0 +1,859 @@
|
|
|
1
|
+
/// \copyright SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
|
|
3
|
+
|
|
4
|
+
#if !(defined(_WIN32) || defined(_WIN64))
|
|
5
|
+
/*----------------------------------------------------------------------------*
|
|
6
|
+
* POSIX/non-Windows LCK-implementation */
|
|
7
|
+
|
|
8
|
+
#include "internals.h"
|
|
9
|
+
|
|
10
|
+
#if MDBX_LOCKING == MDBX_LOCKING_SYSV
|
|
11
|
+
#include <sys/sem.h>
|
|
12
|
+
#endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */
|
|
13
|
+
|
|
14
|
+
/* Описание реализации блокировок для POSIX & Linux:
|
|
15
|
+
*
|
|
16
|
+
* lck-файл отображается в память, в нём организуется таблица читателей и
|
|
17
|
+
* размещаются совместно используемые posix-мьютексы (futex). Посредством
|
|
18
|
+
* этих мьютексов (см struct lck_t) реализуются:
|
|
19
|
+
* - Блокировка таблицы читателей для регистрации,
|
|
20
|
+
* т.е. функции lck_rdt_lock() и lck_rdt_unlock().
|
|
21
|
+
* - Блокировка БД для пишущих транзакций,
|
|
22
|
+
* т.е. функции lck_txn_lock() и lck_txn_unlock().
|
|
23
|
+
*
|
|
24
|
+
* Остальной функционал реализуется отдельно посредством файловых блокировок:
|
|
25
|
+
* - Первоначальный захват БД в режиме exclusive/shared и последующий перевод
|
|
26
|
+
* в операционный режим, функции lck_seize() и lck_downgrade().
|
|
27
|
+
* - Проверка присутствие процессов-читателей,
|
|
28
|
+
* т.е. функции lck_rpid_set(), lck_rpid_clear() и lck_rpid_check().
|
|
29
|
+
*
|
|
30
|
+
* Для блокировки файлов используется fcntl(F_SETLK), так как:
|
|
31
|
+
* - lockf() оперирует только эксклюзивной блокировкой и требует
|
|
32
|
+
* открытия файла в RW-режиме.
|
|
33
|
+
* - flock() не гарантирует атомарности при смене блокировок
|
|
34
|
+
* и оперирует только всем файлом целиком.
|
|
35
|
+
* - Для контроля процессов-читателей используются однобайтовые
|
|
36
|
+
* range-блокировки lck-файла посредством fcntl(F_SETLK). При этом
|
|
37
|
+
* в качестве позиции используется pid процесса-читателя.
|
|
38
|
+
* - Для первоначального захвата и shared/exclusive выполняется блокировка
|
|
39
|
+
* основного файла БД и при успехе lck-файла.
|
|
40
|
+
*
|
|
41
|
+
* ----------------------------------------------------------------------------
|
|
42
|
+
* УДЕРЖИВАЕМЫЕ БЛОКИРОВКИ В ЗАВИСИМОСТИ ОТ РЕЖИМА И СОСТОЯНИЯ
|
|
43
|
+
*
|
|
44
|
+
* Эксклюзивный режим без lck-файла:
|
|
45
|
+
* = заблокирован весь dxb-файл посредством F_RDLCK или F_WRLCK,
|
|
46
|
+
* в зависимости от MDBX_RDONLY.
|
|
47
|
+
*
|
|
48
|
+
* Не-операционный режим на время пере-инициализации и разрушении lck-файла:
|
|
49
|
+
* = F_WRLCK блокировка первого байта lck-файла, другие процессы ждут её
|
|
50
|
+
* снятия при получении F_RDLCK через F_SETLKW.
|
|
51
|
+
* - блокировки dxb-файла могут меняться до снятие эксклюзивной блокировки
|
|
52
|
+
* lck-файла:
|
|
53
|
+
* + для НЕ-эксклюзивного режима блокировка pid-байта в dxb-файле
|
|
54
|
+
* посредством F_RDLCK или F_WRLCK, в зависимости от MDBX_RDONLY.
|
|
55
|
+
* + для ЭКСКЛЮЗИВНОГО режима блокировка всего dxb-файла
|
|
56
|
+
* посредством F_RDLCK или F_WRLCK, в зависимости от MDBX_RDONLY.
|
|
57
|
+
*
|
|
58
|
+
* ОПЕРАЦИОННЫЙ режим с lck-файлом:
|
|
59
|
+
* = F_RDLCK блокировка первого байта lck-файла, другие процессы не могут
|
|
60
|
+
* получить F_WRLCK и таким образом видят что БД используется.
|
|
61
|
+
* + F_WRLCK блокировка pid-байта в clk-файле после первой транзакции чтения.
|
|
62
|
+
* + для НЕ-эксклюзивного режима блокировка pid-байта в dxb-файле
|
|
63
|
+
* посредством F_RDLCK или F_WRLCK, в зависимости от MDBX_RDONLY.
|
|
64
|
+
* + для ЭКСКЛЮЗИВНОГО режима блокировка pid-байта всего dxb-файла
|
|
65
|
+
* посредством F_RDLCK или F_WRLCK, в зависимости от MDBX_RDONLY.
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
#if MDBX_USE_OFDLOCKS
|
|
69
|
+
static int op_setlk, op_setlkw, op_getlk;
|
|
70
|
+
__cold static void choice_fcntl(void) {
|
|
71
|
+
assert(!op_setlk && !op_setlkw && !op_getlk);
|
|
72
|
+
if ((globals.runtime_flags & MDBX_DBG_LEGACY_MULTIOPEN) == 0
|
|
73
|
+
#if defined(__linux__) || defined(__gnu_linux__)
|
|
74
|
+
&& globals.linux_kernel_version > 0x030f0000 /* OFD locks are available since 3.15, but engages here
|
|
75
|
+
only for 3.16 and later kernels (i.e. LTS) because
|
|
76
|
+
of reliability reasons */
|
|
77
|
+
#endif /* linux */
|
|
78
|
+
) {
|
|
79
|
+
op_setlk = MDBX_F_OFD_SETLK;
|
|
80
|
+
op_setlkw = MDBX_F_OFD_SETLKW;
|
|
81
|
+
op_getlk = MDBX_F_OFD_GETLK;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
op_setlk = MDBX_F_SETLK;
|
|
85
|
+
op_setlkw = MDBX_F_SETLKW;
|
|
86
|
+
op_getlk = MDBX_F_GETLK;
|
|
87
|
+
}
|
|
88
|
+
#else
|
|
89
|
+
#define op_setlk MDBX_F_SETLK
|
|
90
|
+
#define op_setlkw MDBX_F_SETLKW
|
|
91
|
+
#define op_getlk MDBX_F_GETLK
|
|
92
|
+
#endif /* MDBX_USE_OFDLOCKS */
|
|
93
|
+
|
|
94
|
+
static int lck_op(const mdbx_filehandle_t fd, int cmd, const int lck, const off_t offset, off_t len) {
|
|
95
|
+
STATIC_ASSERT(sizeof(off_t) >= sizeof(void *) && sizeof(off_t) >= sizeof(size_t));
|
|
96
|
+
#if defined(__ANDROID_API__) && __ANDROID_API__ < 24
|
|
97
|
+
STATIC_ASSERT_MSG((sizeof(off_t) * CHAR_BIT == MDBX_WORDBITS),
|
|
98
|
+
"The bitness of system `off_t` type is mismatch. Please "
|
|
99
|
+
"fix build and/or NDK configuration.");
|
|
100
|
+
#endif /* Android && API < 24 */
|
|
101
|
+
assert(offset >= 0 && len > 0);
|
|
102
|
+
assert((uint64_t)offset < (uint64_t)INT64_MAX && (uint64_t)len < (uint64_t)INT64_MAX &&
|
|
103
|
+
(uint64_t)(offset + len) > (uint64_t)offset);
|
|
104
|
+
|
|
105
|
+
assert((uint64_t)offset < (uint64_t)OFF_T_MAX && (uint64_t)len <= (uint64_t)OFF_T_MAX &&
|
|
106
|
+
(uint64_t)(offset + len) <= (uint64_t)OFF_T_MAX);
|
|
107
|
+
|
|
108
|
+
assert((uint64_t)((off_t)((uint64_t)offset + (uint64_t)len)) == ((uint64_t)offset + (uint64_t)len));
|
|
109
|
+
|
|
110
|
+
jitter4testing(true);
|
|
111
|
+
for (;;) {
|
|
112
|
+
MDBX_STRUCT_FLOCK lock_op;
|
|
113
|
+
STATIC_ASSERT_MSG(sizeof(off_t) <= sizeof(lock_op.l_start) && sizeof(off_t) <= sizeof(lock_op.l_len) &&
|
|
114
|
+
OFF_T_MAX == (off_t)OFF_T_MAX,
|
|
115
|
+
"Support for large/64-bit-sized files is misconfigured "
|
|
116
|
+
"for the target system and/or toolchain. "
|
|
117
|
+
"Please fix it or at least disable it completely.");
|
|
118
|
+
memset(&lock_op, 0, sizeof(lock_op));
|
|
119
|
+
lock_op.l_type = lck;
|
|
120
|
+
lock_op.l_whence = SEEK_SET;
|
|
121
|
+
lock_op.l_start = offset;
|
|
122
|
+
lock_op.l_len = len;
|
|
123
|
+
int rc = MDBX_FCNTL(fd, cmd, &lock_op);
|
|
124
|
+
jitter4testing(true);
|
|
125
|
+
if (rc != -1) {
|
|
126
|
+
if (cmd == op_getlk) {
|
|
127
|
+
/* Checks reader by pid. Returns:
|
|
128
|
+
* MDBX_RESULT_TRUE - if pid is live (reader holds a lock).
|
|
129
|
+
* MDBX_RESULT_FALSE - if pid is dead (a lock could be placed). */
|
|
130
|
+
return (lock_op.l_type == F_UNLCK) ? MDBX_RESULT_FALSE : MDBX_RESULT_TRUE;
|
|
131
|
+
}
|
|
132
|
+
return MDBX_SUCCESS;
|
|
133
|
+
}
|
|
134
|
+
rc = errno;
|
|
135
|
+
#if MDBX_USE_OFDLOCKS
|
|
136
|
+
if (ignore_enosys_and_einval(rc) == MDBX_RESULT_TRUE &&
|
|
137
|
+
(cmd == MDBX_F_OFD_SETLK || cmd == MDBX_F_OFD_SETLKW || cmd == MDBX_F_OFD_GETLK)) {
|
|
138
|
+
/* fallback to non-OFD locks */
|
|
139
|
+
if (cmd == MDBX_F_OFD_SETLK)
|
|
140
|
+
cmd = MDBX_F_SETLK;
|
|
141
|
+
else if (cmd == MDBX_F_OFD_SETLKW)
|
|
142
|
+
cmd = MDBX_F_SETLKW;
|
|
143
|
+
else
|
|
144
|
+
cmd = MDBX_F_GETLK;
|
|
145
|
+
op_setlk = MDBX_F_SETLK;
|
|
146
|
+
op_setlkw = MDBX_F_SETLKW;
|
|
147
|
+
op_getlk = MDBX_F_GETLK;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
#endif /* MDBX_USE_OFDLOCKS */
|
|
151
|
+
if (rc != EINTR || cmd == op_setlkw) {
|
|
152
|
+
assert(MDBX_IS_ERROR(rc));
|
|
153
|
+
return rc;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait) {
|
|
159
|
+
#if MDBX_USE_OFDLOCKS
|
|
160
|
+
if (unlikely(op_setlk == 0))
|
|
161
|
+
choice_fcntl();
|
|
162
|
+
#endif /* MDBX_USE_OFDLOCKS */
|
|
163
|
+
return lck_op(fd, wait ? op_setlkw : op_setlk, F_WRLCK, 0, OFF_T_MAX);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
MDBX_INTERNAL int lck_rpid_set(MDBX_env *env) {
|
|
167
|
+
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
|
168
|
+
assert(env->pid > 0);
|
|
169
|
+
if (unlikely(osal_getpid() != env->pid))
|
|
170
|
+
return MDBX_PANIC;
|
|
171
|
+
return lck_op(env->lck_mmap.fd, op_setlk, F_WRLCK, env->pid, 1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
MDBX_INTERNAL int lck_rpid_clear(MDBX_env *env) {
|
|
175
|
+
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
|
176
|
+
assert(env->pid > 0);
|
|
177
|
+
return lck_op(env->lck_mmap.fd, op_setlk, F_UNLCK, env->pid, 1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
MDBX_INTERNAL int lck_rpid_check(MDBX_env *env, uint32_t pid) {
|
|
181
|
+
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
|
182
|
+
assert(pid > 0);
|
|
183
|
+
return lck_op(env->lck_mmap.fd, op_getlk, F_WRLCK, pid, 1);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/*---------------------------------------------------------------------------*/
|
|
187
|
+
|
|
188
|
+
#if MDBX_LOCKING > MDBX_LOCKING_SYSV
|
|
189
|
+
MDBX_INTERNAL int lck_ipclock_stubinit(osal_ipclock_t *ipc) {
|
|
190
|
+
#if MDBX_LOCKING == MDBX_LOCKING_POSIX1988
|
|
191
|
+
return sem_init(ipc, false, 1) ? errno : 0;
|
|
192
|
+
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
|
|
193
|
+
return pthread_mutex_init(ipc, nullptr);
|
|
194
|
+
#else
|
|
195
|
+
#error "FIXME"
|
|
196
|
+
#endif
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
MDBX_INTERNAL int lck_ipclock_destroy(osal_ipclock_t *ipc) {
|
|
200
|
+
#if MDBX_LOCKING == MDBX_LOCKING_POSIX1988
|
|
201
|
+
return sem_destroy(ipc) ? errno : 0;
|
|
202
|
+
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
|
|
203
|
+
return pthread_mutex_destroy(ipc);
|
|
204
|
+
#else
|
|
205
|
+
#error "FIXME"
|
|
206
|
+
#endif
|
|
207
|
+
}
|
|
208
|
+
#endif /* MDBX_LOCKING > MDBX_LOCKING_SYSV */
|
|
209
|
+
|
|
210
|
+
static int check_fstat(MDBX_env *env) {
|
|
211
|
+
struct stat st;
|
|
212
|
+
|
|
213
|
+
int rc = MDBX_SUCCESS;
|
|
214
|
+
if (fstat(env->lazy_fd, &st)) {
|
|
215
|
+
rc = errno;
|
|
216
|
+
ERROR("fstat(%s), err %d", "DXB", rc);
|
|
217
|
+
return rc;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (!S_ISREG(st.st_mode) || st.st_nlink < 1) {
|
|
221
|
+
#ifdef EBADFD
|
|
222
|
+
rc = EBADFD;
|
|
223
|
+
#else
|
|
224
|
+
rc = EPERM;
|
|
225
|
+
#endif
|
|
226
|
+
ERROR("%s %s, err %d", "DXB", (st.st_nlink < 1) ? "file was removed" : "not a regular file", rc);
|
|
227
|
+
return rc;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (st.st_size < (off_t)(MDBX_MIN_PAGESIZE * NUM_METAS)) {
|
|
231
|
+
VERBOSE("dxb-file is too short (%u), exclusive-lock needed", (unsigned)st.st_size);
|
|
232
|
+
rc = MDBX_RESULT_TRUE;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
//----------------------------------------------------------------------------
|
|
236
|
+
|
|
237
|
+
if (fstat(env->lck_mmap.fd, &st)) {
|
|
238
|
+
rc = errno;
|
|
239
|
+
ERROR("fstat(%s), err %d", "LCK", rc);
|
|
240
|
+
return rc;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (!S_ISREG(st.st_mode) || st.st_nlink < 1) {
|
|
244
|
+
#ifdef EBADFD
|
|
245
|
+
rc = EBADFD;
|
|
246
|
+
#else
|
|
247
|
+
rc = EPERM;
|
|
248
|
+
#endif
|
|
249
|
+
ERROR("%s %s, err %d", "LCK", (st.st_nlink < 1) ? "file was removed" : "not a regular file", rc);
|
|
250
|
+
return rc;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* Checking file size for detect the situation when we got the shared lock
|
|
254
|
+
* immediately after lck_destroy(). */
|
|
255
|
+
if (st.st_size < (off_t)(sizeof(lck_t) + sizeof(reader_slot_t))) {
|
|
256
|
+
VERBOSE("lck-file is too short (%u), exclusive-lock needed", (unsigned)st.st_size);
|
|
257
|
+
rc = MDBX_RESULT_TRUE;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return rc;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
__cold MDBX_INTERNAL int lck_seize(MDBX_env *env) {
|
|
264
|
+
assert(env->lazy_fd != INVALID_HANDLE_VALUE);
|
|
265
|
+
if (unlikely(osal_getpid() != env->pid))
|
|
266
|
+
return MDBX_PANIC;
|
|
267
|
+
|
|
268
|
+
int rc = MDBX_SUCCESS;
|
|
269
|
+
#if defined(__linux__) || defined(__gnu_linux__)
|
|
270
|
+
if (unlikely(globals.running_on_WSL1)) {
|
|
271
|
+
rc = ENOLCK /* No record locks available */;
|
|
272
|
+
ERROR("%s, err %u",
|
|
273
|
+
"WSL1 (Windows Subsystem for Linux) is mad and trouble-full, "
|
|
274
|
+
"injecting failure to avoid data loss",
|
|
275
|
+
rc);
|
|
276
|
+
return rc;
|
|
277
|
+
}
|
|
278
|
+
#endif /* Linux */
|
|
279
|
+
|
|
280
|
+
#if MDBX_USE_OFDLOCKS
|
|
281
|
+
if (unlikely(op_setlk == 0))
|
|
282
|
+
choice_fcntl();
|
|
283
|
+
#endif /* MDBX_USE_OFDLOCKS */
|
|
284
|
+
|
|
285
|
+
if (env->lck_mmap.fd == INVALID_HANDLE_VALUE) {
|
|
286
|
+
/* LY: without-lck mode (e.g. exclusive or on read-only filesystem) */
|
|
287
|
+
rc = lck_op(env->lazy_fd, op_setlk, (env->flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0, OFF_T_MAX);
|
|
288
|
+
if (rc != MDBX_SUCCESS) {
|
|
289
|
+
ERROR("%s, err %u", "without-lck", rc);
|
|
290
|
+
eASSERT(env, MDBX_IS_ERROR(rc));
|
|
291
|
+
return rc;
|
|
292
|
+
}
|
|
293
|
+
return MDBX_RESULT_TRUE /* Done: return with exclusive locking. */;
|
|
294
|
+
}
|
|
295
|
+
#if defined(_POSIX_PRIORITY_SCHEDULING) && _POSIX_PRIORITY_SCHEDULING > 0
|
|
296
|
+
sched_yield();
|
|
297
|
+
#endif
|
|
298
|
+
|
|
299
|
+
retry:
|
|
300
|
+
if (rc == MDBX_RESULT_TRUE) {
|
|
301
|
+
rc = lck_op(env->lck_mmap.fd, op_setlk, F_UNLCK, 0, 1);
|
|
302
|
+
if (rc != MDBX_SUCCESS) {
|
|
303
|
+
ERROR("%s, err %u", "unlock-before-retry", rc);
|
|
304
|
+
eASSERT(env, MDBX_IS_ERROR(rc));
|
|
305
|
+
return rc;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* Firstly try to get exclusive locking. */
|
|
310
|
+
rc = lck_op(env->lck_mmap.fd, op_setlk, F_WRLCK, 0, 1);
|
|
311
|
+
if (rc == MDBX_SUCCESS) {
|
|
312
|
+
rc = check_fstat(env);
|
|
313
|
+
if (MDBX_IS_ERROR(rc))
|
|
314
|
+
return rc;
|
|
315
|
+
|
|
316
|
+
continue_dxb_exclusive:
|
|
317
|
+
rc = lck_op(env->lazy_fd, op_setlk, (env->flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0, OFF_T_MAX);
|
|
318
|
+
if (rc == MDBX_SUCCESS)
|
|
319
|
+
return MDBX_RESULT_TRUE /* Done: return with exclusive locking. */;
|
|
320
|
+
|
|
321
|
+
int err = check_fstat(env);
|
|
322
|
+
if (MDBX_IS_ERROR(err))
|
|
323
|
+
return err;
|
|
324
|
+
|
|
325
|
+
/* the cause may be a collision with POSIX's file-lock recovery. */
|
|
326
|
+
if (!(rc == EAGAIN || rc == EACCES || rc == EBUSY || rc == EWOULDBLOCK || rc == EDEADLK)) {
|
|
327
|
+
ERROR("%s, err %u", "dxb-exclusive", rc);
|
|
328
|
+
eASSERT(env, MDBX_IS_ERROR(rc));
|
|
329
|
+
return rc;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/* Fallback to lck-shared */
|
|
333
|
+
} else if (!(rc == EAGAIN || rc == EACCES || rc == EBUSY || rc == EWOULDBLOCK || rc == EDEADLK)) {
|
|
334
|
+
ERROR("%s, err %u", "try-exclusive", rc);
|
|
335
|
+
eASSERT(env, MDBX_IS_ERROR(rc));
|
|
336
|
+
return rc;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/* Here could be one of two:
|
|
340
|
+
* - lck_destroy() from the another process was hold the lock
|
|
341
|
+
* during a destruction.
|
|
342
|
+
* - either lck_seize() from the another process was got the exclusive
|
|
343
|
+
* lock and doing initialization.
|
|
344
|
+
* For distinguish these cases will use size of the lck-file later. */
|
|
345
|
+
|
|
346
|
+
/* Wait for lck-shared now. */
|
|
347
|
+
/* Here may be await during transient processes, for instance until another
|
|
348
|
+
* competing process doesn't call lck_downgrade(). */
|
|
349
|
+
rc = lck_op(env->lck_mmap.fd, op_setlkw, F_RDLCK, 0, 1);
|
|
350
|
+
if (rc != MDBX_SUCCESS) {
|
|
351
|
+
ERROR("%s, err %u", "try-shared", rc);
|
|
352
|
+
eASSERT(env, MDBX_IS_ERROR(rc));
|
|
353
|
+
return rc;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
rc = check_fstat(env);
|
|
357
|
+
if (rc == MDBX_RESULT_TRUE)
|
|
358
|
+
goto retry;
|
|
359
|
+
if (rc != MDBX_SUCCESS) {
|
|
360
|
+
ERROR("%s, err %u", "lck_fstat", rc);
|
|
361
|
+
return rc;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/* got shared, retry exclusive */
|
|
365
|
+
rc = lck_op(env->lck_mmap.fd, op_setlk, F_WRLCK, 0, 1);
|
|
366
|
+
if (rc == MDBX_SUCCESS)
|
|
367
|
+
goto continue_dxb_exclusive;
|
|
368
|
+
|
|
369
|
+
if (!(rc == EAGAIN || rc == EACCES || rc == EBUSY || rc == EWOULDBLOCK || rc == EDEADLK)) {
|
|
370
|
+
ERROR("%s, err %u", "try-exclusive", rc);
|
|
371
|
+
eASSERT(env, MDBX_IS_ERROR(rc));
|
|
372
|
+
return rc;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/* Lock against another process operating in without-lck or exclusive mode. */
|
|
376
|
+
rc = lck_op(env->lazy_fd, op_setlk, (env->flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, env->pid, 1);
|
|
377
|
+
if (rc != MDBX_SUCCESS) {
|
|
378
|
+
ERROR("%s, err %u", "lock-against-without-lck", rc);
|
|
379
|
+
eASSERT(env, MDBX_IS_ERROR(rc));
|
|
380
|
+
return rc;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/* Done: return with shared locking. */
|
|
384
|
+
return MDBX_RESULT_FALSE;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
MDBX_INTERNAL int lck_downgrade(MDBX_env *env) {
|
|
388
|
+
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
|
389
|
+
if (unlikely(osal_getpid() != env->pid))
|
|
390
|
+
return MDBX_PANIC;
|
|
391
|
+
|
|
392
|
+
int rc = MDBX_SUCCESS;
|
|
393
|
+
if ((env->flags & MDBX_EXCLUSIVE) == 0) {
|
|
394
|
+
rc = lck_op(env->lazy_fd, op_setlk, F_UNLCK, 0, env->pid);
|
|
395
|
+
if (rc == MDBX_SUCCESS)
|
|
396
|
+
rc = lck_op(env->lazy_fd, op_setlk, F_UNLCK, env->pid + 1, OFF_T_MAX - env->pid - 1);
|
|
397
|
+
}
|
|
398
|
+
if (rc == MDBX_SUCCESS)
|
|
399
|
+
rc = lck_op(env->lck_mmap.fd, op_setlk, F_RDLCK, 0, 1);
|
|
400
|
+
if (unlikely(rc != 0)) {
|
|
401
|
+
ERROR("%s, err %u", "lck", rc);
|
|
402
|
+
assert(MDBX_IS_ERROR(rc));
|
|
403
|
+
}
|
|
404
|
+
return rc;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
MDBX_INTERNAL int lck_upgrade(MDBX_env *env, bool dont_wait) {
|
|
408
|
+
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
|
409
|
+
if (unlikely(osal_getpid() != env->pid))
|
|
410
|
+
return MDBX_PANIC;
|
|
411
|
+
|
|
412
|
+
const int cmd = dont_wait ? op_setlk : op_setlkw;
|
|
413
|
+
int rc = lck_op(env->lck_mmap.fd, cmd, F_WRLCK, 0, 1);
|
|
414
|
+
if (rc == MDBX_SUCCESS && (env->flags & MDBX_EXCLUSIVE) == 0) {
|
|
415
|
+
rc = (env->pid > 1) ? lck_op(env->lazy_fd, cmd, F_WRLCK, 0, env->pid - 1) : MDBX_SUCCESS;
|
|
416
|
+
if (rc == MDBX_SUCCESS) {
|
|
417
|
+
rc = lck_op(env->lazy_fd, cmd, F_WRLCK, env->pid + 1, OFF_T_MAX - env->pid - 1);
|
|
418
|
+
if (rc != MDBX_SUCCESS && env->pid > 1 && lck_op(env->lazy_fd, op_setlk, F_UNLCK, 0, env->pid - 1))
|
|
419
|
+
rc = MDBX_PANIC;
|
|
420
|
+
}
|
|
421
|
+
if (rc != MDBX_SUCCESS && lck_op(env->lck_mmap.fd, op_setlk, F_RDLCK, 0, 1))
|
|
422
|
+
rc = MDBX_PANIC;
|
|
423
|
+
}
|
|
424
|
+
if (unlikely(rc != 0)) {
|
|
425
|
+
ERROR("%s, err %u", "lck", rc);
|
|
426
|
+
assert(MDBX_IS_ERROR(rc));
|
|
427
|
+
}
|
|
428
|
+
return rc;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
__cold MDBX_INTERNAL int lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor, const uint32_t current_pid) {
|
|
432
|
+
eASSERT(env, osal_getpid() == current_pid);
|
|
433
|
+
int rc = MDBX_SUCCESS;
|
|
434
|
+
struct stat lck_info;
|
|
435
|
+
lck_t *lck = env->lck;
|
|
436
|
+
if (lck && lck == env->lck_mmap.lck && !inprocess_neighbor &&
|
|
437
|
+
/* try get exclusive access */
|
|
438
|
+
lck_op(env->lck_mmap.fd, op_setlk, F_WRLCK, 0, OFF_T_MAX) == 0 &&
|
|
439
|
+
/* if LCK was not removed */
|
|
440
|
+
fstat(env->lck_mmap.fd, &lck_info) == 0 && lck_info.st_nlink > 0 &&
|
|
441
|
+
lck_op(env->lazy_fd, op_setlk, (env->flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0, OFF_T_MAX) == 0) {
|
|
442
|
+
|
|
443
|
+
VERBOSE("%p got exclusive, drown ipc-locks", (void *)env);
|
|
444
|
+
eASSERT(env, current_pid == env->pid);
|
|
445
|
+
#if MDBX_LOCKING == MDBX_LOCKING_SYSV
|
|
446
|
+
if (env->me_sysv_ipc.semid != -1)
|
|
447
|
+
rc = semctl(env->me_sysv_ipc.semid, 2, IPC_RMID) ? errno : 0;
|
|
448
|
+
#else
|
|
449
|
+
rc = lck_ipclock_destroy(&lck->rdt_lock);
|
|
450
|
+
if (rc == 0)
|
|
451
|
+
rc = lck_ipclock_destroy(&lck->wrt_lock);
|
|
452
|
+
#endif /* MDBX_LOCKING */
|
|
453
|
+
|
|
454
|
+
eASSERT(env, rc == 0);
|
|
455
|
+
if (rc == 0) {
|
|
456
|
+
const bool synced = lck->unsynced_pages.weak == 0;
|
|
457
|
+
osal_munmap(&env->lck_mmap);
|
|
458
|
+
if (synced && env->lck_mmap.fd != INVALID_HANDLE_VALUE)
|
|
459
|
+
rc = ftruncate(env->lck_mmap.fd, 0) ? errno : 0;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
jitter4testing(false);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
#if MDBX_LOCKING == MDBX_LOCKING_SYSV
|
|
466
|
+
env->me_sysv_ipc.semid = -1;
|
|
467
|
+
#endif /* MDBX_LOCKING */
|
|
468
|
+
|
|
469
|
+
if (current_pid != env->pid) {
|
|
470
|
+
eASSERT(env, !inprocess_neighbor);
|
|
471
|
+
NOTICE("drown env %p after-fork pid %d -> %d", __Wpedantic_format_voidptr(env), env->pid, current_pid);
|
|
472
|
+
inprocess_neighbor = nullptr;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/* 1) POSIX's fcntl() locks (i.e. when op_setlk == F_SETLK) should be restored
|
|
476
|
+
* after file was closed.
|
|
477
|
+
*
|
|
478
|
+
* 2) File locks would be released (by kernel) while the file-descriptors will
|
|
479
|
+
* be closed. But to avoid false-positive EACCESS and EDEADLK from the kernel,
|
|
480
|
+
* locks should be released here explicitly with properly order. */
|
|
481
|
+
|
|
482
|
+
/* close dxb and restore lock */
|
|
483
|
+
if (env->dsync_fd != INVALID_HANDLE_VALUE) {
|
|
484
|
+
if (unlikely(close(env->dsync_fd) != 0) && rc == MDBX_SUCCESS)
|
|
485
|
+
rc = errno;
|
|
486
|
+
env->dsync_fd = INVALID_HANDLE_VALUE;
|
|
487
|
+
}
|
|
488
|
+
if (env->lazy_fd != INVALID_HANDLE_VALUE) {
|
|
489
|
+
if (unlikely(close(env->lazy_fd) != 0) && rc == MDBX_SUCCESS)
|
|
490
|
+
rc = errno;
|
|
491
|
+
env->lazy_fd = INVALID_HANDLE_VALUE;
|
|
492
|
+
if (op_setlk == F_SETLK && inprocess_neighbor && rc == MDBX_SUCCESS) {
|
|
493
|
+
/* restore file-lock */
|
|
494
|
+
rc = lck_op(inprocess_neighbor->lazy_fd, F_SETLKW, (inprocess_neighbor->flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK,
|
|
495
|
+
(inprocess_neighbor->flags & MDBX_EXCLUSIVE) ? 0 : inprocess_neighbor->pid,
|
|
496
|
+
(inprocess_neighbor->flags & MDBX_EXCLUSIVE) ? OFF_T_MAX : 1);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/* close clk and restore locks */
|
|
501
|
+
if (env->lck_mmap.fd != INVALID_HANDLE_VALUE) {
|
|
502
|
+
if (unlikely(close(env->lck_mmap.fd) != 0) && rc == MDBX_SUCCESS)
|
|
503
|
+
rc = errno;
|
|
504
|
+
env->lck_mmap.fd = INVALID_HANDLE_VALUE;
|
|
505
|
+
if (op_setlk == F_SETLK && inprocess_neighbor && rc == MDBX_SUCCESS) {
|
|
506
|
+
/* restore file-locks */
|
|
507
|
+
rc = lck_op(inprocess_neighbor->lck_mmap.fd, F_SETLKW, F_RDLCK, 0, 1);
|
|
508
|
+
if (rc == MDBX_SUCCESS && inprocess_neighbor->registered_reader_pid)
|
|
509
|
+
rc = lck_rpid_set(inprocess_neighbor);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (inprocess_neighbor && rc != MDBX_SUCCESS)
|
|
514
|
+
inprocess_neighbor->flags |= ENV_FATAL_ERROR;
|
|
515
|
+
return rc;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/*---------------------------------------------------------------------------*/
|
|
519
|
+
|
|
520
|
+
__cold MDBX_INTERNAL int lck_init(MDBX_env *env, MDBX_env *inprocess_neighbor, int global_uniqueness_flag) {
|
|
521
|
+
#if MDBX_LOCKING == MDBX_LOCKING_SYSV
|
|
522
|
+
int semid = -1;
|
|
523
|
+
/* don't initialize semaphores twice */
|
|
524
|
+
(void)inprocess_neighbor;
|
|
525
|
+
if (global_uniqueness_flag == MDBX_RESULT_TRUE) {
|
|
526
|
+
struct stat st;
|
|
527
|
+
if (fstat(env->lazy_fd, &st))
|
|
528
|
+
return errno;
|
|
529
|
+
sysv_retry_create:
|
|
530
|
+
semid = semget(env->me_sysv_ipc.key, 2, IPC_CREAT | IPC_EXCL | (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)));
|
|
531
|
+
if (unlikely(semid == -1)) {
|
|
532
|
+
int err = errno;
|
|
533
|
+
if (err != EEXIST)
|
|
534
|
+
return err;
|
|
535
|
+
|
|
536
|
+
/* remove and re-create semaphore set */
|
|
537
|
+
semid = semget(env->me_sysv_ipc.key, 2, 0);
|
|
538
|
+
if (semid == -1) {
|
|
539
|
+
err = errno;
|
|
540
|
+
if (err != ENOENT)
|
|
541
|
+
return err;
|
|
542
|
+
goto sysv_retry_create;
|
|
543
|
+
}
|
|
544
|
+
if (semctl(semid, 2, IPC_RMID)) {
|
|
545
|
+
err = errno;
|
|
546
|
+
if (err != EIDRM)
|
|
547
|
+
return err;
|
|
548
|
+
}
|
|
549
|
+
goto sysv_retry_create;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
unsigned short val_array[2] = {1, 1};
|
|
553
|
+
if (semctl(semid, 2, SETALL, val_array))
|
|
554
|
+
return errno;
|
|
555
|
+
} else {
|
|
556
|
+
semid = semget(env->me_sysv_ipc.key, 2, 0);
|
|
557
|
+
if (semid == -1)
|
|
558
|
+
return errno;
|
|
559
|
+
|
|
560
|
+
/* check read & write access */
|
|
561
|
+
struct semid_ds data[2];
|
|
562
|
+
if (semctl(semid, 2, IPC_STAT, data) || semctl(semid, 2, IPC_SET, data))
|
|
563
|
+
return errno;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
env->me_sysv_ipc.semid = semid;
|
|
567
|
+
return MDBX_SUCCESS;
|
|
568
|
+
|
|
569
|
+
#elif MDBX_LOCKING == MDBX_LOCKING_FUTEX
|
|
570
|
+
(void)inprocess_neighbor;
|
|
571
|
+
if (global_uniqueness_flag != MDBX_RESULT_TRUE)
|
|
572
|
+
return MDBX_SUCCESS;
|
|
573
|
+
#error "FIXME: Not implemented"
|
|
574
|
+
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
|
|
575
|
+
|
|
576
|
+
/* don't initialize semaphores twice */
|
|
577
|
+
(void)inprocess_neighbor;
|
|
578
|
+
if (global_uniqueness_flag == MDBX_RESULT_TRUE) {
|
|
579
|
+
if (sem_init(&env->lck_mmap.lck->rdt_lock, true, 1))
|
|
580
|
+
return errno;
|
|
581
|
+
if (sem_init(&env->lck_mmap.lck->wrt_lock, true, 1))
|
|
582
|
+
return errno;
|
|
583
|
+
}
|
|
584
|
+
return MDBX_SUCCESS;
|
|
585
|
+
|
|
586
|
+
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
|
|
587
|
+
if (inprocess_neighbor)
|
|
588
|
+
return MDBX_SUCCESS /* don't need any initialization for mutexes
|
|
589
|
+
if LCK already opened/used inside current process */
|
|
590
|
+
;
|
|
591
|
+
|
|
592
|
+
/* FIXME: Unfortunately, there is no other reliable way but to long testing
|
|
593
|
+
* on each platform. On the other hand, behavior like FreeBSD is incorrect
|
|
594
|
+
* and we can expect it to be rare. Moreover, even on FreeBSD without
|
|
595
|
+
* additional in-process initialization, the probability of an problem
|
|
596
|
+
* occurring is vanishingly small, and the symptom is a return of EINVAL
|
|
597
|
+
* while locking a mutex. In other words, in the worst case, the problem
|
|
598
|
+
* results in an EINVAL error at the start of the transaction, but NOT data
|
|
599
|
+
* loss, nor database corruption, nor other fatal troubles. Thus, the code
|
|
600
|
+
* below I am inclined to think the workaround for erroneous platforms (like
|
|
601
|
+
* FreeBSD), rather than a defect of libmdbx. */
|
|
602
|
+
#if defined(__FreeBSD__)
|
|
603
|
+
/* seems that shared mutexes on FreeBSD required in-process initialization */
|
|
604
|
+
(void)global_uniqueness_flag;
|
|
605
|
+
#else
|
|
606
|
+
/* shared mutexes on many other platforms (including Darwin and Linux's
|
|
607
|
+
* futexes) doesn't need any addition in-process initialization */
|
|
608
|
+
if (global_uniqueness_flag != MDBX_RESULT_TRUE)
|
|
609
|
+
return MDBX_SUCCESS;
|
|
610
|
+
#endif
|
|
611
|
+
|
|
612
|
+
pthread_mutexattr_t ma;
|
|
613
|
+
int rc = pthread_mutexattr_init(&ma);
|
|
614
|
+
if (rc)
|
|
615
|
+
return rc;
|
|
616
|
+
|
|
617
|
+
rc = pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED);
|
|
618
|
+
if (rc)
|
|
619
|
+
goto bailout;
|
|
620
|
+
|
|
621
|
+
#if MDBX_LOCKING == MDBX_LOCKING_POSIX2008
|
|
622
|
+
#if defined(PTHREAD_MUTEX_ROBUST) || defined(pthread_mutexattr_setrobust)
|
|
623
|
+
rc = pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST);
|
|
624
|
+
#elif defined(PTHREAD_MUTEX_ROBUST_NP) || defined(pthread_mutexattr_setrobust_np)
|
|
625
|
+
rc = pthread_mutexattr_setrobust_np(&ma, PTHREAD_MUTEX_ROBUST_NP);
|
|
626
|
+
#elif _POSIX_THREAD_PROCESS_SHARED < 200809L
|
|
627
|
+
rc = pthread_mutexattr_setrobust_np(&ma, PTHREAD_MUTEX_ROBUST_NP);
|
|
628
|
+
#else
|
|
629
|
+
rc = pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST);
|
|
630
|
+
#endif
|
|
631
|
+
if (rc)
|
|
632
|
+
goto bailout;
|
|
633
|
+
#endif /* MDBX_LOCKING == MDBX_LOCKING_POSIX2008 */
|
|
634
|
+
|
|
635
|
+
#if defined(_POSIX_THREAD_PRIO_INHERIT) && _POSIX_THREAD_PRIO_INHERIT >= 0 && !defined(MDBX_SAFE4QEMU)
|
|
636
|
+
rc = pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT);
|
|
637
|
+
if (rc == ENOTSUP)
|
|
638
|
+
rc = pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_NONE);
|
|
639
|
+
if (rc && rc != ENOTSUP)
|
|
640
|
+
goto bailout;
|
|
641
|
+
#endif /* PTHREAD_PRIO_INHERIT */
|
|
642
|
+
|
|
643
|
+
rc = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK);
|
|
644
|
+
if (rc && rc != ENOTSUP)
|
|
645
|
+
goto bailout;
|
|
646
|
+
|
|
647
|
+
rc = pthread_mutex_init(&env->lck_mmap.lck->rdt_lock, &ma);
|
|
648
|
+
if (rc)
|
|
649
|
+
goto bailout;
|
|
650
|
+
rc = pthread_mutex_init(&env->lck_mmap.lck->wrt_lock, &ma);
|
|
651
|
+
|
|
652
|
+
bailout:
|
|
653
|
+
pthread_mutexattr_destroy(&ma);
|
|
654
|
+
return rc;
|
|
655
|
+
#else
|
|
656
|
+
#error "FIXME"
|
|
657
|
+
#endif /* MDBX_LOCKING > 0 */
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
__cold static int osal_ipclock_failed(MDBX_env *env, osal_ipclock_t *ipc, const int err) {
|
|
661
|
+
int rc = err;
|
|
662
|
+
#if MDBX_LOCKING == MDBX_LOCKING_POSIX2008 || MDBX_LOCKING == MDBX_LOCKING_SYSV
|
|
663
|
+
|
|
664
|
+
#ifndef EOWNERDEAD
|
|
665
|
+
#define EOWNERDEAD MDBX_RESULT_TRUE
|
|
666
|
+
#endif /* EOWNERDEAD */
|
|
667
|
+
|
|
668
|
+
if (err == EOWNERDEAD) {
|
|
669
|
+
/* We own the mutex. Clean up after dead previous owner. */
|
|
670
|
+
const bool rlocked = ipc == &env->lck->rdt_lock;
|
|
671
|
+
rc = MDBX_SUCCESS;
|
|
672
|
+
if (!rlocked) {
|
|
673
|
+
if (unlikely(env->txn)) {
|
|
674
|
+
/* env is hosed if the dead thread was ours */
|
|
675
|
+
env->flags |= ENV_FATAL_ERROR;
|
|
676
|
+
env->txn = nullptr;
|
|
677
|
+
rc = MDBX_PANIC;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
WARNING("%clock owner died, %s", (rlocked ? 'r' : 'w'), (rc ? "this process' env is hosed" : "recovering"));
|
|
681
|
+
|
|
682
|
+
int check_rc = mvcc_cleanup_dead(env, rlocked, nullptr);
|
|
683
|
+
check_rc = (check_rc == MDBX_SUCCESS) ? MDBX_RESULT_TRUE : check_rc;
|
|
684
|
+
|
|
685
|
+
#if MDBX_LOCKING == MDBX_LOCKING_SYSV
|
|
686
|
+
rc = (rc == MDBX_SUCCESS) ? check_rc : rc;
|
|
687
|
+
#else
|
|
688
|
+
#if defined(PTHREAD_MUTEX_ROBUST) || defined(pthread_mutex_consistent)
|
|
689
|
+
int mreco_rc = pthread_mutex_consistent(ipc);
|
|
690
|
+
#elif defined(PTHREAD_MUTEX_ROBUST_NP) || defined(pthread_mutex_consistent_np)
|
|
691
|
+
int mreco_rc = pthread_mutex_consistent_np(ipc);
|
|
692
|
+
#elif _POSIX_THREAD_PROCESS_SHARED < 200809L
|
|
693
|
+
int mreco_rc = pthread_mutex_consistent_np(ipc);
|
|
694
|
+
#else
|
|
695
|
+
int mreco_rc = pthread_mutex_consistent(ipc);
|
|
696
|
+
#endif
|
|
697
|
+
check_rc = (mreco_rc == 0) ? check_rc : mreco_rc;
|
|
698
|
+
|
|
699
|
+
if (unlikely(mreco_rc))
|
|
700
|
+
ERROR("lock recovery failed, %s", mdbx_strerror(mreco_rc));
|
|
701
|
+
|
|
702
|
+
rc = (rc == MDBX_SUCCESS) ? check_rc : rc;
|
|
703
|
+
if (MDBX_IS_ERROR(rc))
|
|
704
|
+
pthread_mutex_unlock(ipc);
|
|
705
|
+
#endif /* MDBX_LOCKING == MDBX_LOCKING_POSIX2008 */
|
|
706
|
+
return rc;
|
|
707
|
+
}
|
|
708
|
+
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001
|
|
709
|
+
(void)ipc;
|
|
710
|
+
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
|
|
711
|
+
(void)ipc;
|
|
712
|
+
#elif MDBX_LOCKING == MDBX_LOCKING_FUTEX
|
|
713
|
+
#ifdef _MSC_VER
|
|
714
|
+
#pragma message("warning: TODO")
|
|
715
|
+
#else
|
|
716
|
+
#warning "TODO"
|
|
717
|
+
#endif
|
|
718
|
+
(void)ipc;
|
|
719
|
+
#else
|
|
720
|
+
#error "FIXME"
|
|
721
|
+
#endif /* MDBX_LOCKING */
|
|
722
|
+
|
|
723
|
+
ERROR("mutex (un)lock failed, %s", mdbx_strerror(err));
|
|
724
|
+
if (rc != EDEADLK)
|
|
725
|
+
env->flags |= ENV_FATAL_ERROR;
|
|
726
|
+
return rc;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
|
|
730
|
+
MDBX_INTERNAL int osal_check_tid4bionic(void) {
|
|
731
|
+
/* avoid 32-bit Bionic bug/hang with 32-pit TID */
|
|
732
|
+
if (sizeof(pthread_mutex_t) < sizeof(pid_t) + sizeof(unsigned)) {
|
|
733
|
+
pid_t tid = gettid();
|
|
734
|
+
if (unlikely(tid > 0xffff)) {
|
|
735
|
+
FATAL("Raise the ENOSYS(%d) error to avoid hang due "
|
|
736
|
+
"the 32-bit Bionic/Android bug with tid/thread_id 0x%08x(%i) "
|
|
737
|
+
"that don’t fit in 16 bits, see "
|
|
738
|
+
"https://android.googlesource.com/platform/bionic/+/master/"
|
|
739
|
+
"docs/32-bit-abi.md#is-too-small-for-large-pids",
|
|
740
|
+
ENOSYS, tid, tid);
|
|
741
|
+
return ENOSYS;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return 0;
|
|
745
|
+
}
|
|
746
|
+
#endif /* __ANDROID_API__ || ANDROID) || BIONIC */
|
|
747
|
+
|
|
748
|
+
static int osal_ipclock_lock(MDBX_env *env, osal_ipclock_t *ipc, const bool dont_wait) {
|
|
749
|
+
#if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
|
|
750
|
+
int rc = osal_check_tid4bionic();
|
|
751
|
+
if (likely(rc == 0))
|
|
752
|
+
rc = dont_wait ? pthread_mutex_trylock(ipc) : pthread_mutex_lock(ipc);
|
|
753
|
+
rc = (rc == EBUSY && dont_wait) ? MDBX_BUSY : rc;
|
|
754
|
+
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
|
|
755
|
+
int rc = MDBX_SUCCESS;
|
|
756
|
+
if (dont_wait) {
|
|
757
|
+
if (sem_trywait(ipc)) {
|
|
758
|
+
rc = errno;
|
|
759
|
+
if (rc == EAGAIN)
|
|
760
|
+
rc = MDBX_BUSY;
|
|
761
|
+
}
|
|
762
|
+
} else if (sem_wait(ipc))
|
|
763
|
+
rc = errno;
|
|
764
|
+
#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
|
|
765
|
+
struct sembuf op = {
|
|
766
|
+
.sem_num = (ipc != &env->lck->wrt_lock), .sem_op = -1, .sem_flg = dont_wait ? IPC_NOWAIT | SEM_UNDO : SEM_UNDO};
|
|
767
|
+
int rc;
|
|
768
|
+
if (semop(env->me_sysv_ipc.semid, &op, 1)) {
|
|
769
|
+
rc = errno;
|
|
770
|
+
if (dont_wait && rc == EAGAIN)
|
|
771
|
+
rc = MDBX_BUSY;
|
|
772
|
+
} else {
|
|
773
|
+
rc = *ipc ? EOWNERDEAD : MDBX_SUCCESS;
|
|
774
|
+
*ipc = env->pid;
|
|
775
|
+
}
|
|
776
|
+
#else
|
|
777
|
+
#error "FIXME"
|
|
778
|
+
#endif /* MDBX_LOCKING */
|
|
779
|
+
|
|
780
|
+
if (unlikely(rc != MDBX_SUCCESS && rc != MDBX_BUSY))
|
|
781
|
+
rc = osal_ipclock_failed(env, ipc, rc);
|
|
782
|
+
return rc;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
static int osal_ipclock_unlock(MDBX_env *env, osal_ipclock_t *ipc) {
|
|
786
|
+
int err = MDBX_ENOSYS;
|
|
787
|
+
#if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
|
|
788
|
+
err = pthread_mutex_unlock(ipc);
|
|
789
|
+
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
|
|
790
|
+
err = sem_post(ipc) ? errno : MDBX_SUCCESS;
|
|
791
|
+
#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
|
|
792
|
+
if (unlikely(*ipc != (pid_t)env->pid || env->me_sysv_ipc.key == -1))
|
|
793
|
+
err = EPERM;
|
|
794
|
+
else {
|
|
795
|
+
*ipc = 0;
|
|
796
|
+
struct sembuf op = {.sem_num = (ipc != &env->lck->wrt_lock), .sem_op = 1, .sem_flg = SEM_UNDO};
|
|
797
|
+
err = semop(env->me_sysv_ipc.semid, &op, 1) ? errno : MDBX_SUCCESS;
|
|
798
|
+
}
|
|
799
|
+
#else
|
|
800
|
+
#error "FIXME"
|
|
801
|
+
#endif /* MDBX_LOCKING */
|
|
802
|
+
int rc = err;
|
|
803
|
+
if (unlikely(rc != MDBX_SUCCESS)) {
|
|
804
|
+
const uint32_t current_pid = osal_getpid();
|
|
805
|
+
if (current_pid == env->pid || LOG_ENABLED(MDBX_LOG_NOTICE))
|
|
806
|
+
debug_log((current_pid == env->pid) ? MDBX_LOG_FATAL : (rc = MDBX_SUCCESS, MDBX_LOG_NOTICE), "ipc-unlock()",
|
|
807
|
+
__LINE__, "failed: env %p, lck-%s %p, err %d\n", __Wpedantic_format_voidptr(env),
|
|
808
|
+
(env->lck == env->lck_mmap.lck) ? "mmap" : "stub", __Wpedantic_format_voidptr(env->lck), err);
|
|
809
|
+
}
|
|
810
|
+
return rc;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
MDBX_INTERNAL int lck_rdt_lock(MDBX_env *env) {
|
|
814
|
+
TRACE("%s", ">>");
|
|
815
|
+
jitter4testing(true);
|
|
816
|
+
int rc = osal_ipclock_lock(env, &env->lck->rdt_lock, false);
|
|
817
|
+
TRACE("<< rc %d", rc);
|
|
818
|
+
return rc;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
MDBX_INTERNAL void lck_rdt_unlock(MDBX_env *env) {
|
|
822
|
+
TRACE("%s", ">>");
|
|
823
|
+
int err = osal_ipclock_unlock(env, &env->lck->rdt_lock);
|
|
824
|
+
TRACE("<< err %d", err);
|
|
825
|
+
if (unlikely(err != MDBX_SUCCESS))
|
|
826
|
+
mdbx_panic("%s() failed: err %d\n", __func__, err);
|
|
827
|
+
jitter4testing(true);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
int lck_txn_lock(MDBX_env *env, bool dont_wait) {
|
|
831
|
+
TRACE("%swait %s", dont_wait ? "dont-" : "", ">>");
|
|
832
|
+
jitter4testing(true);
|
|
833
|
+
const int err = osal_ipclock_lock(env, &env->lck->wrt_lock, dont_wait);
|
|
834
|
+
int rc = err;
|
|
835
|
+
if (likely(env->basal_txn && !MDBX_IS_ERROR(err))) {
|
|
836
|
+
eASSERT(env, !env->basal_txn->owner || err == /* если другой поток в этом-же процессе завершился
|
|
837
|
+
не освободив блокировку */
|
|
838
|
+
MDBX_RESULT_TRUE);
|
|
839
|
+
env->basal_txn->owner = osal_thread_self();
|
|
840
|
+
rc = MDBX_SUCCESS;
|
|
841
|
+
}
|
|
842
|
+
TRACE("<< err %d, rc %d", err, rc);
|
|
843
|
+
return rc;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
void lck_txn_unlock(MDBX_env *env) {
|
|
847
|
+
TRACE("%s", ">>");
|
|
848
|
+
if (env->basal_txn) {
|
|
849
|
+
eASSERT(env, env->basal_txn->owner == osal_thread_self());
|
|
850
|
+
env->basal_txn->owner = 0;
|
|
851
|
+
}
|
|
852
|
+
int err = osal_ipclock_unlock(env, &env->lck->wrt_lock);
|
|
853
|
+
TRACE("<< err %d", err);
|
|
854
|
+
if (unlikely(err != MDBX_SUCCESS))
|
|
855
|
+
mdbx_panic("%s() failed: err %d\n", __func__, err);
|
|
856
|
+
jitter4testing(true);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
#endif /* !Windows LCK-implementation */
|