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,142 @@
|
|
|
1
|
+
/// \copyright SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
|
|
3
|
+
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include "essentials.h"
|
|
7
|
+
|
|
8
|
+
#if MDBX_ENABLE_DBI_SPARSE
|
|
9
|
+
|
|
10
|
+
MDBX_NOTHROW_CONST_FUNCTION MDBX_MAYBE_UNUSED MDBX_INTERNAL size_t dbi_bitmap_ctz_fallback(const MDBX_txn *txn,
|
|
11
|
+
intptr_t bmi);
|
|
12
|
+
|
|
13
|
+
static inline size_t dbi_bitmap_ctz(const MDBX_txn *txn, intptr_t bmi) {
|
|
14
|
+
tASSERT(txn, bmi > 0);
|
|
15
|
+
STATIC_ASSERT(sizeof(bmi) >= sizeof(txn->dbi_sparse[0]));
|
|
16
|
+
#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl)
|
|
17
|
+
if (sizeof(txn->dbi_sparse[0]) <= sizeof(int))
|
|
18
|
+
return __builtin_ctz((int)bmi);
|
|
19
|
+
if (sizeof(txn->dbi_sparse[0]) == sizeof(long))
|
|
20
|
+
return __builtin_ctzl((long)bmi);
|
|
21
|
+
#if (defined(__SIZEOF_LONG_LONG__) && __SIZEOF_LONG_LONG__ == 8) || __has_builtin(__builtin_ctzll)
|
|
22
|
+
return __builtin_ctzll(bmi);
|
|
23
|
+
#endif /* have(long long) && long long == uint64_t */
|
|
24
|
+
#endif /* GNU C */
|
|
25
|
+
|
|
26
|
+
#if defined(_MSC_VER)
|
|
27
|
+
unsigned long index;
|
|
28
|
+
if (sizeof(txn->dbi_sparse[0]) > 4) {
|
|
29
|
+
#if defined(_M_AMD64) || defined(_M_ARM64) || defined(_M_X64)
|
|
30
|
+
_BitScanForward64(&index, bmi);
|
|
31
|
+
return index;
|
|
32
|
+
#else
|
|
33
|
+
if (bmi > UINT32_MAX) {
|
|
34
|
+
_BitScanForward(&index, (uint32_t)((uint64_t)bmi >> 32));
|
|
35
|
+
return index;
|
|
36
|
+
}
|
|
37
|
+
#endif
|
|
38
|
+
}
|
|
39
|
+
_BitScanForward(&index, (uint32_t)bmi);
|
|
40
|
+
return index;
|
|
41
|
+
#endif /* MSVC */
|
|
42
|
+
|
|
43
|
+
return dbi_bitmap_ctz_fallback(txn, bmi);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* LY: Макрос целенаправленно сделан с одним циклом, чтобы сохранить возможность
|
|
47
|
+
* использования оператора break */
|
|
48
|
+
#define TXN_FOREACH_DBI_FROM(TXN, I, FROM) \
|
|
49
|
+
for (size_t bitmap_chunk = CHAR_BIT * sizeof(TXN->dbi_sparse[0]), bitmap_item = TXN->dbi_sparse[0] >> FROM, \
|
|
50
|
+
I = FROM; \
|
|
51
|
+
I < TXN->n_dbi; ++I) \
|
|
52
|
+
if (bitmap_item == 0) { \
|
|
53
|
+
I = (I - 1) | (bitmap_chunk - 1); \
|
|
54
|
+
bitmap_item = TXN->dbi_sparse[(1 + I) / bitmap_chunk]; \
|
|
55
|
+
if (!bitmap_item) \
|
|
56
|
+
/* coverity[const_overflow] */ \
|
|
57
|
+
I += bitmap_chunk; \
|
|
58
|
+
continue; \
|
|
59
|
+
} else if ((bitmap_item & 1) == 0) { \
|
|
60
|
+
size_t bitmap_skip = dbi_bitmap_ctz(txn, bitmap_item); \
|
|
61
|
+
bitmap_item >>= bitmap_skip; \
|
|
62
|
+
I += bitmap_skip - 1; \
|
|
63
|
+
continue; \
|
|
64
|
+
} else if (bitmap_item >>= 1, TXN->dbi_state[I])
|
|
65
|
+
|
|
66
|
+
#else
|
|
67
|
+
|
|
68
|
+
#define TXN_FOREACH_DBI_FROM(TXN, I, SKIP) \
|
|
69
|
+
for (size_t I = SKIP; I < TXN->n_dbi; ++I) \
|
|
70
|
+
if (TXN->dbi_state[I])
|
|
71
|
+
|
|
72
|
+
#endif /* MDBX_ENABLE_DBI_SPARSE */
|
|
73
|
+
|
|
74
|
+
#define TXN_FOREACH_DBI_ALL(TXN, I) TXN_FOREACH_DBI_FROM(TXN, I, 0)
|
|
75
|
+
#define TXN_FOREACH_DBI_USER(TXN, I) TXN_FOREACH_DBI_FROM(TXN, I, CORE_DBS)
|
|
76
|
+
|
|
77
|
+
MDBX_INTERNAL int dbi_import(MDBX_txn *txn, const size_t dbi);
|
|
78
|
+
|
|
79
|
+
struct dbi_snap_result {
|
|
80
|
+
uint32_t sequence;
|
|
81
|
+
unsigned flags;
|
|
82
|
+
};
|
|
83
|
+
MDBX_INTERNAL struct dbi_snap_result dbi_snap(const MDBX_env *env, const size_t dbi);
|
|
84
|
+
|
|
85
|
+
MDBX_INTERNAL int dbi_update(MDBX_txn *txn, int keep);
|
|
86
|
+
|
|
87
|
+
static inline uint8_t dbi_state(const MDBX_txn *txn, const size_t dbi) {
|
|
88
|
+
STATIC_ASSERT((int)DBI_DIRTY == MDBX_DBI_DIRTY && (int)DBI_STALE == MDBX_DBI_STALE &&
|
|
89
|
+
(int)DBI_FRESH == MDBX_DBI_FRESH && (int)DBI_CREAT == MDBX_DBI_CREAT);
|
|
90
|
+
|
|
91
|
+
#if MDBX_ENABLE_DBI_SPARSE
|
|
92
|
+
const size_t bitmap_chunk = CHAR_BIT * sizeof(txn->dbi_sparse[0]);
|
|
93
|
+
const size_t bitmap_indx = dbi / bitmap_chunk;
|
|
94
|
+
const size_t bitmap_mask = (size_t)1 << dbi % bitmap_chunk;
|
|
95
|
+
return likely(dbi < txn->n_dbi && (txn->dbi_sparse[bitmap_indx] & bitmap_mask) != 0) ? txn->dbi_state[dbi] : 0;
|
|
96
|
+
#else
|
|
97
|
+
return likely(dbi < txn->n_dbi) ? txn->dbi_state[dbi] : 0;
|
|
98
|
+
#endif /* MDBX_ENABLE_DBI_SPARSE */
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
static inline bool dbi_changed(const MDBX_txn *txn, const size_t dbi) {
|
|
102
|
+
const MDBX_env *const env = txn->env;
|
|
103
|
+
eASSERT(env, dbi_state(txn, dbi) & DBI_LINDO);
|
|
104
|
+
const uint32_t snap_seq = atomic_load32(&env->dbi_seqs[dbi], mo_AcquireRelease);
|
|
105
|
+
return unlikely(snap_seq != txn->dbi_seqs[dbi]);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static inline int dbi_check(const MDBX_txn *txn, const size_t dbi) {
|
|
109
|
+
const uint8_t state = dbi_state(txn, dbi);
|
|
110
|
+
if (likely((state & DBI_LINDO) != 0 && !dbi_changed(txn, dbi)))
|
|
111
|
+
return (state & DBI_VALID) ? MDBX_SUCCESS : MDBX_BAD_DBI;
|
|
112
|
+
|
|
113
|
+
/* Медленный путь: ленивая до-инициализацяи и импорт */
|
|
114
|
+
return dbi_import((MDBX_txn *)txn, dbi);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static inline uint32_t dbi_seq_next(const MDBX_env *const env, size_t dbi) {
|
|
118
|
+
uint32_t v = atomic_load32(&env->dbi_seqs[dbi], mo_AcquireRelease) + 1;
|
|
119
|
+
return v ? v : 1;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
MDBX_INTERNAL int dbi_open(MDBX_txn *txn, const MDBX_val *const name, unsigned user_flags, MDBX_dbi *dbi,
|
|
123
|
+
MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp);
|
|
124
|
+
|
|
125
|
+
MDBX_INTERNAL int dbi_bind(MDBX_txn *txn, const size_t dbi, unsigned user_flags, MDBX_cmp_func *keycmp,
|
|
126
|
+
MDBX_cmp_func *datacmp);
|
|
127
|
+
|
|
128
|
+
typedef struct defer_free_item {
|
|
129
|
+
struct defer_free_item *next;
|
|
130
|
+
uint64_t timestamp;
|
|
131
|
+
} defer_free_item_t;
|
|
132
|
+
|
|
133
|
+
MDBX_INTERNAL int dbi_defer_release(MDBX_env *const env, defer_free_item_t *const chain);
|
|
134
|
+
MDBX_INTERNAL int dbi_close_release(MDBX_env *env, MDBX_dbi dbi);
|
|
135
|
+
MDBX_INTERNAL const tree_t *dbi_dig(const MDBX_txn *txn, const size_t dbi, tree_t *fallback);
|
|
136
|
+
|
|
137
|
+
struct dbi_rename_result {
|
|
138
|
+
defer_free_item_t *defer;
|
|
139
|
+
int err;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
MDBX_INTERNAL struct dbi_rename_result dbi_rename_locked(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val new_name);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#if defined(__GNUC__) && !defined(__LCC__)
|
|
2
|
+
|
|
3
|
+
#pragma push_macro("TRACE")
|
|
4
|
+
#pragma push_macro("DEBUG")
|
|
5
|
+
#pragma push_macro("VERBOSE")
|
|
6
|
+
#pragma push_macro("NOTICE")
|
|
7
|
+
#pragma push_macro("WARNING")
|
|
8
|
+
#pragma push_macro("ERROR")
|
|
9
|
+
#pragma push_macro("eASSERT")
|
|
10
|
+
|
|
11
|
+
#undef TRACE
|
|
12
|
+
#define TRACE(fmt, ...) debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
|
13
|
+
|
|
14
|
+
#undef DEBUG
|
|
15
|
+
#define DEBUG(fmt, ...) debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
|
16
|
+
|
|
17
|
+
#undef VERBOSE
|
|
18
|
+
#define VERBOSE(fmt, ...) debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
|
19
|
+
|
|
20
|
+
#undef NOTICE
|
|
21
|
+
#define NOTICE(fmt, ...) debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
|
22
|
+
|
|
23
|
+
#undef WARNING
|
|
24
|
+
#define WARNING(fmt, ...) debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
|
25
|
+
|
|
26
|
+
#undef ERROR
|
|
27
|
+
#define ERROR(fmt, ...) debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
|
28
|
+
|
|
29
|
+
#undef eASSERT
|
|
30
|
+
#define eASSERT(env, expr) ENSURE(env, expr)
|
|
31
|
+
|
|
32
|
+
#if !defined(__clang__)
|
|
33
|
+
#pragma GCC optimize("-Og")
|
|
34
|
+
#endif
|
|
35
|
+
|
|
36
|
+
#endif /* GCC only */
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#if defined(__GNUC__) && !defined(__LCC__)
|
|
2
|
+
|
|
3
|
+
#pragma pop_macro("TRACE")
|
|
4
|
+
#pragma pop_macro("DEBUG")
|
|
5
|
+
#pragma pop_macro("VERBOSE")
|
|
6
|
+
#pragma pop_macro("NOTICE")
|
|
7
|
+
#pragma pop_macro("WARNING")
|
|
8
|
+
#pragma pop_macro("ERROR")
|
|
9
|
+
#pragma pop_macro("eASSERT")
|
|
10
|
+
|
|
11
|
+
#if !defined(__clang__)
|
|
12
|
+
#pragma GCC reset_options
|
|
13
|
+
#endif
|
|
14
|
+
|
|
15
|
+
#endif /* GCC only */
|
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
/// \copyright SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
|
|
3
|
+
|
|
4
|
+
#include "internals.h"
|
|
5
|
+
|
|
6
|
+
static inline size_t dpl_size2bytes(ptrdiff_t size) {
|
|
7
|
+
assert(size > CURSOR_STACK_SIZE && (size_t)size <= PAGELIST_LIMIT);
|
|
8
|
+
#if MDBX_DPL_PREALLOC_FOR_RADIXSORT
|
|
9
|
+
size += size;
|
|
10
|
+
#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
|
|
11
|
+
STATIC_ASSERT(MDBX_ASSUME_MALLOC_OVERHEAD + sizeof(dpl_t) +
|
|
12
|
+
(PAGELIST_LIMIT * (MDBX_DPL_PREALLOC_FOR_RADIXSORT + 1)) * sizeof(dp_t) +
|
|
13
|
+
MDBX_PNL_GRANULATE * sizeof(void *) * 2 <
|
|
14
|
+
SIZE_MAX / 4 * 3);
|
|
15
|
+
size_t bytes = ceil_powerof2(MDBX_ASSUME_MALLOC_OVERHEAD + sizeof(dpl_t) + size * sizeof(dp_t),
|
|
16
|
+
MDBX_PNL_GRANULATE * sizeof(void *) * 2) -
|
|
17
|
+
MDBX_ASSUME_MALLOC_OVERHEAD;
|
|
18
|
+
return bytes;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static inline size_t dpl_bytes2size(const ptrdiff_t bytes) {
|
|
22
|
+
size_t size = (bytes - sizeof(dpl_t)) / sizeof(dp_t);
|
|
23
|
+
#if MDBX_DPL_PREALLOC_FOR_RADIXSORT
|
|
24
|
+
size >>= 1;
|
|
25
|
+
#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
|
|
26
|
+
assert(size > CURSOR_STACK_SIZE && size <= PAGELIST_LIMIT + MDBX_PNL_GRANULATE);
|
|
27
|
+
return size;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
void dpl_free(MDBX_txn *txn) {
|
|
31
|
+
if (likely(txn->tw.dirtylist)) {
|
|
32
|
+
osal_free(txn->tw.dirtylist);
|
|
33
|
+
txn->tw.dirtylist = nullptr;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
dpl_t *dpl_reserve(MDBX_txn *txn, size_t size) {
|
|
38
|
+
tASSERT(txn, (txn->flags & MDBX_TXN_RDONLY) == 0);
|
|
39
|
+
tASSERT(txn, (txn->flags & MDBX_WRITEMAP) == 0 || MDBX_AVOID_MSYNC);
|
|
40
|
+
|
|
41
|
+
size_t bytes = dpl_size2bytes((size < PAGELIST_LIMIT) ? size : PAGELIST_LIMIT);
|
|
42
|
+
dpl_t *const dl = osal_realloc(txn->tw.dirtylist, bytes);
|
|
43
|
+
if (likely(dl)) {
|
|
44
|
+
#ifdef osal_malloc_usable_size
|
|
45
|
+
bytes = osal_malloc_usable_size(dl);
|
|
46
|
+
#endif /* osal_malloc_usable_size */
|
|
47
|
+
dl->detent = dpl_bytes2size(bytes);
|
|
48
|
+
tASSERT(txn, txn->tw.dirtylist == nullptr || dl->length <= dl->detent);
|
|
49
|
+
txn->tw.dirtylist = dl;
|
|
50
|
+
}
|
|
51
|
+
return dl;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
int dpl_alloc(MDBX_txn *txn) {
|
|
55
|
+
tASSERT(txn, (txn->flags & MDBX_TXN_RDONLY) == 0);
|
|
56
|
+
tASSERT(txn, (txn->flags & MDBX_WRITEMAP) == 0 || MDBX_AVOID_MSYNC);
|
|
57
|
+
|
|
58
|
+
const size_t wanna = (txn->env->options.dp_initial < txn->geo.upper) ? txn->env->options.dp_initial : txn->geo.upper;
|
|
59
|
+
#if MDBX_FORCE_ASSERTIONS || MDBX_DEBUG
|
|
60
|
+
if (txn->tw.dirtylist)
|
|
61
|
+
/* обнуляем чтобы не сработал ассерт внутри dpl_reserve() */
|
|
62
|
+
txn->tw.dirtylist->sorted = txn->tw.dirtylist->length = 0;
|
|
63
|
+
#endif /* asertions enabled */
|
|
64
|
+
if (unlikely(!txn->tw.dirtylist || txn->tw.dirtylist->detent < wanna || txn->tw.dirtylist->detent > wanna + wanna) &&
|
|
65
|
+
unlikely(!dpl_reserve(txn, wanna)))
|
|
66
|
+
return MDBX_ENOMEM;
|
|
67
|
+
|
|
68
|
+
dpl_clear(txn->tw.dirtylist);
|
|
69
|
+
return MDBX_SUCCESS;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
#define MDBX_DPL_EXTRACT_KEY(ptr) ((ptr)->pgno)
|
|
73
|
+
RADIXSORT_IMPL(dp, dp_t, MDBX_DPL_EXTRACT_KEY, MDBX_DPL_PREALLOC_FOR_RADIXSORT, 1)
|
|
74
|
+
|
|
75
|
+
#define DP_SORT_CMP(first, last) ((first).pgno < (last).pgno)
|
|
76
|
+
SORT_IMPL(dp_sort, false, dp_t, DP_SORT_CMP)
|
|
77
|
+
|
|
78
|
+
__hot __noinline dpl_t *dpl_sort_slowpath(const MDBX_txn *txn) {
|
|
79
|
+
tASSERT(txn, (txn->flags & MDBX_TXN_RDONLY) == 0);
|
|
80
|
+
tASSERT(txn, (txn->flags & MDBX_WRITEMAP) == 0 || MDBX_AVOID_MSYNC);
|
|
81
|
+
|
|
82
|
+
dpl_t *dl = txn->tw.dirtylist;
|
|
83
|
+
assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
|
|
84
|
+
const size_t unsorted = dl->length - dl->sorted;
|
|
85
|
+
if (likely(unsorted < MDBX_RADIXSORT_THRESHOLD) || unlikely(!dp_radixsort(dl->items + 1, dl->length))) {
|
|
86
|
+
if (dl->sorted > unsorted / 4 + 4 &&
|
|
87
|
+
(MDBX_DPL_PREALLOC_FOR_RADIXSORT || dl->length + unsorted < dl->detent + dpl_gap_mergesort)) {
|
|
88
|
+
dp_t *const sorted_begin = dl->items + 1;
|
|
89
|
+
dp_t *const sorted_end = sorted_begin + dl->sorted;
|
|
90
|
+
dp_t *const end =
|
|
91
|
+
dl->items + (MDBX_DPL_PREALLOC_FOR_RADIXSORT ? dl->length + dl->length + 1 : dl->detent + dpl_reserve_gap);
|
|
92
|
+
dp_t *const tmp = end - unsorted;
|
|
93
|
+
assert(dl->items + dl->length + 1 < tmp);
|
|
94
|
+
/* copy unsorted to the end of allocated space and sort it */
|
|
95
|
+
memcpy(tmp, sorted_end, unsorted * sizeof(dp_t));
|
|
96
|
+
dp_sort(tmp, tmp + unsorted);
|
|
97
|
+
/* merge two parts from end to begin */
|
|
98
|
+
dp_t *__restrict w = dl->items + dl->length;
|
|
99
|
+
dp_t *__restrict l = dl->items + dl->sorted;
|
|
100
|
+
dp_t *__restrict r = end - 1;
|
|
101
|
+
do {
|
|
102
|
+
const bool cmp = expect_with_probability(l->pgno > r->pgno, 0, .5);
|
|
103
|
+
#if defined(__LCC__) || __CLANG_PREREQ(13, 0) || !MDBX_HAVE_CMOV
|
|
104
|
+
*w = cmp ? *l-- : *r--;
|
|
105
|
+
#else
|
|
106
|
+
*w = cmp ? *l : *r;
|
|
107
|
+
l -= cmp;
|
|
108
|
+
r += (ptrdiff_t)cmp - 1;
|
|
109
|
+
#endif
|
|
110
|
+
} while (likely(--w > l));
|
|
111
|
+
assert(r == tmp - 1);
|
|
112
|
+
assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
|
|
113
|
+
if (ASSERT_ENABLED())
|
|
114
|
+
for (size_t i = 0; i <= dl->length; ++i)
|
|
115
|
+
assert(dl->items[i].pgno < dl->items[i + 1].pgno);
|
|
116
|
+
} else {
|
|
117
|
+
dp_sort(dl->items + 1, dl->items + dl->length + 1);
|
|
118
|
+
assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
|
|
122
|
+
}
|
|
123
|
+
dl->sorted = dl->length;
|
|
124
|
+
return dl;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Returns the index of the first dirty-page whose pgno
|
|
128
|
+
* member is greater than or equal to id. */
|
|
129
|
+
#define DP_SEARCH_CMP(dp, id) ((dp).pgno < (id))
|
|
130
|
+
SEARCH_IMPL(dp_bsearch, dp_t, pgno_t, DP_SEARCH_CMP)
|
|
131
|
+
|
|
132
|
+
__hot __noinline size_t dpl_search(const MDBX_txn *txn, pgno_t pgno) {
|
|
133
|
+
tASSERT(txn, (txn->flags & MDBX_TXN_RDONLY) == 0);
|
|
134
|
+
tASSERT(txn, (txn->flags & MDBX_WRITEMAP) == 0 || MDBX_AVOID_MSYNC);
|
|
135
|
+
|
|
136
|
+
dpl_t *dl = txn->tw.dirtylist;
|
|
137
|
+
assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
|
|
138
|
+
if (AUDIT_ENABLED()) {
|
|
139
|
+
for (const dp_t *ptr = dl->items + dl->sorted; --ptr > dl->items;) {
|
|
140
|
+
assert(ptr[0].pgno < ptr[1].pgno);
|
|
141
|
+
assert(ptr[0].pgno >= NUM_METAS);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
switch (dl->length - dl->sorted) {
|
|
146
|
+
default:
|
|
147
|
+
/* sort a whole */
|
|
148
|
+
dpl_sort_slowpath(txn);
|
|
149
|
+
break;
|
|
150
|
+
case 0:
|
|
151
|
+
/* whole sorted cases */
|
|
152
|
+
break;
|
|
153
|
+
|
|
154
|
+
#define LINEAR_SEARCH_CASE(N) \
|
|
155
|
+
case N: \
|
|
156
|
+
if (dl->items[dl->length - N + 1].pgno == pgno) \
|
|
157
|
+
return dl->length - N + 1; \
|
|
158
|
+
__fallthrough
|
|
159
|
+
|
|
160
|
+
/* use linear scan until the threshold */
|
|
161
|
+
LINEAR_SEARCH_CASE(7); /* fall through */
|
|
162
|
+
LINEAR_SEARCH_CASE(6); /* fall through */
|
|
163
|
+
LINEAR_SEARCH_CASE(5); /* fall through */
|
|
164
|
+
LINEAR_SEARCH_CASE(4); /* fall through */
|
|
165
|
+
LINEAR_SEARCH_CASE(3); /* fall through */
|
|
166
|
+
LINEAR_SEARCH_CASE(2); /* fall through */
|
|
167
|
+
case 1:
|
|
168
|
+
if (dl->items[dl->length].pgno == pgno)
|
|
169
|
+
return dl->length;
|
|
170
|
+
/* continue bsearch on the sorted part */
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
return dp_bsearch(dl->items + 1, dl->sorted, pgno) - dl->items;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const page_t *debug_dpl_find(const MDBX_txn *txn, const pgno_t pgno) {
|
|
177
|
+
tASSERT(txn, (txn->flags & MDBX_TXN_RDONLY) == 0);
|
|
178
|
+
const dpl_t *dl = txn->tw.dirtylist;
|
|
179
|
+
if (dl) {
|
|
180
|
+
tASSERT(txn, (txn->flags & MDBX_WRITEMAP) == 0 || MDBX_AVOID_MSYNC);
|
|
181
|
+
assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
|
|
182
|
+
for (size_t i = dl->length; i > dl->sorted; --i)
|
|
183
|
+
if (dl->items[i].pgno == pgno)
|
|
184
|
+
return dl->items[i].ptr;
|
|
185
|
+
|
|
186
|
+
if (dl->sorted) {
|
|
187
|
+
const size_t i = dp_bsearch(dl->items + 1, dl->sorted, pgno) - dl->items;
|
|
188
|
+
if (dl->items[i].pgno == pgno)
|
|
189
|
+
return dl->items[i].ptr;
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
tASSERT(txn, (txn->flags & MDBX_WRITEMAP) != 0 && !MDBX_AVOID_MSYNC);
|
|
193
|
+
}
|
|
194
|
+
return nullptr;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
void dpl_remove_ex(const MDBX_txn *txn, size_t i, size_t npages) {
|
|
198
|
+
tASSERT(txn, (txn->flags & MDBX_TXN_RDONLY) == 0);
|
|
199
|
+
tASSERT(txn, (txn->flags & MDBX_WRITEMAP) == 0 || MDBX_AVOID_MSYNC);
|
|
200
|
+
|
|
201
|
+
dpl_t *dl = txn->tw.dirtylist;
|
|
202
|
+
assert((intptr_t)i > 0 && i <= dl->length);
|
|
203
|
+
assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
|
|
204
|
+
dl->pages_including_loose -= npages;
|
|
205
|
+
dl->sorted -= dl->sorted >= i;
|
|
206
|
+
dl->length -= 1;
|
|
207
|
+
memmove(dl->items + i, dl->items + i + 1, (dl->length - i + 2) * sizeof(dl->items[0]));
|
|
208
|
+
assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
int __must_check_result dpl_append(MDBX_txn *txn, pgno_t pgno, page_t *page, size_t npages) {
|
|
212
|
+
tASSERT(txn, (txn->flags & MDBX_TXN_RDONLY) == 0);
|
|
213
|
+
tASSERT(txn, (txn->flags & MDBX_WRITEMAP) == 0 || MDBX_AVOID_MSYNC);
|
|
214
|
+
const dp_t dp = {page, pgno, (pgno_t)npages};
|
|
215
|
+
if ((txn->flags & MDBX_WRITEMAP) == 0) {
|
|
216
|
+
size_t *const ptr = ptr_disp(page, -(ptrdiff_t)sizeof(size_t));
|
|
217
|
+
*ptr = txn->tw.dirtylru;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
dpl_t *dl = txn->tw.dirtylist;
|
|
221
|
+
tASSERT(txn, dl->length <= PAGELIST_LIMIT + MDBX_PNL_GRANULATE);
|
|
222
|
+
tASSERT(txn, dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
|
|
223
|
+
if (AUDIT_ENABLED()) {
|
|
224
|
+
for (size_t i = dl->length; i > 0; --i) {
|
|
225
|
+
assert(dl->items[i].pgno != dp.pgno);
|
|
226
|
+
if (unlikely(dl->items[i].pgno == dp.pgno)) {
|
|
227
|
+
ERROR("Page %u already exist in the DPL at %zu", dp.pgno, i);
|
|
228
|
+
return MDBX_PROBLEM;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (unlikely(dl->length == dl->detent)) {
|
|
234
|
+
if (unlikely(dl->detent >= PAGELIST_LIMIT)) {
|
|
235
|
+
ERROR("DPL is full (PAGELIST_LIMIT %zu)", PAGELIST_LIMIT);
|
|
236
|
+
return MDBX_TXN_FULL;
|
|
237
|
+
}
|
|
238
|
+
const size_t size = (dl->detent < MDBX_PNL_INITIAL * 42) ? dl->detent + dl->detent : dl->detent + dl->detent / 2;
|
|
239
|
+
dl = dpl_reserve(txn, size);
|
|
240
|
+
if (unlikely(!dl))
|
|
241
|
+
return MDBX_ENOMEM;
|
|
242
|
+
tASSERT(txn, dl->length < dl->detent);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/* Сортировка нужна для быстрого поиска, используем несколько тактик:
|
|
246
|
+
* 1) Сохраняем упорядоченность при естественной вставке в нужном порядке.
|
|
247
|
+
* 2) Добавляем в не-сортированный хвост, который сортируем и сливаем
|
|
248
|
+
* с отсортированной головой по необходимости, а пока хвост короткий
|
|
249
|
+
* ищем в нём сканированием, избегая большой пересортировки.
|
|
250
|
+
* 3) Если не-сортированный хвост короткий, а добавляемый элемент близок
|
|
251
|
+
* к концу отсортированной головы, то выгоднее сразу вставить элемент
|
|
252
|
+
* в нужное место.
|
|
253
|
+
*
|
|
254
|
+
* Алгоритмически:
|
|
255
|
+
* - добавлять в не-сортированный хвост следует только если вставка сильно
|
|
256
|
+
* дорогая, т.е. если целевая позиция элемента сильно далека от конца;
|
|
257
|
+
* - для быстрой проверки достаточно сравнить добавляемый элемент с отстоящим
|
|
258
|
+
* от конца на максимально-приемлемое расстояние;
|
|
259
|
+
* - если список короче, либо элемент в этой позиции меньше вставляемого,
|
|
260
|
+
* то следует перемещать элементы и вставлять в отсортированную голову;
|
|
261
|
+
* - если не-сортированный хвост длиннее, либо элемент в этой позиции больше,
|
|
262
|
+
* то следует добавлять в не-сортированный хвост. */
|
|
263
|
+
|
|
264
|
+
dl->pages_including_loose += npages;
|
|
265
|
+
dp_t *i = dl->items + dl->length;
|
|
266
|
+
|
|
267
|
+
const ptrdiff_t pivot = (ptrdiff_t)dl->length - dpl_insertion_threshold;
|
|
268
|
+
#if MDBX_HAVE_CMOV
|
|
269
|
+
const pgno_t pivot_pgno =
|
|
270
|
+
dl->items[(dl->length < dpl_insertion_threshold) ? 0 : dl->length - dpl_insertion_threshold].pgno;
|
|
271
|
+
#endif /* MDBX_HAVE_CMOV */
|
|
272
|
+
|
|
273
|
+
/* copy the stub beyond the end */
|
|
274
|
+
i[2] = i[1];
|
|
275
|
+
dl->length += 1;
|
|
276
|
+
|
|
277
|
+
if (likely(pivot <= (ptrdiff_t)dl->sorted) &&
|
|
278
|
+
#if MDBX_HAVE_CMOV
|
|
279
|
+
pivot_pgno < dp.pgno) {
|
|
280
|
+
#else
|
|
281
|
+
(pivot <= 0 || dl->items[pivot].pgno < dp.pgno)) {
|
|
282
|
+
#endif /* MDBX_HAVE_CMOV */
|
|
283
|
+
dl->sorted += 1;
|
|
284
|
+
|
|
285
|
+
/* сдвигаем несортированный хвост */
|
|
286
|
+
while (i >= dl->items + dl->sorted) {
|
|
287
|
+
#if !defined(__GNUC__) /* пытаемся избежать вызова memmove() */
|
|
288
|
+
i[1] = *i;
|
|
289
|
+
#elif MDBX_WORDBITS == 64 && (defined(__SIZEOF_INT128__) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128))
|
|
290
|
+
STATIC_ASSERT(sizeof(dp) == sizeof(__uint128_t));
|
|
291
|
+
((__uint128_t *)i)[1] = *(volatile __uint128_t *)i;
|
|
292
|
+
#else
|
|
293
|
+
i[1].ptr = i->ptr;
|
|
294
|
+
i[1].pgno = i->pgno;
|
|
295
|
+
i[1].npages = i->npages;
|
|
296
|
+
#endif
|
|
297
|
+
--i;
|
|
298
|
+
}
|
|
299
|
+
/* ищем нужную позицию сдвигая отсортированные элементы */
|
|
300
|
+
while (i->pgno > pgno) {
|
|
301
|
+
tASSERT(txn, i > dl->items);
|
|
302
|
+
i[1] = *i;
|
|
303
|
+
--i;
|
|
304
|
+
}
|
|
305
|
+
tASSERT(txn, i->pgno < dp.pgno);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
i[1] = dp;
|
|
309
|
+
assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
|
|
310
|
+
assert(dl->sorted <= dl->length);
|
|
311
|
+
return MDBX_SUCCESS;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
__cold bool dpl_check(MDBX_txn *txn) {
|
|
315
|
+
tASSERT(txn, (txn->flags & MDBX_TXN_RDONLY) == 0);
|
|
316
|
+
const dpl_t *const dl = txn->tw.dirtylist;
|
|
317
|
+
if (!dl) {
|
|
318
|
+
tASSERT(txn, (txn->flags & MDBX_WRITEMAP) != 0 && !MDBX_AVOID_MSYNC);
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
tASSERT(txn, (txn->flags & MDBX_WRITEMAP) == 0 || MDBX_AVOID_MSYNC);
|
|
322
|
+
|
|
323
|
+
assert(dl->items[0].pgno == 0 && dl->items[dl->length + 1].pgno == P_INVALID);
|
|
324
|
+
tASSERT(txn,
|
|
325
|
+
txn->tw.dirtyroom + dl->length == (txn->parent ? txn->parent->tw.dirtyroom : txn->env->options.dp_limit));
|
|
326
|
+
|
|
327
|
+
if (!AUDIT_ENABLED())
|
|
328
|
+
return true;
|
|
329
|
+
|
|
330
|
+
size_t loose = 0, pages = 0;
|
|
331
|
+
for (size_t i = dl->length; i > 0; --i) {
|
|
332
|
+
const page_t *const dp = dl->items[i].ptr;
|
|
333
|
+
if (!dp)
|
|
334
|
+
continue;
|
|
335
|
+
|
|
336
|
+
tASSERT(txn, dp->pgno == dl->items[i].pgno);
|
|
337
|
+
if (unlikely(dp->pgno != dl->items[i].pgno))
|
|
338
|
+
return false;
|
|
339
|
+
|
|
340
|
+
if ((txn->flags & MDBX_WRITEMAP) == 0) {
|
|
341
|
+
const uint32_t age = dpl_age(txn, i);
|
|
342
|
+
tASSERT(txn, age < UINT32_MAX / 3);
|
|
343
|
+
if (unlikely(age > UINT32_MAX / 3))
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
tASSERT(txn, dp->flags == P_LOOSE || is_modifable(txn, dp));
|
|
348
|
+
if (dp->flags == P_LOOSE) {
|
|
349
|
+
loose += 1;
|
|
350
|
+
} else if (unlikely(!is_modifable(txn, dp)))
|
|
351
|
+
return false;
|
|
352
|
+
|
|
353
|
+
const unsigned num = dpl_npages(dl, i);
|
|
354
|
+
pages += num;
|
|
355
|
+
tASSERT(txn, txn->geo.first_unallocated >= dp->pgno + num);
|
|
356
|
+
if (unlikely(txn->geo.first_unallocated < dp->pgno + num))
|
|
357
|
+
return false;
|
|
358
|
+
|
|
359
|
+
if (i < dl->sorted) {
|
|
360
|
+
tASSERT(txn, dl->items[i + 1].pgno >= dp->pgno + num);
|
|
361
|
+
if (unlikely(dl->items[i + 1].pgno < dp->pgno + num))
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const size_t rpa = pnl_search(txn->tw.repnl, dp->pgno, txn->geo.first_unallocated);
|
|
366
|
+
tASSERT(txn, rpa > MDBX_PNL_GETSIZE(txn->tw.repnl) || txn->tw.repnl[rpa] != dp->pgno);
|
|
367
|
+
if (rpa <= MDBX_PNL_GETSIZE(txn->tw.repnl) && unlikely(txn->tw.repnl[rpa] == dp->pgno))
|
|
368
|
+
return false;
|
|
369
|
+
if (num > 1) {
|
|
370
|
+
const size_t rpb = pnl_search(txn->tw.repnl, dp->pgno + num - 1, txn->geo.first_unallocated);
|
|
371
|
+
tASSERT(txn, rpa == rpb);
|
|
372
|
+
if (unlikely(rpa != rpb))
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
tASSERT(txn, loose == txn->tw.loose_count);
|
|
378
|
+
if (unlikely(loose != txn->tw.loose_count))
|
|
379
|
+
return false;
|
|
380
|
+
|
|
381
|
+
tASSERT(txn, pages == dl->pages_including_loose);
|
|
382
|
+
if (unlikely(pages != dl->pages_including_loose))
|
|
383
|
+
return false;
|
|
384
|
+
|
|
385
|
+
for (size_t i = 1; i <= MDBX_PNL_GETSIZE(txn->tw.retired_pages); ++i) {
|
|
386
|
+
const page_t *const dp = debug_dpl_find(txn, txn->tw.retired_pages[i]);
|
|
387
|
+
tASSERT(txn, !dp);
|
|
388
|
+
if (unlikely(dp))
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/*----------------------------------------------------------------------------*/
|
|
396
|
+
|
|
397
|
+
__noinline void dpl_lru_reduce(MDBX_txn *txn) {
|
|
398
|
+
NOTICE("lru-reduce %u -> %u", txn->tw.dirtylru, txn->tw.dirtylru >> 1);
|
|
399
|
+
tASSERT(txn, (txn->flags & (MDBX_TXN_RDONLY | MDBX_WRITEMAP)) == 0);
|
|
400
|
+
do {
|
|
401
|
+
txn->tw.dirtylru >>= 1;
|
|
402
|
+
dpl_t *dl = txn->tw.dirtylist;
|
|
403
|
+
for (size_t i = 1; i <= dl->length; ++i) {
|
|
404
|
+
size_t *const ptr = ptr_disp(dl->items[i].ptr, -(ptrdiff_t)sizeof(size_t));
|
|
405
|
+
*ptr >>= 1;
|
|
406
|
+
}
|
|
407
|
+
txn = txn->parent;
|
|
408
|
+
} while (txn);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
void dpl_sift(MDBX_txn *const txn, pnl_t pl, const bool spilled) {
|
|
412
|
+
tASSERT(txn, (txn->flags & MDBX_TXN_RDONLY) == 0);
|
|
413
|
+
tASSERT(txn, (txn->flags & MDBX_WRITEMAP) == 0 || MDBX_AVOID_MSYNC);
|
|
414
|
+
if (MDBX_PNL_GETSIZE(pl) && txn->tw.dirtylist->length) {
|
|
415
|
+
tASSERT(txn, pnl_check_allocated(pl, (size_t)txn->geo.first_unallocated << spilled));
|
|
416
|
+
dpl_t *dl = dpl_sort(txn);
|
|
417
|
+
|
|
418
|
+
/* Scanning in ascend order */
|
|
419
|
+
const intptr_t step = MDBX_PNL_ASCENDING ? 1 : -1;
|
|
420
|
+
const intptr_t begin = MDBX_PNL_ASCENDING ? 1 : MDBX_PNL_GETSIZE(pl);
|
|
421
|
+
const intptr_t end = MDBX_PNL_ASCENDING ? MDBX_PNL_GETSIZE(pl) + 1 : 0;
|
|
422
|
+
tASSERT(txn, pl[begin] <= pl[end - step]);
|
|
423
|
+
|
|
424
|
+
size_t w, r = dpl_search(txn, pl[begin] >> spilled);
|
|
425
|
+
tASSERT(txn, dl->sorted == dl->length);
|
|
426
|
+
for (intptr_t i = begin; r <= dl->length;) { /* scan loop */
|
|
427
|
+
assert(i != end);
|
|
428
|
+
tASSERT(txn, !spilled || (pl[i] & 1) == 0);
|
|
429
|
+
pgno_t pl_pgno = pl[i] >> spilled;
|
|
430
|
+
pgno_t dp_pgno = dl->items[r].pgno;
|
|
431
|
+
if (likely(dp_pgno != pl_pgno)) {
|
|
432
|
+
const bool cmp = dp_pgno < pl_pgno;
|
|
433
|
+
r += cmp;
|
|
434
|
+
i += cmp ? 0 : step;
|
|
435
|
+
if (likely(i != end))
|
|
436
|
+
continue;
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/* update loop */
|
|
441
|
+
unsigned npages;
|
|
442
|
+
w = r;
|
|
443
|
+
remove_dl:
|
|
444
|
+
npages = dpl_npages(dl, r);
|
|
445
|
+
dl->pages_including_loose -= npages;
|
|
446
|
+
if (!MDBX_AVOID_MSYNC || !(txn->flags & MDBX_WRITEMAP))
|
|
447
|
+
page_shadow_release(txn->env, dl->items[r].ptr, npages);
|
|
448
|
+
++r;
|
|
449
|
+
next_i:
|
|
450
|
+
i += step;
|
|
451
|
+
if (unlikely(i == end)) {
|
|
452
|
+
while (r <= dl->length)
|
|
453
|
+
dl->items[w++] = dl->items[r++];
|
|
454
|
+
} else {
|
|
455
|
+
while (r <= dl->length) {
|
|
456
|
+
assert(i != end);
|
|
457
|
+
tASSERT(txn, !spilled || (pl[i] & 1) == 0);
|
|
458
|
+
pl_pgno = pl[i] >> spilled;
|
|
459
|
+
dp_pgno = dl->items[r].pgno;
|
|
460
|
+
if (dp_pgno < pl_pgno)
|
|
461
|
+
dl->items[w++] = dl->items[r++];
|
|
462
|
+
else if (dp_pgno > pl_pgno)
|
|
463
|
+
goto next_i;
|
|
464
|
+
else
|
|
465
|
+
goto remove_dl;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
dl->sorted = dpl_setlen(dl, w - 1);
|
|
469
|
+
txn->tw.dirtyroom += r - w;
|
|
470
|
+
tASSERT(txn, txn->tw.dirtyroom + txn->tw.dirtylist->length ==
|
|
471
|
+
(txn->parent ? txn->parent->tw.dirtyroom : txn->env->options.dp_limit));
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
void dpl_release_shadows(MDBX_txn *txn) {
|
|
478
|
+
tASSERT(txn, (txn->flags & (MDBX_TXN_RDONLY | MDBX_WRITEMAP)) == 0);
|
|
479
|
+
MDBX_env *env = txn->env;
|
|
480
|
+
dpl_t *const dl = txn->tw.dirtylist;
|
|
481
|
+
|
|
482
|
+
for (size_t i = 1; i <= dl->length; i++)
|
|
483
|
+
page_shadow_release(env, dl->items[i].ptr, dpl_npages(dl, i));
|
|
484
|
+
|
|
485
|
+
dpl_clear(dl);
|
|
486
|
+
}
|