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.
Files changed (220) hide show
  1. package/.github/workflows/ci.yml +32 -0
  2. package/.github/workflows/publish.yml +27 -0
  3. package/.gitmodules +3 -0
  4. package/CMakeLists.txt +53 -0
  5. package/LICENSE +201 -0
  6. package/README.md +639 -0
  7. package/build.js +11 -0
  8. package/deps/libmdbx/.clang-format +3 -0
  9. package/deps/libmdbx/.cmake-format.yaml +3 -0
  10. package/deps/libmdbx/.le.ini +40 -0
  11. package/deps/libmdbx/CMakeLists.txt +1269 -0
  12. package/deps/libmdbx/COPYRIGHT +159 -0
  13. package/deps/libmdbx/ChangeLog.md +2786 -0
  14. package/deps/libmdbx/GNUmakefile +950 -0
  15. package/deps/libmdbx/LICENSE +177 -0
  16. package/deps/libmdbx/Makefile +16 -0
  17. package/deps/libmdbx/NOTICE +39 -0
  18. package/deps/libmdbx/README.md +863 -0
  19. package/deps/libmdbx/TODO.md +43 -0
  20. package/deps/libmdbx/cmake/compiler.cmake +1221 -0
  21. package/deps/libmdbx/cmake/profile.cmake +58 -0
  22. package/deps/libmdbx/cmake/utils.cmake +524 -0
  23. package/deps/libmdbx/conanfile.py +323 -0
  24. package/deps/libmdbx/docs/Doxyfile.in +2734 -0
  25. package/deps/libmdbx/docs/_preface.md +47 -0
  26. package/deps/libmdbx/docs/_restrictions.md +248 -0
  27. package/deps/libmdbx/docs/_starting.md +245 -0
  28. package/deps/libmdbx/docs/_toc.md +34 -0
  29. package/deps/libmdbx/docs/header.html +96 -0
  30. package/deps/libmdbx/example/CMakeLists.txt +6 -0
  31. package/deps/libmdbx/example/README.md +1 -0
  32. package/deps/libmdbx/example/example-mdbx.c +154 -0
  33. package/deps/libmdbx/example/sample-bdb.txt +77 -0
  34. package/deps/libmdbx/mdbx.h +6655 -0
  35. package/deps/libmdbx/mdbx.h++ +6428 -0
  36. package/deps/libmdbx/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch +173 -0
  37. package/deps/libmdbx/src/alloy.c +54 -0
  38. package/deps/libmdbx/src/api-cold.c +543 -0
  39. package/deps/libmdbx/src/api-copy.c +912 -0
  40. package/deps/libmdbx/src/api-cursor.c +754 -0
  41. package/deps/libmdbx/src/api-dbi.c +315 -0
  42. package/deps/libmdbx/src/api-env.c +1434 -0
  43. package/deps/libmdbx/src/api-extra.c +165 -0
  44. package/deps/libmdbx/src/api-key-transform.c +197 -0
  45. package/deps/libmdbx/src/api-misc.c +286 -0
  46. package/deps/libmdbx/src/api-opts.c +575 -0
  47. package/deps/libmdbx/src/api-range-estimate.c +365 -0
  48. package/deps/libmdbx/src/api-txn-data.c +454 -0
  49. package/deps/libmdbx/src/api-txn.c +921 -0
  50. package/deps/libmdbx/src/atomics-ops.h +364 -0
  51. package/deps/libmdbx/src/atomics-types.h +97 -0
  52. package/deps/libmdbx/src/audit.c +109 -0
  53. package/deps/libmdbx/src/bits.md +34 -0
  54. package/deps/libmdbx/src/chk.c +1796 -0
  55. package/deps/libmdbx/src/cogs.c +309 -0
  56. package/deps/libmdbx/src/cogs.h +506 -0
  57. package/deps/libmdbx/src/coherency.c +170 -0
  58. package/deps/libmdbx/src/config.h.in +88 -0
  59. package/deps/libmdbx/src/cursor.c +2396 -0
  60. package/deps/libmdbx/src/cursor.h +391 -0
  61. package/deps/libmdbx/src/dbi.c +717 -0
  62. package/deps/libmdbx/src/dbi.h +142 -0
  63. package/deps/libmdbx/src/debug_begin.h +36 -0
  64. package/deps/libmdbx/src/debug_end.h +15 -0
  65. package/deps/libmdbx/src/dpl.c +486 -0
  66. package/deps/libmdbx/src/dpl.h +134 -0
  67. package/deps/libmdbx/src/dxb.c +1335 -0
  68. package/deps/libmdbx/src/env.c +607 -0
  69. package/deps/libmdbx/src/essentials.h +125 -0
  70. package/deps/libmdbx/src/gc-get.c +1345 -0
  71. package/deps/libmdbx/src/gc-put.c +970 -0
  72. package/deps/libmdbx/src/gc.h +40 -0
  73. package/deps/libmdbx/src/global.c +474 -0
  74. package/deps/libmdbx/src/internals.h +585 -0
  75. package/deps/libmdbx/src/layout-dxb.h +288 -0
  76. package/deps/libmdbx/src/layout-lck.h +289 -0
  77. package/deps/libmdbx/src/lck-posix.c +859 -0
  78. package/deps/libmdbx/src/lck-windows.c +607 -0
  79. package/deps/libmdbx/src/lck.c +174 -0
  80. package/deps/libmdbx/src/lck.h +110 -0
  81. package/deps/libmdbx/src/logging_and_debug.c +250 -0
  82. package/deps/libmdbx/src/logging_and_debug.h +159 -0
  83. package/deps/libmdbx/src/man1/mdbx_chk.1 +106 -0
  84. package/deps/libmdbx/src/man1/mdbx_copy.1 +95 -0
  85. package/deps/libmdbx/src/man1/mdbx_drop.1 +48 -0
  86. package/deps/libmdbx/src/man1/mdbx_dump.1 +101 -0
  87. package/deps/libmdbx/src/man1/mdbx_load.1 +105 -0
  88. package/deps/libmdbx/src/man1/mdbx_stat.1 +86 -0
  89. package/deps/libmdbx/src/mdbx.c++ +1837 -0
  90. package/deps/libmdbx/src/meta.c +656 -0
  91. package/deps/libmdbx/src/meta.h +168 -0
  92. package/deps/libmdbx/src/mvcc-readers.c +414 -0
  93. package/deps/libmdbx/src/node.c +365 -0
  94. package/deps/libmdbx/src/node.h +102 -0
  95. package/deps/libmdbx/src/ntdll.def +1246 -0
  96. package/deps/libmdbx/src/options.h +534 -0
  97. package/deps/libmdbx/src/osal.c +3485 -0
  98. package/deps/libmdbx/src/osal.h +587 -0
  99. package/deps/libmdbx/src/page-get.c +483 -0
  100. package/deps/libmdbx/src/page-iov.c +185 -0
  101. package/deps/libmdbx/src/page-iov.h +34 -0
  102. package/deps/libmdbx/src/page-ops.c +744 -0
  103. package/deps/libmdbx/src/page-ops.h +142 -0
  104. package/deps/libmdbx/src/pnl.c +236 -0
  105. package/deps/libmdbx/src/pnl.h +146 -0
  106. package/deps/libmdbx/src/preface.h +990 -0
  107. package/deps/libmdbx/src/proto.h +105 -0
  108. package/deps/libmdbx/src/refund.c +212 -0
  109. package/deps/libmdbx/src/sort.h +484 -0
  110. package/deps/libmdbx/src/spill.c +431 -0
  111. package/deps/libmdbx/src/spill.h +74 -0
  112. package/deps/libmdbx/src/table.c +107 -0
  113. package/deps/libmdbx/src/tls.c +551 -0
  114. package/deps/libmdbx/src/tls.h +43 -0
  115. package/deps/libmdbx/src/tools/chk.c +673 -0
  116. package/deps/libmdbx/src/tools/copy.c +166 -0
  117. package/deps/libmdbx/src/tools/drop.c +199 -0
  118. package/deps/libmdbx/src/tools/dump.c +515 -0
  119. package/deps/libmdbx/src/tools/load.c +831 -0
  120. package/deps/libmdbx/src/tools/stat.c +516 -0
  121. package/deps/libmdbx/src/tools/wingetopt.c +87 -0
  122. package/deps/libmdbx/src/tools/wingetopt.h +30 -0
  123. package/deps/libmdbx/src/tree-ops.c +1554 -0
  124. package/deps/libmdbx/src/tree-search.c +140 -0
  125. package/deps/libmdbx/src/txl.c +99 -0
  126. package/deps/libmdbx/src/txl.h +26 -0
  127. package/deps/libmdbx/src/txn.c +1083 -0
  128. package/deps/libmdbx/src/unaligned.h +205 -0
  129. package/deps/libmdbx/src/utils.c +32 -0
  130. package/deps/libmdbx/src/utils.h +76 -0
  131. package/deps/libmdbx/src/version.c.in +44 -0
  132. package/deps/libmdbx/src/walk.c +290 -0
  133. package/deps/libmdbx/src/walk.h +20 -0
  134. package/deps/libmdbx/src/windows-import.c +152 -0
  135. package/deps/libmdbx/src/windows-import.h +128 -0
  136. package/deps/libmdbx/test/CMakeLists.txt +317 -0
  137. package/deps/libmdbx/test/append.c++ +237 -0
  138. package/deps/libmdbx/test/base.h++ +92 -0
  139. package/deps/libmdbx/test/battery-tmux.sh +64 -0
  140. package/deps/libmdbx/test/cases.c++ +118 -0
  141. package/deps/libmdbx/test/chrono.c++ +134 -0
  142. package/deps/libmdbx/test/chrono.h++ +85 -0
  143. package/deps/libmdbx/test/config.c++ +643 -0
  144. package/deps/libmdbx/test/config.h++ +334 -0
  145. package/deps/libmdbx/test/copy.c++ +62 -0
  146. package/deps/libmdbx/test/dead.c++ +39 -0
  147. package/deps/libmdbx/test/dump-load.sh +40 -0
  148. package/deps/libmdbx/test/extra/crunched_delete.c++ +409 -0
  149. package/deps/libmdbx/test/extra/cursor_closing.c++ +410 -0
  150. package/deps/libmdbx/test/extra/dbi.c++ +229 -0
  151. package/deps/libmdbx/test/extra/doubtless_positioning.c++ +253 -0
  152. package/deps/libmdbx/test/extra/dupfix_addodd.c +94 -0
  153. package/deps/libmdbx/test/extra/dupfix_multiple.c++ +311 -0
  154. package/deps/libmdbx/test/extra/early_close_dbi.c++ +137 -0
  155. package/deps/libmdbx/test/extra/hex_base64_base58.c++ +118 -0
  156. package/deps/libmdbx/test/extra/maindb_ordinal.c++ +61 -0
  157. package/deps/libmdbx/test/extra/open.c++ +96 -0
  158. package/deps/libmdbx/test/extra/pcrf/README.md +2 -0
  159. package/deps/libmdbx/test/extra/pcrf/pcrf_test.c +380 -0
  160. package/deps/libmdbx/test/extra/probe.c++ +10 -0
  161. package/deps/libmdbx/test/extra/txn.c++ +407 -0
  162. package/deps/libmdbx/test/extra/upsert_alldups.c +193 -0
  163. package/deps/libmdbx/test/fork.c++ +263 -0
  164. package/deps/libmdbx/test/hill.c++ +447 -0
  165. package/deps/libmdbx/test/jitter.c++ +197 -0
  166. package/deps/libmdbx/test/keygen.c++ +393 -0
  167. package/deps/libmdbx/test/keygen.h++ +130 -0
  168. package/deps/libmdbx/test/log.c++ +358 -0
  169. package/deps/libmdbx/test/log.h++ +91 -0
  170. package/deps/libmdbx/test/main.c++ +706 -0
  171. package/deps/libmdbx/test/nested.c++ +318 -0
  172. package/deps/libmdbx/test/osal-unix.c++ +647 -0
  173. package/deps/libmdbx/test/osal-windows.c++ +440 -0
  174. package/deps/libmdbx/test/osal.h++ +41 -0
  175. package/deps/libmdbx/test/stochastic.sh +690 -0
  176. package/deps/libmdbx/test/stub/LICENSE +24 -0
  177. package/deps/libmdbx/test/stub/README.md +8 -0
  178. package/deps/libmdbx/test/stub/pthread_barrier.c +104 -0
  179. package/deps/libmdbx/test/stub/pthread_barrier.h +77 -0
  180. package/deps/libmdbx/test/test.c++ +1551 -0
  181. package/deps/libmdbx/test/test.h++ +298 -0
  182. package/deps/libmdbx/test/tmux.conf +3 -0
  183. package/deps/libmdbx/test/try.c++ +30 -0
  184. package/deps/libmdbx/test/ttl.c++ +240 -0
  185. package/deps/libmdbx/test/utils.c++ +203 -0
  186. package/deps/libmdbx/test/utils.h++ +326 -0
  187. package/deps/libmdbx/test/valgrind_suppress.txt +536 -0
  188. package/lib/mdbx_evn_async.js +211 -0
  189. package/lib/mdbx_worker.js +195 -0
  190. package/lib/nativemou.js +6 -0
  191. package/package.json +38 -0
  192. package/src/async/envmou_close.cpp +34 -0
  193. package/src/async/envmou_close.hpp +32 -0
  194. package/src/async/envmou_copy_to.cpp +29 -0
  195. package/src/async/envmou_copy_to.hpp +38 -0
  196. package/src/async/envmou_keys.cpp +201 -0
  197. package/src/async/envmou_keys.hpp +50 -0
  198. package/src/async/envmou_open.cpp +38 -0
  199. package/src/async/envmou_open.hpp +33 -0
  200. package/src/async/envmou_query.cpp +167 -0
  201. package/src/async/envmou_query.hpp +53 -0
  202. package/src/dbimou.cpp +522 -0
  203. package/src/dbimou.hpp +82 -0
  204. package/src/env_arg0.hpp +24 -0
  205. package/src/envmou.cpp +445 -0
  206. package/src/envmou.hpp +116 -0
  207. package/src/modulemou.cpp +113 -0
  208. package/src/querymou.cpp +177 -0
  209. package/src/querymou.hpp +93 -0
  210. package/src/txnmou.cpp +254 -0
  211. package/src/txnmou.hpp +122 -0
  212. package/src/typemou.hpp +239 -0
  213. package/src/valuemou.hpp +194 -0
  214. package/test/async.js +67 -0
  215. package/test/e3.js +38 -0
  216. package/test/e4.js +89 -0
  217. package/test/e5.js +162 -0
  218. package/test/test-batch-ops.js +243 -0
  219. package/test/test-cursor-mode.js +84 -0
  220. 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 */