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,237 @@
|
|
|
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
|
+
class testcase_append : public testcase {
|
|
7
|
+
public:
|
|
8
|
+
testcase_append(const actor_config &config, const mdbx_pid_t pid) : testcase(config, pid) {}
|
|
9
|
+
bool run() override;
|
|
10
|
+
|
|
11
|
+
static bool review_params(actor_params ¶ms, unsigned space_id) {
|
|
12
|
+
if (!testcase::review_params(params, space_id))
|
|
13
|
+
return false;
|
|
14
|
+
const bool ordered = !flipcoin_x3();
|
|
15
|
+
log_notice("the '%s' key-generation mode is selected", ordered ? "ordered/linear" : "unordered/non-linear");
|
|
16
|
+
if (ordered && !params.make_keygen_linear())
|
|
17
|
+
return false;
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
REGISTER_TESTCASE(append);
|
|
22
|
+
|
|
23
|
+
bool testcase_append::run() {
|
|
24
|
+
const bool reverse = flipcoin();
|
|
25
|
+
const char *const caption = reverse ? "ahead" : "append";
|
|
26
|
+
log_notice("the '%s' scenario is selected", caption);
|
|
27
|
+
|
|
28
|
+
int err = db_open__begin__table_create_open_clean(dbi);
|
|
29
|
+
if (unlikely(err != MDBX_SUCCESS)) {
|
|
30
|
+
log_notice("%s: bailout-prepare due '%s'", caption, mdbx_strerror(err));
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
cursor_open(dbi);
|
|
35
|
+
keyvalue_maker.setup(config.params, 0 /* thread_number */);
|
|
36
|
+
/* LY: тест наполнения таблиц в append-режиме,
|
|
37
|
+
* при котором записи добавляются строго в конец (в порядке сортировки) */
|
|
38
|
+
const MDBX_put_flags_t flags = reverse ? ((config.params.table_flags & MDBX_DUPSORT) ? MDBX_UPSERT : MDBX_NOOVERWRITE)
|
|
39
|
+
: ((config.params.table_flags & MDBX_DUPSORT)
|
|
40
|
+
? (flipcoin() ? MDBX_APPEND | MDBX_APPENDDUP : MDBX_APPENDDUP)
|
|
41
|
+
: MDBX_APPEND);
|
|
42
|
+
|
|
43
|
+
key = keygen::alloc(config.params.keylen_max);
|
|
44
|
+
data = keygen::alloc(config.params.datalen_max);
|
|
45
|
+
|
|
46
|
+
simple_checksum inserted_checksum;
|
|
47
|
+
uint64_t inserted_number = 0;
|
|
48
|
+
uint64_t serial_count = 0;
|
|
49
|
+
if (reverse)
|
|
50
|
+
keyvalue_maker.seek2end(serial_count);
|
|
51
|
+
|
|
52
|
+
unsigned txn_nops = 0;
|
|
53
|
+
uint64_t committed_inserted_number = inserted_number;
|
|
54
|
+
simple_checksum committed_inserted_checksum = inserted_checksum;
|
|
55
|
+
while (should_continue()) {
|
|
56
|
+
const keygen::serial_t serial = serial_count;
|
|
57
|
+
const bool turn_key = (config.params.table_flags & MDBX_DUPSORT) == 0 || flipcoin_n(config.params.keygen.split);
|
|
58
|
+
if (turn_key ? !keyvalue_maker.increment_key_part(serial_count, reverse ? -1 : 1)
|
|
59
|
+
: !keyvalue_maker.increment(serial_count, reverse ? -1 : 1)) {
|
|
60
|
+
// дошли до границы пространства ключей
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
log_trace("%s: insert-a %" PRIu64, caption, serial);
|
|
65
|
+
generate_pair(serial);
|
|
66
|
+
// keygen::log_pair(logging::verbose, "append.", key, data);
|
|
67
|
+
|
|
68
|
+
bool expect_key_mismatch = false;
|
|
69
|
+
if (flags & (MDBX_APPEND | MDBX_APPENDDUP)) {
|
|
70
|
+
MDBX_val ge_key = key->value;
|
|
71
|
+
MDBX_val ge_data = data->value;
|
|
72
|
+
err = mdbx_get_equal_or_great(txn_guard.get(), dbi, &ge_key, &ge_data);
|
|
73
|
+
|
|
74
|
+
if (err == MDBX_SUCCESS /* exact match */) {
|
|
75
|
+
expect_key_mismatch = true;
|
|
76
|
+
assert(inserted_number > 0);
|
|
77
|
+
assert(mdbx_cmp(txn_guard.get(), dbi, &key->value, &ge_key) == 0);
|
|
78
|
+
assert((config.params.table_flags & MDBX_DUPSORT) == 0 ||
|
|
79
|
+
mdbx_dcmp(txn_guard.get(), dbi, &data->value, &ge_data) == 0);
|
|
80
|
+
assert(inserted_number > 0);
|
|
81
|
+
} else if (err == MDBX_RESULT_TRUE /* have key-value pair great than */) {
|
|
82
|
+
assert(mdbx_cmp(txn_guard.get(), dbi, &key->value, &ge_key) < 0 ||
|
|
83
|
+
((config.params.table_flags & MDBX_DUPSORT) &&
|
|
84
|
+
mdbx_cmp(txn_guard.get(), dbi, &key->value, &ge_key) == 0 &&
|
|
85
|
+
mdbx_dcmp(txn_guard.get(), dbi, &data->value, &ge_data) < 0));
|
|
86
|
+
switch (int(flags)) {
|
|
87
|
+
default:
|
|
88
|
+
abort();
|
|
89
|
+
#if CONSTEXPR_ENUM_FLAGS_OPERATIONS
|
|
90
|
+
case MDBX_APPEND | MDBX_APPENDDUP:
|
|
91
|
+
#else
|
|
92
|
+
case int(MDBX_APPEND) | int(MDBX_APPENDDUP):
|
|
93
|
+
#endif
|
|
94
|
+
assert((config.params.table_flags & MDBX_DUPSORT) != 0);
|
|
95
|
+
__fallthrough;
|
|
96
|
+
// fall through
|
|
97
|
+
case MDBX_APPEND:
|
|
98
|
+
expect_key_mismatch = true;
|
|
99
|
+
break;
|
|
100
|
+
case MDBX_APPENDDUP:
|
|
101
|
+
assert((config.params.table_flags & MDBX_DUPSORT) != 0);
|
|
102
|
+
expect_key_mismatch = mdbx_cmp(txn_guard.get(), dbi, &key->value, &ge_key) == 0;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
} else if (err == MDBX_NOTFOUND /* all pair are less than */) {
|
|
106
|
+
switch (int(flags)) {
|
|
107
|
+
default:
|
|
108
|
+
abort();
|
|
109
|
+
case MDBX_APPENDDUP:
|
|
110
|
+
#if CONSTEXPR_ENUM_FLAGS_OPERATIONS
|
|
111
|
+
case MDBX_APPEND | MDBX_APPENDDUP:
|
|
112
|
+
#else
|
|
113
|
+
case int(MDBX_APPEND) | int(MDBX_APPENDDUP):
|
|
114
|
+
#endif
|
|
115
|
+
assert((config.params.table_flags & MDBX_DUPSORT) != 0);
|
|
116
|
+
__fallthrough;
|
|
117
|
+
// fall through
|
|
118
|
+
case MDBX_APPEND:
|
|
119
|
+
expect_key_mismatch = false;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
} else
|
|
123
|
+
failure_perror("mdbx_get_equal_or_great()", err);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
err = mdbx_cursor_put(cursor_guard.get(), &key->value, &data->value, flags);
|
|
127
|
+
if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) {
|
|
128
|
+
log_notice("%s: bailout-insert due '%s'", caption, mdbx_strerror(err));
|
|
129
|
+
txn_end(true);
|
|
130
|
+
inserted_number = committed_inserted_number;
|
|
131
|
+
inserted_checksum = committed_inserted_checksum;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!expect_key_mismatch) {
|
|
136
|
+
if (unlikely(err != MDBX_SUCCESS))
|
|
137
|
+
failure_perror("mdbx_cursor_put(append)", err);
|
|
138
|
+
++inserted_number;
|
|
139
|
+
inserted_checksum.push((uint32_t)inserted_number, key->value);
|
|
140
|
+
inserted_checksum.push(10639, data->value);
|
|
141
|
+
|
|
142
|
+
if (config.params.speculum) {
|
|
143
|
+
Item item(iov2dataview(key), iov2dataview(data));
|
|
144
|
+
const auto insertion_result = speculum.insert(item);
|
|
145
|
+
if (!insertion_result.second) {
|
|
146
|
+
char dump_key[32], dump_value[32];
|
|
147
|
+
log_error("speculum.append: unexpected %s {%s, %s}", "MDBX_SUCCESS",
|
|
148
|
+
mdbx_dump_val(&key->value, dump_key, sizeof(dump_key)),
|
|
149
|
+
mdbx_dump_val(&data->value, dump_value, sizeof(dump_value)));
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
} else if (unlikely(err != MDBX_EKEYMISMATCH))
|
|
154
|
+
failure_perror("mdbx_cursor_put(append) != MDBX_EKEYMISMATCH", err);
|
|
155
|
+
|
|
156
|
+
if (++txn_nops >= config.params.batch_write) {
|
|
157
|
+
err = breakable_restart();
|
|
158
|
+
if (unlikely(err != MDBX_SUCCESS)) {
|
|
159
|
+
log_notice("%s: bailout-commit due '%s'", caption, mdbx_strerror(err));
|
|
160
|
+
inserted_number = committed_inserted_number;
|
|
161
|
+
inserted_checksum = committed_inserted_checksum;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
committed_inserted_number = inserted_number;
|
|
165
|
+
committed_inserted_checksum = inserted_checksum;
|
|
166
|
+
txn_nops = 0;
|
|
167
|
+
if (!speculum_verify()) {
|
|
168
|
+
log_notice("append: bailout breakable_restart");
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
report(1);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (txn_guard) {
|
|
177
|
+
err = breakable_commit();
|
|
178
|
+
if (unlikely(err != MDBX_SUCCESS)) {
|
|
179
|
+
log_notice("%s: bailout-commit due '%s'", caption, mdbx_strerror(err));
|
|
180
|
+
inserted_number = committed_inserted_number;
|
|
181
|
+
inserted_checksum = committed_inserted_checksum;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//----------------------------------------------------------------------------
|
|
185
|
+
txn_begin(true);
|
|
186
|
+
if (!speculum_verify()) {
|
|
187
|
+
log_notice("append: bailout verify");
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
cursor_renew();
|
|
191
|
+
|
|
192
|
+
MDBX_val check_key, check_data;
|
|
193
|
+
err = mdbx_cursor_get(cursor_guard.get(), &check_key, &check_data, reverse ? MDBX_LAST : MDBX_FIRST);
|
|
194
|
+
if (likely(inserted_number)) {
|
|
195
|
+
if (unlikely(err != MDBX_SUCCESS))
|
|
196
|
+
failure_perror("mdbx_cursor_get(MDBX_FIRST)", err);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
simple_checksum read_checksum;
|
|
200
|
+
uint64_t read_count = 0;
|
|
201
|
+
while (err == MDBX_SUCCESS) {
|
|
202
|
+
++read_count;
|
|
203
|
+
read_checksum.push((uint32_t)read_count, check_key);
|
|
204
|
+
read_checksum.push(10639, check_data);
|
|
205
|
+
|
|
206
|
+
err = mdbx_cursor_get(cursor_guard.get(), &check_key, &check_data, reverse ? MDBX_PREV : MDBX_NEXT);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (unlikely(err != MDBX_NOTFOUND))
|
|
210
|
+
failure_perror("mdbx_cursor_get(MDBX_NEXT) != EOF", err);
|
|
211
|
+
|
|
212
|
+
if (unlikely(read_count != inserted_number))
|
|
213
|
+
failure("read_count(%" PRIu64 ") != inserted_number(%" PRIu64 ")", read_count, inserted_number);
|
|
214
|
+
|
|
215
|
+
if (unlikely(read_checksum.value != inserted_checksum.value) && !keyvalue_maker.is_unordered())
|
|
216
|
+
failure("read_checksum(0x%016" PRIu64 ") "
|
|
217
|
+
"!= inserted_checksum(0x%016" PRIu64 ")",
|
|
218
|
+
read_checksum.value, inserted_checksum.value);
|
|
219
|
+
|
|
220
|
+
cursor_close();
|
|
221
|
+
txn_end(true);
|
|
222
|
+
//----------------------------------------------------------------------------
|
|
223
|
+
|
|
224
|
+
if (dbi) {
|
|
225
|
+
if (config.params.drop_table && !mode_readonly()) {
|
|
226
|
+
txn_begin(false);
|
|
227
|
+
db_table_drop(dbi);
|
|
228
|
+
err = breakable_commit();
|
|
229
|
+
if (unlikely(err != MDBX_SUCCESS)) {
|
|
230
|
+
log_notice("%s: bailout-clean due '%s'", caption, mdbx_strerror(err));
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
} else
|
|
234
|
+
db_table_close(dbi);
|
|
235
|
+
}
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
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 "../src/essentials.h"
|
|
7
|
+
|
|
8
|
+
#ifdef _MSC_VER
|
|
9
|
+
#pragma warning(push, 1)
|
|
10
|
+
#pragma warning(disable : 4548) /* expression before comma has no effect; \
|
|
11
|
+
expected expression with side - effect */
|
|
12
|
+
#pragma warning(disable : 4530) /* C++ exception handler used, but unwind \
|
|
13
|
+
semantics are not enabled. Specify /EHsc */
|
|
14
|
+
#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling \
|
|
15
|
+
mode specified; termination on exception \
|
|
16
|
+
is not guaranteed. Specify /EHsc */
|
|
17
|
+
#endif /* _MSC_VER (warnings) */
|
|
18
|
+
|
|
19
|
+
#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
|
|
20
|
+
/* If you wish to build your application for a previous Windows platform,
|
|
21
|
+
* include WinSDKVer.h and set the _WIN32_WINNT macro to the platform you
|
|
22
|
+
* wish to support before including SDKDDKVer.h.
|
|
23
|
+
*
|
|
24
|
+
* TODO: #define _WIN32_WINNT WIN32_MUSTDIE */
|
|
25
|
+
#include <SDKDDKVer.h>
|
|
26
|
+
#endif /* WINDOWS */
|
|
27
|
+
|
|
28
|
+
#include <errno.h>
|
|
29
|
+
#include <limits.h>
|
|
30
|
+
#include <stdio.h>
|
|
31
|
+
#include <stdlib.h>
|
|
32
|
+
#include <string.h>
|
|
33
|
+
#include <time.h>
|
|
34
|
+
|
|
35
|
+
#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
|
|
36
|
+
#include <io.h>
|
|
37
|
+
#else
|
|
38
|
+
#include <fcntl.h>
|
|
39
|
+
#include <sys/param.h>
|
|
40
|
+
#include <sys/stat.h>
|
|
41
|
+
#include <sys/time.h>
|
|
42
|
+
#include <sys/types.h>
|
|
43
|
+
#include <unistd.h>
|
|
44
|
+
#endif
|
|
45
|
+
|
|
46
|
+
#ifdef _BSD_SOURCE
|
|
47
|
+
#include <endian.h>
|
|
48
|
+
#endif
|
|
49
|
+
|
|
50
|
+
#include <algorithm>
|
|
51
|
+
#include <cassert>
|
|
52
|
+
#include <cinttypes> // for PRId64, PRIu64
|
|
53
|
+
#include <cstdarg>
|
|
54
|
+
#include <cstddef>
|
|
55
|
+
#include <cstdint>
|
|
56
|
+
#include <map>
|
|
57
|
+
#include <memory>
|
|
58
|
+
#include <set>
|
|
59
|
+
#include <string>
|
|
60
|
+
#include <type_traits>
|
|
61
|
+
#include <unordered_map>
|
|
62
|
+
#include <unordered_set>
|
|
63
|
+
#include <vector>
|
|
64
|
+
|
|
65
|
+
#define MDBX_INTERNAL
|
|
66
|
+
#define xMDBX_TOOLS /* Avoid using internal eASSERT() */
|
|
67
|
+
#include "../mdbx.h++"
|
|
68
|
+
#include "../src/osal.h"
|
|
69
|
+
|
|
70
|
+
#include "../src/options.h"
|
|
71
|
+
|
|
72
|
+
#ifdef _MSC_VER
|
|
73
|
+
#pragma warning(pop)
|
|
74
|
+
#pragma warning(disable : 4201) /* nonstandard extension used: nameless \
|
|
75
|
+
struct/union */
|
|
76
|
+
#pragma warning(disable : 4127) /* conditional expression is constant */
|
|
77
|
+
#if _MSC_VER < 1900
|
|
78
|
+
#pragma warning(disable : 4510) /* default constructor could \
|
|
79
|
+
not be generated */
|
|
80
|
+
#pragma warning(disable : 4512) /* assignment operator could \
|
|
81
|
+
not be generated */
|
|
82
|
+
#pragma warning(disable : 4610) /* user-defined constructor required */
|
|
83
|
+
#ifndef snprintf
|
|
84
|
+
#define snprintf(buffer, buffer_size, format, ...) _snprintf_s(buffer, buffer_size, _TRUNCATE, format, __VA_ARGS__)
|
|
85
|
+
#endif
|
|
86
|
+
#ifndef vsnprintf
|
|
87
|
+
#define vsnprintf(buffer, buffer_size, format, args) _vsnprintf_s(buffer, buffer_size, _TRUNCATE, format, args)
|
|
88
|
+
#endif
|
|
89
|
+
#pragma warning(disable : 4996) /* 'vsnprintf': This function or variable \
|
|
90
|
+
may be unsafe */
|
|
91
|
+
#endif
|
|
92
|
+
#endif /* _MSC_VER */
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru>
|
|
4
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
|
|
6
|
+
TMUX=tmux
|
|
7
|
+
DIR="$(dirname ${BASH_SOURCE[0]})"
|
|
8
|
+
TEST="${DIR}/stochastic.sh --skip-make --db-upto-gb 32"
|
|
9
|
+
PREFIX="/dev/shm/mdbxtest-"
|
|
10
|
+
|
|
11
|
+
NUMACTL="$(which numactl 2>-)"
|
|
12
|
+
NUMALIST=()
|
|
13
|
+
NUMAIDX=0
|
|
14
|
+
if [ -n "${NUMACTL}" -a $(${NUMACTL} --hardware | grep 'node [0-9]\+ cpus' | wc -l) -gt 1 ]; then
|
|
15
|
+
NUMALIST=($(${NUMACTL} --hardware | grep 'node [0-9]\+ cpus' | cut -d ' ' -f 2))
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
function test_numacycle {
|
|
19
|
+
NUMAIDX=$((NUMAIDX + 1))
|
|
20
|
+
if [ ${NUMAIDX} -ge ${#NUMALIST[@]} ]; then
|
|
21
|
+
NUMAIDX=0
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function test_numanode {
|
|
26
|
+
if [[ ${#NUMALIST[@]} > 1 ]]; then
|
|
27
|
+
echo "${TEST} --numa ${NUMALIST[$NUMAIDX]}"
|
|
28
|
+
else
|
|
29
|
+
echo "${TEST}"
|
|
30
|
+
fi
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
${TMUX} kill-session -t mdbx
|
|
34
|
+
rm -rf ${PREFIX}*
|
|
35
|
+
# git clean -x -f -d && make test-assertions
|
|
36
|
+
${TMUX} -f "${DIR}/tmux.conf" new-session -d -s mdbx htop
|
|
37
|
+
|
|
38
|
+
W=0
|
|
39
|
+
for ps in min 4k max; do
|
|
40
|
+
for from in 1 30000; do
|
|
41
|
+
for n in 0 1 2 3; do
|
|
42
|
+
CMD="$(test_numanode) --delay $((n * 7)) --page-size ${ps} --from ${from} --dir ${PREFIX}page-${ps}.from-${from}.${n}"
|
|
43
|
+
if [ $n -eq 0 ]; then
|
|
44
|
+
${TMUX} new-window -t mdbx:$((++W)) -n "page-${ps}.from-${from}" -k -d "$CMD"
|
|
45
|
+
${TMUX} select-layout -E tiled
|
|
46
|
+
else
|
|
47
|
+
${TMUX} split-window -t mdbx:$W -l 20% -d $CMD
|
|
48
|
+
fi
|
|
49
|
+
test_numacycle
|
|
50
|
+
done
|
|
51
|
+
for n in 0 1 2 3; do
|
|
52
|
+
CMD="$(test_numanode) --delay $((3 + n * 7)) --extra --page-size ${ps} --from ${from} --dir ${PREFIX}page-${ps}.from-${from}.${n}-extra"
|
|
53
|
+
if [ $n -eq 0 ]; then
|
|
54
|
+
${TMUX} new-window -t mdbx:$((++W)) -n "page-${ps}.from-${from}-extra" -k -d "$CMD"
|
|
55
|
+
${TMUX} select-layout -E tiled
|
|
56
|
+
else
|
|
57
|
+
${TMUX} split-window -t mdbx:$W -l 20% -d $CMD
|
|
58
|
+
fi
|
|
59
|
+
test_numacycle
|
|
60
|
+
done
|
|
61
|
+
done
|
|
62
|
+
done
|
|
63
|
+
|
|
64
|
+
${TMUX} attach -t mdbx
|
|
@@ -0,0 +1,118 @@
|
|
|
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
|
+
registry *registry::instance() {
|
|
7
|
+
static registry *singleton;
|
|
8
|
+
if (!singleton)
|
|
9
|
+
singleton = new registry();
|
|
10
|
+
return singleton;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
bool registry::add(const record *item) {
|
|
14
|
+
auto const singleton = instance();
|
|
15
|
+
assert(singleton->name2id.count(std::string(item->name)) == 0);
|
|
16
|
+
assert(singleton->id2record.count(item->id) == 0);
|
|
17
|
+
if (singleton->name2id.count(std::string(item->name)) + singleton->id2record.count(item->id) == 0) {
|
|
18
|
+
singleton->name2id[std::string(item->name)] = item;
|
|
19
|
+
singleton->id2record[item->id] = item;
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
testcase *registry::create_actor(const actor_config &config, const mdbx_pid_t pid) {
|
|
26
|
+
return instance()->id2record.at(config.testcase)->constructor(config, pid);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
bool registry::review_actor_params(const actor_testcase id, actor_params ¶ms, const unsigned space_id) {
|
|
30
|
+
return instance()->id2record.at(id)->review_params(params, space_id);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//-----------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
void configure_actor(unsigned &last_space_id, const actor_testcase testcase, const char *space_id_cstr,
|
|
36
|
+
actor_params params) {
|
|
37
|
+
unsigned wait4id = 0;
|
|
38
|
+
if (params.waitfor_nops) {
|
|
39
|
+
for (auto i = global::actors.rbegin(); i != global::actors.rend(); ++i) {
|
|
40
|
+
if (i->is_waitable(params.waitfor_nops)) {
|
|
41
|
+
if (i->signal_nops && i->signal_nops != params.waitfor_nops)
|
|
42
|
+
failure("Previous waitable actor (id=%u) already linked on %u-ops\n", i->actor_id, i->signal_nops);
|
|
43
|
+
wait4id = i->actor_id;
|
|
44
|
+
i->signal_nops = params.waitfor_nops;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (!wait4id)
|
|
49
|
+
failure("No previous waitable actor for %u-ops\n", params.waitfor_nops);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
unsigned long space_id = 0;
|
|
53
|
+
if (!space_id_cstr || strcmp(space_id_cstr, "auto") == 0)
|
|
54
|
+
space_id = last_space_id + 1;
|
|
55
|
+
else {
|
|
56
|
+
char *end = nullptr;
|
|
57
|
+
errno = 0;
|
|
58
|
+
space_id = strtoul(space_id_cstr, &end, 0);
|
|
59
|
+
if (errno)
|
|
60
|
+
failure_perror("Expects an integer value for space-id\n", errno);
|
|
61
|
+
if (end && *end)
|
|
62
|
+
failure("The '%s' is unexpected for space-id\n", end);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (space_id > ACTOR_ID_MAX)
|
|
66
|
+
failure("Invalid space-id %lu\n", space_id);
|
|
67
|
+
|
|
68
|
+
if (!registry::review_actor_params(testcase, params, unsigned(space_id)))
|
|
69
|
+
failure("Actor config-review failed for space-id %lu\n", space_id);
|
|
70
|
+
|
|
71
|
+
last_space_id = unsigned(space_id);
|
|
72
|
+
log_trace("configure_actor: space %lu for %s", space_id, testcase2str(testcase));
|
|
73
|
+
global::actors.emplace_back(actor_config(testcase, params, unsigned(space_id), wait4id));
|
|
74
|
+
global::databases.insert(params.pathname_db);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
void testcase_setup(const char *casename, const actor_params ¶ms, unsigned &last_space_id) {
|
|
78
|
+
if (strcmp(casename, "basic") == 0) {
|
|
79
|
+
log_notice(">>> testcase_setup(%s)", casename);
|
|
80
|
+
configure_actor(last_space_id, ac_nested, nullptr, params);
|
|
81
|
+
configure_actor(last_space_id, ac_hill, nullptr, params);
|
|
82
|
+
configure_actor(last_space_id, ac_ttl, nullptr, params);
|
|
83
|
+
configure_actor(last_space_id, ac_copy, nullptr, params);
|
|
84
|
+
configure_actor(last_space_id, ac_append, nullptr, params);
|
|
85
|
+
configure_actor(last_space_id, ac_jitter, nullptr, params);
|
|
86
|
+
configure_actor(last_space_id, ac_try, nullptr, params);
|
|
87
|
+
configure_actor(last_space_id, ac_jitter, nullptr, params);
|
|
88
|
+
configure_actor(last_space_id, ac_try, nullptr, params);
|
|
89
|
+
#if !defined(_WIN32) && !defined(_WIN64)
|
|
90
|
+
configure_actor(last_space_id, ac_forkread, nullptr, params);
|
|
91
|
+
configure_actor(last_space_id, ac_forkwrite, nullptr, params);
|
|
92
|
+
#endif /* Windows */
|
|
93
|
+
log_notice("<<< testcase_setup(%s): done", casename);
|
|
94
|
+
} else {
|
|
95
|
+
failure("unknown testcase `%s`", casename);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
void keycase_setup(const char *casename, actor_params ¶ms) {
|
|
100
|
+
if (strcmp(casename, "random") == 0 || strcmp(casename, "prng") == 0) {
|
|
101
|
+
log_notice(">>> keycase_setup(%s)", casename);
|
|
102
|
+
params.keygen.keycase = kc_random;
|
|
103
|
+
// TODO
|
|
104
|
+
log_notice("<<< keycase_setup(%s): done", casename);
|
|
105
|
+
} else if (strcmp(casename, "dashes") == 0 || strcmp(casename, "aside") == 0) {
|
|
106
|
+
log_notice(">>> keycase_setup(%s)", casename);
|
|
107
|
+
params.keygen.keycase = kc_dashes;
|
|
108
|
+
// TODO
|
|
109
|
+
log_notice("<<< keycase_setup(%s): done", casename);
|
|
110
|
+
} else if (strcmp(casename, "custom") == 0) {
|
|
111
|
+
log_notice("=== keycase_setup(%s): skip", casename);
|
|
112
|
+
params.keygen.keycase = kc_custom;
|
|
113
|
+
} else {
|
|
114
|
+
failure("unknown keycase `%s`", casename);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* TODO */
|
|
@@ -0,0 +1,134 @@
|
|
|
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
|
+
namespace chrono {
|
|
7
|
+
|
|
8
|
+
#ifndef NSEC_PER_SEC
|
|
9
|
+
#define NSEC_PER_SEC 1000000000u
|
|
10
|
+
#endif /* NSEC_PER_SEC */
|
|
11
|
+
|
|
12
|
+
uint32_t ns2fractional(uint32_t ns) {
|
|
13
|
+
assert(ns < NSEC_PER_SEC);
|
|
14
|
+
/* LY: здесь и далее используется "длинное деление", которое
|
|
15
|
+
* для ясности кода оставлено как есть (без ручной оптимизации). Так как
|
|
16
|
+
* GCC, Clang и даже MSVC сами давно умеют конвертировать деление на
|
|
17
|
+
* константу в быструю reciprocal-форму. */
|
|
18
|
+
return uint32_t((uint64_t(ns) << 32) / NSEC_PER_SEC);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
uint32_t fractional2ns(uint32_t fractional) { return uint32_t((fractional * uint64_t(NSEC_PER_SEC)) >> 32); }
|
|
22
|
+
|
|
23
|
+
#ifndef USEC_PER_SEC
|
|
24
|
+
#define USEC_PER_SEC 1000000u
|
|
25
|
+
#endif /* USEC_PER_SEC */
|
|
26
|
+
uint32_t us2fractional(uint32_t us) {
|
|
27
|
+
assert(us < USEC_PER_SEC);
|
|
28
|
+
return uint32_t((uint64_t(us) << 32) / USEC_PER_SEC);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
uint32_t fractional2us(uint32_t fractional) {
|
|
32
|
+
#if !(defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64))
|
|
33
|
+
/* Смеяться или плакать, но все существующие на май 2024 компиляторы Microsoft
|
|
34
|
+
* для ARM/ARM64, уже порядка 10 лет, падают на этом коде из-за внтутренней
|
|
35
|
+
* ошибке (aka ICE). */
|
|
36
|
+
return uint32_t((fractional * uint64_t(USEC_PER_SEC)) >> 32);
|
|
37
|
+
#else
|
|
38
|
+
static_assert(USEC_PER_SEC % 16 == 0, "WTF?");
|
|
39
|
+
/* Crutch for MSVC ARM/ARM64 compilers to avoid internal compiler error. */
|
|
40
|
+
return UInt32x32To64(fractional, USEC_PER_SEC / 16) >> 28;
|
|
41
|
+
#endif
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#ifndef MSEC_PER_SEC
|
|
45
|
+
#define MSEC_PER_SEC 1000u
|
|
46
|
+
#endif /* MSEC_PER_SEC */
|
|
47
|
+
uint32_t ms2fractional(uint32_t ms) {
|
|
48
|
+
assert(ms < MSEC_PER_SEC);
|
|
49
|
+
return uint32_t((uint64_t(ms) << 32) / MSEC_PER_SEC);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
uint32_t fractional2ms(uint32_t fractional) { return uint32_t((fractional * uint64_t(MSEC_PER_SEC)) >> 32); }
|
|
53
|
+
|
|
54
|
+
time from_ns(uint64_t ns) {
|
|
55
|
+
time result;
|
|
56
|
+
result.fixedpoint = ((ns / NSEC_PER_SEC) << 32) | ns2fractional(uint32_t(ns % NSEC_PER_SEC));
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
time from_us(uint64_t us) {
|
|
61
|
+
time result;
|
|
62
|
+
result.fixedpoint = ((us / USEC_PER_SEC) << 32) | us2fractional(uint32_t(us % USEC_PER_SEC));
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
time from_ms(uint64_t ms) {
|
|
67
|
+
time result;
|
|
68
|
+
result.fixedpoint = ((ms / MSEC_PER_SEC) << 32) | ms2fractional(uint32_t(ms % MSEC_PER_SEC));
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
#if __GNUC_PREREQ(8, 0) && (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__))
|
|
73
|
+
#pragma GCC diagnostic push
|
|
74
|
+
#pragma GCC diagnostic ignored "-Wcast-function-type"
|
|
75
|
+
#endif /* GCC/MINGW */
|
|
76
|
+
|
|
77
|
+
time now_realtime() {
|
|
78
|
+
#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
|
|
79
|
+
static void(WINAPI * query_time)(LPFILETIME);
|
|
80
|
+
if (unlikely(!query_time)) {
|
|
81
|
+
HMODULE hModule = GetModuleHandle(TEXT("kernel32.dll"));
|
|
82
|
+
if (hModule)
|
|
83
|
+
query_time = (void(WINAPI *)(LPFILETIME))GetProcAddress(hModule, "GetSystemTimePreciseAsFileTime");
|
|
84
|
+
if (!query_time)
|
|
85
|
+
query_time = GetSystemTimeAsFileTime;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
FILETIME filetime;
|
|
89
|
+
query_time(&filetime);
|
|
90
|
+
uint64_t ns100 = (uint64_t)filetime.dwHighDateTime << 32 | filetime.dwLowDateTime;
|
|
91
|
+
return from_ns((ns100 - UINT64_C(116444736000000000)) * 100u);
|
|
92
|
+
#else
|
|
93
|
+
struct timespec ts;
|
|
94
|
+
if (unlikely(clock_gettime(CLOCK_REALTIME, &ts)))
|
|
95
|
+
failure_perror("clock_gettime(CLOCK_REALTIME", errno);
|
|
96
|
+
|
|
97
|
+
return from_timespec(ts);
|
|
98
|
+
#endif
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
time now_monotonic() {
|
|
102
|
+
#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
|
|
103
|
+
static uint64_t reciprocal;
|
|
104
|
+
static LARGE_INTEGER Frequency;
|
|
105
|
+
if (reciprocal == 0) {
|
|
106
|
+
if (!QueryPerformanceFrequency(&Frequency))
|
|
107
|
+
failure_perror("QueryPerformanceFrequency()", GetLastError());
|
|
108
|
+
reciprocal = (((UINT64_C(1) << 48) + Frequency.QuadPart / 2 + 1) / Frequency.QuadPart);
|
|
109
|
+
assert(reciprocal);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
LARGE_INTEGER Counter;
|
|
113
|
+
if (!QueryPerformanceCounter(&Counter))
|
|
114
|
+
failure_perror("QueryPerformanceCounter()", GetLastError());
|
|
115
|
+
|
|
116
|
+
time result;
|
|
117
|
+
result.fixedpoint = (Counter.QuadPart / Frequency.QuadPart) << 32;
|
|
118
|
+
uint64_t mod = Counter.QuadPart % Frequency.QuadPart;
|
|
119
|
+
result.fixedpoint += (mod * reciprocal) >> 16;
|
|
120
|
+
return result;
|
|
121
|
+
#else
|
|
122
|
+
struct timespec ts;
|
|
123
|
+
if (unlikely(clock_gettime(CLOCK_MONOTONIC, &ts)))
|
|
124
|
+
failure_perror("clock_gettime(CLOCK_MONOTONIC)", errno);
|
|
125
|
+
|
|
126
|
+
return from_timespec(ts);
|
|
127
|
+
#endif
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#if __GNUC_PREREQ(8, 0) && (defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__))
|
|
131
|
+
#pragma GCC diagnostic pop
|
|
132
|
+
#endif /* GCC/MINGW */
|
|
133
|
+
|
|
134
|
+
} /* namespace chrono */
|