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,130 @@
|
|
|
1
|
+
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
|
|
2
|
+
/// \copyright SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include "base.h++"
|
|
7
|
+
#include "config.h++"
|
|
8
|
+
#include "log.h++"
|
|
9
|
+
#include "utils.h++"
|
|
10
|
+
|
|
11
|
+
namespace keygen {
|
|
12
|
+
|
|
13
|
+
/* Под "генерацией ключей" здесь понимается генерация обоих значений для
|
|
14
|
+
* пар key-value, т.е. не только ключей, но и ассоциированных с ними данных.
|
|
15
|
+
*
|
|
16
|
+
* Генерацию ключей нельзя отнести к простым задачам, так как требования
|
|
17
|
+
* примерно следующие:
|
|
18
|
+
* - генерация разного количества уникальных ключей различной длины
|
|
19
|
+
* в задаваемом диапазоне;
|
|
20
|
+
* - возможность выбора как псевдо-случайного порядка ключей,
|
|
21
|
+
* так и по некоторым специфическим законам (ограниченными упорядоченными
|
|
22
|
+
* последовательностями, в шахматном порядке по граница диапазона и т.д.);
|
|
23
|
+
* - возможность генерации дубликатов с задаваемым законом распределения;
|
|
24
|
+
* - возможность генерации непересекающимися кластерами для параллельного
|
|
25
|
+
* использования в нескольких потоках;
|
|
26
|
+
* - использовать минимум ресурсов, как CPU, так и RAM, в том числе
|
|
27
|
+
* включая cache pollution и ram bandwidth.
|
|
28
|
+
*
|
|
29
|
+
* При этом заведомо известно, что для MDBX не имеет значения:
|
|
30
|
+
* - используемый алфавит (значения байтов);
|
|
31
|
+
* - частотное распределение по алфавиту;
|
|
32
|
+
* - абсолютное значение ключей или разность между отдельными значениями;
|
|
33
|
+
*
|
|
34
|
+
* Соответственно, в общих чертах, схема генерации следующая:
|
|
35
|
+
* - вводится плоская одномерная "координата" serial (uint64_t);
|
|
36
|
+
* - генерация специфических паттернов (последовательностей)
|
|
37
|
+
* реализуется посредством соответствующих преобразований "координат", при
|
|
38
|
+
* этом все подобные преобразования выполняются только над "координатой";
|
|
39
|
+
* - итоговая "координата" преобразуется в 8-байтное суррогатное значение
|
|
40
|
+
* ключа;
|
|
41
|
+
* - для получения ключей длиной МЕНЕЕ 8 байт суррогат может усекаться
|
|
42
|
+
* до ненулевых байт, в том числе до нулевой длины;
|
|
43
|
+
* - для получения ключей длиной БОЛЕЕ 8 байт суррогат дополняется
|
|
44
|
+
* нулями или псевдослучайной последовательностью;
|
|
45
|
+
*
|
|
46
|
+
* Механизм генерации паттернов:
|
|
47
|
+
* - реализованный механизм является компромиссом между скоростью/простотой
|
|
48
|
+
* и гибкостью, необходимой для получения последовательностей, которых
|
|
49
|
+
* будет достаточно для проверки сценариев разделения и слияния страниц
|
|
50
|
+
* с данными внутри mdbx;
|
|
51
|
+
* - псевдо-случайные паттерны реализуются посредством набора инъективных
|
|
52
|
+
* отображающих функций;
|
|
53
|
+
* - не-псевдо-случайные паттерны реализуются посредством параметризируемого
|
|
54
|
+
* трех-этапного преобразования:
|
|
55
|
+
* 1) смещение (сложение) по модулю;
|
|
56
|
+
* 2) циклический сдвиг;
|
|
57
|
+
* 3) добавление абсолютного смещения (базы);
|
|
58
|
+
*
|
|
59
|
+
* Также см. описание параметров генератора ключей и значений в config.h */
|
|
60
|
+
|
|
61
|
+
typedef uint64_t serial_t;
|
|
62
|
+
|
|
63
|
+
enum : serial_t { serial_minwith = 8, serial_maxwith = sizeof(serial_t) * 8, serial_allones = ~(serial_t)0u };
|
|
64
|
+
|
|
65
|
+
struct result {
|
|
66
|
+
MDBX_val value;
|
|
67
|
+
size_t limit;
|
|
68
|
+
union {
|
|
69
|
+
uint8_t bytes[sizeof(uint64_t)];
|
|
70
|
+
uint32_t u32;
|
|
71
|
+
uint64_t u64;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
std::string as_string() const { return std::string((const char *)value.iov_base, value.iov_len); }
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
//-----------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
struct buffer_deleter /* : public std::unary_function<void, result *> */ {
|
|
80
|
+
void operator()(result *buffer) const { free(buffer); }
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
typedef std::unique_ptr<result, buffer_deleter> buffer;
|
|
84
|
+
|
|
85
|
+
buffer alloc(size_t limit);
|
|
86
|
+
|
|
87
|
+
class maker {
|
|
88
|
+
config::keygen_params_pod mapping;
|
|
89
|
+
serial_t base{0};
|
|
90
|
+
serial_t salt{0};
|
|
91
|
+
|
|
92
|
+
struct essentials {
|
|
93
|
+
uint16_t minlen{0};
|
|
94
|
+
enum { prng_fill_flag = 1, value_age_minwidth = 5 };
|
|
95
|
+
uint16_t flags{0};
|
|
96
|
+
uint32_t maxlen{0};
|
|
97
|
+
serial_t mask{0};
|
|
98
|
+
unsigned bits{0};
|
|
99
|
+
} key_essentials, value_essentials;
|
|
100
|
+
unsigned value_age_bits{0};
|
|
101
|
+
serial_t value_age_mask{0};
|
|
102
|
+
|
|
103
|
+
static serial_t mk_begin(serial_t serial, const essentials ¶ms, result &out);
|
|
104
|
+
static void mk_continue(const serial_t serial, const essentials ¶ms, result &out);
|
|
105
|
+
|
|
106
|
+
public:
|
|
107
|
+
void pair(serial_t serial, const buffer &key, buffer &value, serial_t value_age, const bool keylen_changeable);
|
|
108
|
+
void setup(const config::actor_params_pod &actor, unsigned thread_number);
|
|
109
|
+
bool is_unordered() const;
|
|
110
|
+
void seek2end(serial_t &serial) const;
|
|
111
|
+
|
|
112
|
+
bool increment(serial_t &serial, int64_t delta) const;
|
|
113
|
+
bool increment_key_part(serial_t &serial, int64_t delta, bool reset_value_part = true) const {
|
|
114
|
+
if (reset_value_part) {
|
|
115
|
+
serial_t value_part_bits = ((serial_t(1) << mapping.split) - 1);
|
|
116
|
+
serial |= value_part_bits;
|
|
117
|
+
if (delta >= 0)
|
|
118
|
+
serial &= ~value_part_bits;
|
|
119
|
+
}
|
|
120
|
+
return increment(serial, int64_t(uint64_t(delta) << mapping.split));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
serial_t remix_age(serial_t serial) const {
|
|
124
|
+
return (UINT64_C(768097847591) * (serial ^ UINT64_C(768097847591))) & value_age_mask;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
void log_pair(logging::loglevel level, const char *prefix, const buffer &key, buffer &value);
|
|
129
|
+
|
|
130
|
+
} /* namespace keygen */
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
|
|
2
|
+
/// \copyright SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
#include "test.h++"
|
|
5
|
+
|
|
6
|
+
static void fflushall() { fflush(nullptr); }
|
|
7
|
+
|
|
8
|
+
void failure(const char *fmt, ...) {
|
|
9
|
+
va_list ap;
|
|
10
|
+
va_start(ap, fmt);
|
|
11
|
+
fflushall();
|
|
12
|
+
logging::output_nocheckloglevel_ap(logging::failure, fmt, ap);
|
|
13
|
+
va_end(ap);
|
|
14
|
+
fflushall();
|
|
15
|
+
exit(EXIT_FAILURE);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const char *test_strerror(int errnum) {
|
|
19
|
+
static __thread char buf[1024];
|
|
20
|
+
return mdbx_strerror_r(errnum, buf, sizeof(buf));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
MDBX_NORETURN void failure_perror(const char *what, int errnum) {
|
|
24
|
+
failure("%s failed: %s (%d)\n", what, test_strerror(errnum), errnum);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//-----------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
static void mdbx_logger(MDBX_log_level_t priority, const char *function, int line, const char *fmt,
|
|
30
|
+
va_list args) MDBX_CXX17_NOEXCEPT {
|
|
31
|
+
if (function) {
|
|
32
|
+
if (priority == MDBX_LOG_FATAL)
|
|
33
|
+
log_error("mdbx: fatal failure: %s, %d", function, line);
|
|
34
|
+
logging::output_nocheckloglevel(logging::loglevel(priority),
|
|
35
|
+
strncmp(function, "mdbx_", 5) == 0 ? "%s: " : "mdbx %s: ", function);
|
|
36
|
+
logging::feed_ap(fmt, args);
|
|
37
|
+
} else
|
|
38
|
+
logging::feed_ap(fmt, args);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
namespace logging {
|
|
42
|
+
|
|
43
|
+
/* логирование может быть вызвано после деструкторов */
|
|
44
|
+
static char prefix_buf[64];
|
|
45
|
+
static size_t prefix_len;
|
|
46
|
+
static std::string suffix_buf;
|
|
47
|
+
static const char *suffix_ptr = "~~~";
|
|
48
|
+
struct suffix_cleaner {
|
|
49
|
+
suffix_cleaner() { suffix_ptr = ""; }
|
|
50
|
+
~suffix_cleaner() { suffix_ptr = "~~~"; }
|
|
51
|
+
} static anchor;
|
|
52
|
+
|
|
53
|
+
static loglevel level;
|
|
54
|
+
static FILE *flow;
|
|
55
|
+
|
|
56
|
+
void setlevel(loglevel priority) {
|
|
57
|
+
level = priority;
|
|
58
|
+
int rc = mdbx_setup_debug(MDBX_log_level_t(priority),
|
|
59
|
+
MDBX_DBG_ASSERT | MDBX_DBG_AUDIT | MDBX_DBG_JITTER | MDBX_DBG_DUMP, mdbx_logger);
|
|
60
|
+
log_trace("set mdbx debug-opts: 0x%02x", rc);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
void setup(const std::string &prefix) {
|
|
64
|
+
prefix_len = std::min(prefix.size(), sizeof(prefix_buf) - 1);
|
|
65
|
+
memcpy(prefix_buf, prefix.data(), prefix_len);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void setup(loglevel priority, const std::string &prefix) {
|
|
69
|
+
setlevel(priority);
|
|
70
|
+
setup(prefix);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const char *level2str(const loglevel alevel) {
|
|
74
|
+
switch (alevel) {
|
|
75
|
+
default:
|
|
76
|
+
return "invalid/unknown";
|
|
77
|
+
case extra:
|
|
78
|
+
return "extra";
|
|
79
|
+
case trace:
|
|
80
|
+
return "trace";
|
|
81
|
+
case debug:
|
|
82
|
+
return "debug";
|
|
83
|
+
case verbose:
|
|
84
|
+
return "verbose";
|
|
85
|
+
case notice:
|
|
86
|
+
return "notice";
|
|
87
|
+
case warning:
|
|
88
|
+
return "warning";
|
|
89
|
+
case error:
|
|
90
|
+
return "error";
|
|
91
|
+
case failure:
|
|
92
|
+
return "failure";
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
bool output(const loglevel priority, const char *format, ...) {
|
|
97
|
+
if (lower(priority, level))
|
|
98
|
+
return false;
|
|
99
|
+
|
|
100
|
+
va_list ap;
|
|
101
|
+
va_start(ap, format);
|
|
102
|
+
output_nocheckloglevel_ap(priority, format, ap);
|
|
103
|
+
va_end(ap);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
void ln() {
|
|
108
|
+
if (flow) {
|
|
109
|
+
putc('\n', flow);
|
|
110
|
+
if (flow != stdout)
|
|
111
|
+
putc('\n', stdout);
|
|
112
|
+
flow = nullptr;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
void output_nocheckloglevel_ap(const logging::loglevel priority, const char *format, va_list ap) {
|
|
117
|
+
ln();
|
|
118
|
+
chrono::time now = chrono::now_realtime();
|
|
119
|
+
struct tm tm;
|
|
120
|
+
#ifdef _MSC_VER
|
|
121
|
+
int rc = _localtime32_s(&tm, (const __time32_t *)&now.utc);
|
|
122
|
+
#elif defined(_WIN32) || defined(_WIN64)
|
|
123
|
+
const time_t time_proxy = now.utc;
|
|
124
|
+
int rc = localtime_s(&tm, &time_proxy);
|
|
125
|
+
#else
|
|
126
|
+
time_t time = now.utc;
|
|
127
|
+
int rc = localtime_r(&time, &tm) ? MDBX_SUCCESS : errno;
|
|
128
|
+
#endif
|
|
129
|
+
if (rc != MDBX_SUCCESS)
|
|
130
|
+
failure_perror("localtime_r()", rc);
|
|
131
|
+
|
|
132
|
+
fprintf(stdout, "[ %02d%02d%02d-%02d:%02d:%02d.%06d_%05lu %-10s %.4s ] %s" /* TODO */, tm.tm_year - 100,
|
|
133
|
+
tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, chrono::fractional2us(now.fractional),
|
|
134
|
+
(long)osal_getpid(), prefix_buf, level2str(priority), suffix_ptr);
|
|
135
|
+
|
|
136
|
+
va_list ones;
|
|
137
|
+
memset(&ones, 0, sizeof(ones)) /* zap MSVC and other goofy compilers */;
|
|
138
|
+
if (same_or_higher(priority, error))
|
|
139
|
+
va_copy(ones, ap);
|
|
140
|
+
vfprintf(stdout, format, ap);
|
|
141
|
+
|
|
142
|
+
size_t len = strlen(format);
|
|
143
|
+
char end = len ? format[len - 1] : '\0';
|
|
144
|
+
|
|
145
|
+
switch (end) {
|
|
146
|
+
default:
|
|
147
|
+
putc('\n', stdout);
|
|
148
|
+
break;
|
|
149
|
+
case '\n':
|
|
150
|
+
break;
|
|
151
|
+
case ' ':
|
|
152
|
+
case '_':
|
|
153
|
+
case ':':
|
|
154
|
+
case '|':
|
|
155
|
+
case ',':
|
|
156
|
+
case '\t':
|
|
157
|
+
case '\b':
|
|
158
|
+
case '\r':
|
|
159
|
+
case '\0':
|
|
160
|
+
flow = stdout;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (same_or_higher(priority, error)) {
|
|
165
|
+
if (flow)
|
|
166
|
+
flow = stderr;
|
|
167
|
+
fprintf(stderr, "[ %05lu %-10s %.4s ] %s", (long)osal_getpid(), prefix_buf, level2str(priority), suffix_ptr);
|
|
168
|
+
vfprintf(stderr, format, ones);
|
|
169
|
+
va_end(ones);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
bool feed_ap(const char *format, va_list ap) {
|
|
174
|
+
if (!flow)
|
|
175
|
+
return false;
|
|
176
|
+
|
|
177
|
+
if (flow == stderr) {
|
|
178
|
+
va_list ones;
|
|
179
|
+
va_copy(ones, ap);
|
|
180
|
+
vfprintf(stdout, format, ones);
|
|
181
|
+
va_end(ones);
|
|
182
|
+
}
|
|
183
|
+
vfprintf(flow, format, ap);
|
|
184
|
+
size_t len = strlen(format);
|
|
185
|
+
if (len && format[len - 1] == '\n')
|
|
186
|
+
flow = nullptr;
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
bool feed(const char *format, ...) {
|
|
191
|
+
if (!flow)
|
|
192
|
+
return false;
|
|
193
|
+
|
|
194
|
+
va_list ap;
|
|
195
|
+
va_start(ap, format);
|
|
196
|
+
feed_ap(format, ap);
|
|
197
|
+
va_end(ap);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
local_suffix::local_suffix(const char *c_str) : trim_pos(suffix_buf.size()), indent(0) {
|
|
202
|
+
suffix_buf.append(c_str);
|
|
203
|
+
suffix_ptr = suffix_buf.c_str();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
local_suffix::local_suffix(const std::string &str) : trim_pos(suffix_buf.size()), indent(0) {
|
|
207
|
+
suffix_buf.append(str);
|
|
208
|
+
suffix_ptr = suffix_buf.c_str();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
void local_suffix::push() {
|
|
212
|
+
indent += 1;
|
|
213
|
+
suffix_buf.push_back('\t');
|
|
214
|
+
suffix_ptr = suffix_buf.c_str();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
void local_suffix::pop() {
|
|
218
|
+
assert(indent > 0);
|
|
219
|
+
if (indent > 0) {
|
|
220
|
+
indent -= 1;
|
|
221
|
+
suffix_buf.pop_back();
|
|
222
|
+
suffix_ptr = suffix_buf.c_str();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
local_suffix::~local_suffix() {
|
|
227
|
+
suffix_buf.erase(trim_pos);
|
|
228
|
+
suffix_ptr = suffix_buf.c_str();
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
void progress_canary(bool active) {
|
|
232
|
+
static chrono::time progress_timestamp;
|
|
233
|
+
chrono::time now = chrono::now_monotonic();
|
|
234
|
+
|
|
235
|
+
if (now.fixedpoint - progress_timestamp.fixedpoint < chrono::from_ms(42).fixedpoint)
|
|
236
|
+
return;
|
|
237
|
+
|
|
238
|
+
if (osal_progress_push(active)) {
|
|
239
|
+
progress_timestamp = now;
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (progress_timestamp.fixedpoint == 0) {
|
|
244
|
+
putc('>', stderr);
|
|
245
|
+
progress_timestamp = now;
|
|
246
|
+
} else if (global::config::console_mode) {
|
|
247
|
+
if (active) {
|
|
248
|
+
static int last_point = -1;
|
|
249
|
+
int point = (now.fixedpoint >> 29) & 3;
|
|
250
|
+
if (point != last_point) {
|
|
251
|
+
progress_timestamp = now;
|
|
252
|
+
fprintf(stderr, "%c\b", "-\\|/"[last_point = point]);
|
|
253
|
+
}
|
|
254
|
+
} else if (now.fixedpoint - progress_timestamp.fixedpoint > chrono::from_seconds(2).fixedpoint) {
|
|
255
|
+
progress_timestamp = now;
|
|
256
|
+
fprintf(stderr, "%c\b", "@*"[now.utc & 1]);
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
static int count;
|
|
260
|
+
if (active && now.fixedpoint - progress_timestamp.fixedpoint > chrono::from_seconds(1).fixedpoint) {
|
|
261
|
+
putc('.', stderr);
|
|
262
|
+
progress_timestamp = now;
|
|
263
|
+
++count;
|
|
264
|
+
} else if (now.fixedpoint - progress_timestamp.fixedpoint > chrono::from_seconds(5).fixedpoint) {
|
|
265
|
+
putc("@*"[now.utc & 1], stderr);
|
|
266
|
+
progress_timestamp = now;
|
|
267
|
+
++count;
|
|
268
|
+
}
|
|
269
|
+
if (count == 60) {
|
|
270
|
+
count = 0;
|
|
271
|
+
putc('\n', stderr);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
fflush(stderr);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
} // namespace logging
|
|
278
|
+
|
|
279
|
+
void log_extra(const char *msg, ...) {
|
|
280
|
+
logging::ln();
|
|
281
|
+
if (logging::same_or_higher(logging::extra, logging::level)) {
|
|
282
|
+
va_list ap;
|
|
283
|
+
va_start(ap, msg);
|
|
284
|
+
logging::output_nocheckloglevel_ap(logging::extra, msg, ap);
|
|
285
|
+
va_end(ap);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
void log_trace(const char *msg, ...) {
|
|
290
|
+
logging::ln();
|
|
291
|
+
if (logging::same_or_higher(logging::trace, logging::level)) {
|
|
292
|
+
va_list ap;
|
|
293
|
+
va_start(ap, msg);
|
|
294
|
+
logging::output_nocheckloglevel_ap(logging::trace, msg, ap);
|
|
295
|
+
va_end(ap);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
void log_debug(const char *msg, ...) {
|
|
300
|
+
logging::ln();
|
|
301
|
+
if (logging::same_or_higher(logging::debug, logging::level)) {
|
|
302
|
+
va_list ap;
|
|
303
|
+
va_start(ap, msg);
|
|
304
|
+
logging::output_nocheckloglevel_ap(logging::debug, msg, ap);
|
|
305
|
+
va_end(ap);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
void log_verbose(const char *msg, ...) {
|
|
310
|
+
logging::ln();
|
|
311
|
+
if (logging::same_or_higher(logging::verbose, logging::level)) {
|
|
312
|
+
va_list ap;
|
|
313
|
+
va_start(ap, msg);
|
|
314
|
+
logging::output_nocheckloglevel_ap(logging::verbose, msg, ap);
|
|
315
|
+
va_end(ap);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
void log_notice(const char *msg, ...) {
|
|
320
|
+
logging::ln();
|
|
321
|
+
if (logging::same_or_higher(logging::notice, logging::level)) {
|
|
322
|
+
va_list ap;
|
|
323
|
+
va_start(ap, msg);
|
|
324
|
+
logging::output_nocheckloglevel_ap(logging::notice, msg, ap);
|
|
325
|
+
va_end(ap);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
void log_warning(const char *msg, ...) {
|
|
330
|
+
logging::ln();
|
|
331
|
+
if (logging::same_or_higher(logging::warning, logging::level)) {
|
|
332
|
+
va_list ap;
|
|
333
|
+
va_start(ap, msg);
|
|
334
|
+
logging::output_nocheckloglevel_ap(logging::warning, msg, ap);
|
|
335
|
+
va_end(ap);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
void log_error(const char *msg, ...) {
|
|
340
|
+
logging::ln();
|
|
341
|
+
if (logging::same_or_higher(logging::error, logging::level)) {
|
|
342
|
+
va_list ap;
|
|
343
|
+
va_start(ap, msg);
|
|
344
|
+
logging::output_nocheckloglevel_ap(logging::error, msg, ap);
|
|
345
|
+
va_end(ap);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
void log_trouble(const char *where, const char *what, int errnum) {
|
|
350
|
+
log_error("%s: %s %s", where, what, test_strerror(errnum));
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
bool log_enabled(const logging::loglevel priority) { return logging::same_or_higher(priority, logging::level); }
|
|
354
|
+
|
|
355
|
+
void log_flush(void) {
|
|
356
|
+
logging::ln();
|
|
357
|
+
fflushall();
|
|
358
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2015-2025
|
|
2
|
+
/// \copyright SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include "base.h++"
|
|
7
|
+
#include "chrono.h++"
|
|
8
|
+
|
|
9
|
+
MDBX_NORETURN void usage(void);
|
|
10
|
+
MDBX_NORETURN void MDBX_PRINTF_ARGS(1, 2) failure(const char *fmt, ...);
|
|
11
|
+
MDBX_NORETURN void failure_perror(const char *what, int errnum);
|
|
12
|
+
const char *test_strerror(int errnum);
|
|
13
|
+
|
|
14
|
+
namespace logging {
|
|
15
|
+
|
|
16
|
+
enum loglevel {
|
|
17
|
+
extra = MDBX_LOG_EXTRA,
|
|
18
|
+
trace = MDBX_LOG_TRACE,
|
|
19
|
+
debug = MDBX_LOG_DEBUG,
|
|
20
|
+
verbose = MDBX_LOG_VERBOSE,
|
|
21
|
+
notice = MDBX_LOG_NOTICE,
|
|
22
|
+
warning = MDBX_LOG_WARN,
|
|
23
|
+
error = MDBX_LOG_ERROR,
|
|
24
|
+
failure = MDBX_LOG_FATAL
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
inline bool lower(loglevel left, loglevel right) {
|
|
28
|
+
static_assert(MDBX_LOG_EXTRA > MDBX_LOG_FATAL, "WTF?");
|
|
29
|
+
return left > right;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
inline bool same_or_higher(loglevel left, loglevel right) { return left <= right; }
|
|
33
|
+
|
|
34
|
+
const char *level2str(const loglevel level);
|
|
35
|
+
void setup(loglevel priority, const std::string &prefix);
|
|
36
|
+
void setup(const std::string &prefix);
|
|
37
|
+
void setlevel(loglevel priority);
|
|
38
|
+
|
|
39
|
+
void output_nocheckloglevel_ap(const loglevel priority, const char *format, va_list ap);
|
|
40
|
+
bool MDBX_PRINTF_ARGS(2, 3) output(const loglevel priority, const char *format, ...);
|
|
41
|
+
bool feed_ap(const char *format, va_list ap);
|
|
42
|
+
bool MDBX_PRINTF_ARGS(1, 2) feed(const char *format, ...);
|
|
43
|
+
void ln();
|
|
44
|
+
|
|
45
|
+
void inline MDBX_PRINTF_ARGS(2, 3) output_nocheckloglevel(const loglevel priority, const char *format, ...) {
|
|
46
|
+
va_list ap;
|
|
47
|
+
va_start(ap, format);
|
|
48
|
+
output_nocheckloglevel_ap(priority, format, ap);
|
|
49
|
+
va_end(ap);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void progress_canary(bool active);
|
|
53
|
+
|
|
54
|
+
class local_suffix {
|
|
55
|
+
protected:
|
|
56
|
+
size_t trim_pos;
|
|
57
|
+
int indent;
|
|
58
|
+
|
|
59
|
+
public:
|
|
60
|
+
local_suffix(const local_suffix &) = delete;
|
|
61
|
+
local_suffix(const local_suffix &&) = delete;
|
|
62
|
+
const local_suffix &operator=(const local_suffix &) = delete;
|
|
63
|
+
|
|
64
|
+
local_suffix(const char *c_str);
|
|
65
|
+
local_suffix(const std::string &str);
|
|
66
|
+
void push();
|
|
67
|
+
void pop();
|
|
68
|
+
~local_suffix();
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
} // namespace logging
|
|
72
|
+
|
|
73
|
+
void MDBX_PRINTF_ARGS(1, 2) static inline log_null(const char *msg, ...) { return (void)msg; }
|
|
74
|
+
void MDBX_PRINTF_ARGS(1, 2) log_extra(const char *msg, ...);
|
|
75
|
+
void MDBX_PRINTF_ARGS(1, 2) log_trace(const char *msg, ...);
|
|
76
|
+
void MDBX_PRINTF_ARGS(1, 2) log_debug(const char *msg, ...);
|
|
77
|
+
void MDBX_PRINTF_ARGS(1, 2) log_verbose(const char *msg, ...);
|
|
78
|
+
void MDBX_PRINTF_ARGS(1, 2) log_notice(const char *msg, ...);
|
|
79
|
+
void MDBX_PRINTF_ARGS(1, 2) log_warning(const char *msg, ...);
|
|
80
|
+
void MDBX_PRINTF_ARGS(1, 2) log_error(const char *msg, ...);
|
|
81
|
+
|
|
82
|
+
void log_trouble(const char *where, const char *what, int errnum);
|
|
83
|
+
void log_flush(void);
|
|
84
|
+
bool log_enabled(const logging::loglevel priority);
|
|
85
|
+
|
|
86
|
+
#undef TRACE
|
|
87
|
+
#ifdef _DEBUG
|
|
88
|
+
#define TRACE(...) log_trace(__VA_ARGS__)
|
|
89
|
+
#else
|
|
90
|
+
#define TRACE(...) log_null(__VA_ARGS__)
|
|
91
|
+
#endif
|