summaryrefslogtreecommitdiff
path: root/libs/libmdbx/src/test
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-06-23 12:11:35 +0300
committerGeorge Hazan <ghazan@miranda.im>2019-06-23 12:11:35 +0300
commitede0e5088aa37d1ef710a7bf74ccead5140c9117 (patch)
tree984ec1470c0c83653e8871953b4b39806fee2b99 /libs/libmdbx/src/test
parent3632205b947823fa049e91b86a5611e9bbb59673 (diff)
libmdbx: merge
Diffstat (limited to 'libs/libmdbx/src/test')
-rw-r--r--libs/libmdbx/src/test/CMakeLists.txt1
-rw-r--r--libs/libmdbx/src/test/append.cc29
-rw-r--r--libs/libmdbx/src/test/cases.cc1
-rw-r--r--libs/libmdbx/src/test/config.h3
-rw-r--r--libs/libmdbx/src/test/gc.sh6
-rw-r--r--libs/libmdbx/src/test/keygen.cc4
-rw-r--r--libs/libmdbx/src/test/keygen.h4
-rw-r--r--libs/libmdbx/src/test/main.cc11
-rw-r--r--libs/libmdbx/src/test/test.cc53
-rw-r--r--libs/libmdbx/src/test/test.h8
-rw-r--r--libs/libmdbx/src/test/test.vcxproj1
-rw-r--r--libs/libmdbx/src/test/ttl.cc137
-rw-r--r--libs/libmdbx/src/test/utils.cc15
-rw-r--r--libs/libmdbx/src/test/utils.h57
14 files changed, 276 insertions, 54 deletions
diff --git a/libs/libmdbx/src/test/CMakeLists.txt b/libs/libmdbx/src/test/CMakeLists.txt
index 88fd09e01b..bb4abd5d6d 100644
--- a/libs/libmdbx/src/test/CMakeLists.txt
+++ b/libs/libmdbx/src/test/CMakeLists.txt
@@ -28,6 +28,7 @@ add_executable(${TARGET}
utils.cc
utils.h
append.cc
+ ttl.cc
)
target_link_libraries(${TARGET}
diff --git a/libs/libmdbx/src/test/append.cc b/libs/libmdbx/src/test/append.cc
index 3ce53eb292..c5e7e91d9e 100644
--- a/libs/libmdbx/src/test/append.cc
+++ b/libs/libmdbx/src/test/append.cc
@@ -19,9 +19,7 @@ bool testcase_append::run() {
txn_begin(false);
MDBX_dbi dbi = db_table_open(true);
- int rc = mdbx_drop(txn_guard.get(), dbi, false);
- if (unlikely(rc != MDBX_SUCCESS))
- failure_perror("mdbx_drop(delete=false)", rc);
+ db_table_clear(dbi);
keyvalue_maker.setup(config.params, config.actor_id, 0 /* thread_number */);
/* LY: тест наполнения таблиц в append-режиме,
@@ -59,10 +57,10 @@ bool testcase_append::run() {
if (cmp == 0 && (config.params.table_flags & MDBX_DUPSORT))
cmp = mdbx_dcmp(txn_guard.get(), dbi, &data->value, &last_data->value);
- rc = mdbx_put(txn_guard.get(), dbi, &key->value, &data->value, flags);
+ int err = mdbx_put(txn_guard.get(), dbi, &key->value, &data->value, flags);
if (cmp > 0) {
- if (unlikely(rc != MDBX_SUCCESS))
- failure_perror("mdbx_put(appenda-a)", rc);
+ if (unlikely(err != MDBX_SUCCESS))
+ failure_perror("mdbx_put(appenda-a)", err);
memcpy(last_key->value.iov_base, key->value.iov_base,
last_key->value.iov_len = key->value.iov_len);
memcpy(last_data->value.iov_base, data->value.iov_base,
@@ -71,8 +69,8 @@ bool testcase_append::run() {
inserted_checksum.push((uint32_t)inserted_number, key->value);
inserted_checksum.push(10639, data->value);
} else {
- if (unlikely(rc != MDBX_EKEYMISMATCH))
- failure_perror("mdbx_put(appenda-a) != MDBX_EKEYMISMATCH", rc);
+ if (unlikely(err != MDBX_EKEYMISMATCH))
+ failure_perror("mdbx_put(appenda-a) != MDBX_EKEYMISMATCH", err);
}
if (++txn_nops >= config.params.batch_write) {
@@ -88,23 +86,24 @@ bool testcase_append::run() {
cursor_open(dbi);
MDBX_val check_key, check_data;
- rc = mdbx_cursor_get(cursor_guard.get(), &check_key, &check_data, MDBX_FIRST);
- if (unlikely(rc != MDBX_SUCCESS))
- failure_perror("mdbx_cursor_get(MDBX_FIRST)", rc);
+ int err =
+ mdbx_cursor_get(cursor_guard.get(), &check_key, &check_data, MDBX_FIRST);
+ if (unlikely(err != MDBX_SUCCESS))
+ failure_perror("mdbx_cursor_get(MDBX_FIRST)", err);
simple_checksum read_checksum;
uint64_t read_count = 0;
- while (rc == MDBX_SUCCESS) {
+ while (err == MDBX_SUCCESS) {
++read_count;
read_checksum.push((uint32_t)read_count, check_key);
read_checksum.push(10639, check_data);
- rc =
+ err =
mdbx_cursor_get(cursor_guard.get(), &check_key, &check_data, MDBX_NEXT);
}
- if (unlikely(rc != MDBX_NOTFOUND))
- failure_perror("mdbx_cursor_get(MDBX_NEXT) != EOF", rc);
+ if (unlikely(err != MDBX_NOTFOUND))
+ failure_perror("mdbx_cursor_get(MDBX_NEXT) != EOF", err);
if (unlikely(read_count != inserted_number))
failure("read_count(%" PRIu64 ") != inserted_number(%" PRIu64 ")",
diff --git a/libs/libmdbx/src/test/cases.cc b/libs/libmdbx/src/test/cases.cc
index 1d41efc82b..023a80020c 100644
--- a/libs/libmdbx/src/test/cases.cc
+++ b/libs/libmdbx/src/test/cases.cc
@@ -67,6 +67,7 @@ void testcase_setup(const char *casename, actor_params &params,
configure_actor(last_space_id, ac_hill, nullptr, params);
configure_actor(last_space_id, ac_jitter, nullptr, params);
configure_actor(last_space_id, ac_hill, nullptr, params);
+ configure_actor(last_space_id, ac_ttl, nullptr, params);
configure_actor(last_space_id, ac_try, nullptr, params);
configure_actor(last_space_id, ac_copy, nullptr, params);
configure_actor(last_space_id, ac_append, nullptr, params);
diff --git a/libs/libmdbx/src/test/config.h b/libs/libmdbx/src/test/config.h
index d6eaea2e54..b8a4b6827d 100644
--- a/libs/libmdbx/src/test/config.h
+++ b/libs/libmdbx/src/test/config.h
@@ -28,7 +28,8 @@ enum actor_testcase {
ac_jitter,
ac_try,
ac_copy,
- ac_append
+ ac_append,
+ ac_ttl
};
enum actor_status {
diff --git a/libs/libmdbx/src/test/gc.sh b/libs/libmdbx/src/test/gc.sh
index 76c7a9a51c..9c1407f53e 100644
--- a/libs/libmdbx/src/test/gc.sh
+++ b/libs/libmdbx/src/test/gc.sh
@@ -23,9 +23,9 @@ function probe {
echo "=============================================== $(date)"
echo "${caption}: $*"
rm -f ${TESTDB_PREFIX}* \
- && ./mdbx_test --pathname=${TESTDB_PREFIX}db "$@" | lz4 > ${TESTDB_PREFIX}log.lz4 \
+ && ./mdbx_test --repeat=12 --pathname=${TESTDB_PREFIX}db "$@" | lz4 > ${TESTDB_PREFIX}log.lz4 \
&& ./mdbx_chk -nvvv ${TESTDB_PREFIX}db | tee ${TESTDB_PREFIX}chk \
- && ./mdbx_chk -nvvv ${TESTDB_PREFIX}db-copy | tee ${TESTDB_PREFIX}chk-copy \
+ && ([ ! -e ${TESTDB_PREFIX}db-copy ] || ./mdbx_chk -nvvv ${TESTDB_PREFIX}db-copy | tee ${TESTDB_PREFIX}chk-copy) \
|| (echo "FAILED"; exit 1)
}
@@ -34,7 +34,7 @@ function probe {
count=0
for nops in {2..7}; do
for ((wbatch=nops-1; wbatch > 0; --wbatch)); do
- loops=$(((3333 >> nops) / nops + 1))
+ loops=$(((333 >> nops) / nops + 3))
for ((rep=0; rep++ < loops; )); do
for ((bits=2**${#options[@]}; --bits >= 0; )); do
seed=$(date +%N)
diff --git a/libs/libmdbx/src/test/keygen.cc b/libs/libmdbx/src/test/keygen.cc
index 5876fd8cec..30cdf7a571 100644
--- a/libs/libmdbx/src/test/keygen.cc
+++ b/libs/libmdbx/src/test/keygen.cc
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
@@ -176,7 +176,7 @@ bool maker::is_unordered() const {
return (mapping.mesh >= serial_minwith || mapping.rotate) != 0;
}
-bool maker::increment(serial_t &serial, int delta) {
+bool maker::increment(serial_t &serial, int delta) const {
if (serial > mask(mapping.width)) {
log_extra("keygen-increment: %" PRIu64 " > %" PRIu64 ", overflow", serial,
mask(mapping.width));
diff --git a/libs/libmdbx/src/test/keygen.h b/libs/libmdbx/src/test/keygen.h
index 890397b8ca..d0299e1e7d 100644
--- a/libs/libmdbx/src/test/keygen.h
+++ b/libs/libmdbx/src/test/keygen.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
@@ -124,7 +124,7 @@ public:
void make_ordered();
bool is_unordered() const;
- bool increment(serial_t &serial, int delta);
+ bool increment(serial_t &serial, int delta) const;
};
} /* namespace keygen */
diff --git a/libs/libmdbx/src/test/main.cc b/libs/libmdbx/src/test/main.cc
index f3ee76b62f..9dc3eccbae 100644
--- a/libs/libmdbx/src/test/main.cc
+++ b/libs/libmdbx/src/test/main.cc
@@ -37,7 +37,8 @@ void actor_params::set_defaults(const std::string &tmpdir) {
table_flags = MDBX_DUPSORT;
size_lower = -1;
- size_now = 1024 * 1024 * ((table_flags & MDBX_DUPSORT) ? 4 : 256);
+ size_now =
+ intptr_t(1024) * 1024 * ((table_flags & MDBX_DUPSORT) ? 256 : 1024);
size_upper = -1;
shrink_threshold = -1;
growth_step = -1;
@@ -61,8 +62,8 @@ void actor_params::set_defaults(const std::string &tmpdir) {
datalen_min = mdbx_datalen_min();
datalen_max = std::min(mdbx_datalen_max(), 256u * 1024 + 42);
- batch_read = 4;
- batch_write = 4;
+ batch_read = 42;
+ batch_write = 42;
delaystart = 0;
waitfor_nops = 0;
@@ -345,6 +346,10 @@ int main(int argc, char *const argv[]) {
configure_actor(last_space_id, ac_append, value, params);
continue;
}
+ if (config::parse_option(argc, argv, narg, "ttl", nullptr)) {
+ configure_actor(last_space_id, ac_ttl, value, params);
+ continue;
+ }
if (config::parse_option(argc, argv, narg, "failfast",
global::config::failfast))
continue;
diff --git a/libs/libmdbx/src/test/test.cc b/libs/libmdbx/src/test/test.cc
index e34bd7f0e8..cf61f1eeee 100644
--- a/libs/libmdbx/src/test/test.cc
+++ b/libs/libmdbx/src/test/test.cc
@@ -35,6 +35,8 @@ const char *testcase2str(const actor_testcase testcase) {
return "copy";
case ac_append:
return "append";
+ case ac_ttl:
+ return "ttl";
}
}
@@ -322,6 +324,7 @@ bool testcase::setup() {
return false;
start_timestamp = chrono::now_motonic();
+ nops_completed = 0;
return true;
}
@@ -429,6 +432,14 @@ void testcase::db_table_drop(MDBX_dbi handle) {
}
}
+void testcase::db_table_clear(MDBX_dbi handle) {
+ log_trace(">> testcase::db_table_clear, handle %u", handle);
+ int rc = mdbx_drop(txn_guard.get(), handle, false);
+ if (unlikely(rc != MDBX_SUCCESS))
+ failure_perror("mdbx_drop(delete=false)", rc);
+ log_trace("<< testcase::db_table_clear");
+}
+
void testcase::db_table_close(MDBX_dbi handle) {
log_trace(">> testcase::db_table_close, handle %u", handle);
assert(!txn_guard);
@@ -450,8 +461,9 @@ void testcase::checkdata(const char *step, MDBX_dbi handle, MDBX_val key2check,
//-----------------------------------------------------------------------------
-bool test_execute(const actor_config &config) {
+bool test_execute(const actor_config &config_const) {
const mdbx_pid_t pid = osal_getpid();
+ actor_config config = config_const;
if (global::singlemode) {
logging::setup(format("single_%s", testcase2str(config.testcase)));
@@ -487,23 +499,40 @@ bool test_execute(const actor_config &config) {
case ac_append:
test.reset(new testcase_append(config, pid));
break;
+ case ac_ttl:
+ test.reset(new testcase_ttl(config, pid));
+ break;
default:
test.reset(new testcase(config, pid));
break;
}
- if (!test->setup())
- log_notice("test setup failed");
- else if (!test->run())
- log_notice("test failed");
- else if (!test->teardown())
- log_notice("test teardown failed");
- else {
- log_info("test successed");
- return true;
- }
+ size_t iter = 0;
+ do {
+ iter++;
+ if (!test->setup()) {
+ log_notice("test setup failed");
+ return false;
+ } else if (!test->run()) {
+ log_notice("test failed");
+ return false;
+ } else if (!test->teardown()) {
+ log_notice("test teardown failed");
+ return false;
+ } else {
+ if (config.params.nrepeat == 1)
+ log_info("test successed");
+ else if (config.params.nrepeat == 1)
+ log_info("test successed (iteration %zi of %zi)", iter,
+ size_t(config.params.nrepeat));
+ else
+ log_info("test successed (iteration %zi)", iter);
+ config.params.keygen.seed += INT32_C(0xA4F4D37B);
+ }
+ } while (config.params.nrepeat == 0 || iter < config.params.nrepeat);
+ return true;
} catch (const std::exception &pipets) {
failure("***** Exception: %s *****", pipets.what());
+ return false;
}
- return false;
}
diff --git a/libs/libmdbx/src/test/test.h b/libs/libmdbx/src/test/test.h
index e726023279..117a66f93c 100644
--- a/libs/libmdbx/src/test/test.h
+++ b/libs/libmdbx/src/test/test.h
@@ -119,6 +119,7 @@ protected:
MDBX_dbi db_table_open(bool create);
void db_table_drop(MDBX_dbi handle);
+ void db_table_clear(MDBX_dbi handle);
void db_table_close(MDBX_dbi handle);
bool wait4start();
@@ -153,6 +154,13 @@ public:
virtual ~testcase() {}
};
+class testcase_ttl : public testcase {
+public:
+ testcase_ttl(const actor_config &config, const mdbx_pid_t pid)
+ : testcase(config, pid) {}
+ bool run();
+};
+
class testcase_hill : public testcase {
public:
testcase_hill(const actor_config &config, const mdbx_pid_t pid)
diff --git a/libs/libmdbx/src/test/test.vcxproj b/libs/libmdbx/src/test/test.vcxproj
index 9eb62cdcf5..93de00e3a0 100644
--- a/libs/libmdbx/src/test/test.vcxproj
+++ b/libs/libmdbx/src/test/test.vcxproj
@@ -181,6 +181,7 @@
<ClInclude Include="utils.h" />
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="ttl.cc" />
<ClCompile Include="append.cc" />
<ClCompile Include="cases.cc" />
<ClCompile Include="chrono.cc" />
diff --git a/libs/libmdbx/src/test/ttl.cc b/libs/libmdbx/src/test/ttl.cc
new file mode 100644
index 0000000000..1ecfd0c7e5
--- /dev/null
+++ b/libs/libmdbx/src/test/ttl.cc
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
+ * and other libmdbx authors: please see AUTHORS file.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include "test.h"
+#include <cmath>
+#include <deque>
+
+static unsigned edge2window(uint64_t edge, unsigned window_max) {
+ const double rnd = u64_to_double1(bleach64(edge));
+ const unsigned window = window_max - std::lrint(std::pow(window_max, rnd));
+ return window;
+}
+
+static unsigned edge2count(uint64_t edge, unsigned count_max) {
+ const double rnd = u64_to_double1(prng64_map1_white(edge));
+ const unsigned count = std::lrint(std::pow(count_max, rnd));
+ return count;
+}
+
+bool testcase_ttl::run() {
+ db_open();
+
+ txn_begin(false);
+ MDBX_dbi dbi = db_table_open(true);
+ db_table_clear(dbi);
+ txn_end(false);
+
+ /* LY: тест "эмуляцией time-to-live":
+ * - организуется "скользящее окно", которое двигается вперед вдоль
+ * числовой оси каждую транзакцию.
+ * - по переднему краю "скользящего окна" записи добавляются в таблицу,
+ * а по заднему удаляются.
+ * - количество добавляемых/удаляемых записей псевдослучайно зависит
+ * от номера транзакции, но с экспоненциальным распределением.
+ * - размер "скользящего окна" также псевдослучайно зависит от номера
+ * транзакции с "отрицательным" экспоненциальным распределением
+ * MAX_WIDTH - exp(rnd(N)), при уменьшении окна сдвигается задний
+ * край и удаляются записи позади него.
+ *
+ * Таким образом имитируется поведение таблицы с TTL: записи стохастически
+ * добавляются и удаляются, но изредка происходят массивные удаления.
+ */
+
+ /* LY: для параметризации используем подходящие параметры, которые не имеют
+ * здесь смысла в первоначальном значении */
+ const unsigned window_max =
+ (config.params.batch_read > 999) ? config.params.batch_read : 1000;
+ const unsigned count_max =
+ (config.params.batch_write > 999) ? config.params.batch_write : 1000;
+ log_info("ttl: using `batch_read` value %u for window_max", window_max);
+ log_info("ttl: using `batch_write` value %u for count_max", count_max);
+
+ uint64_t seed =
+ prng64_map2_white(config.params.keygen.seed) + config.actor_id;
+ keyvalue_maker.setup(config.params, config.actor_id, 0 /* thread_number */);
+ key = keygen::alloc(config.params.keylen_max);
+ data = keygen::alloc(config.params.datalen_max);
+ const unsigned insert_flags = (config.params.table_flags & MDBX_DUPSORT)
+ ? MDBX_NODUPDATA
+ : MDBX_NODUPDATA | MDBX_NOOVERWRITE;
+
+ std::deque<std::pair<uint64_t, unsigned>> fifo;
+ uint64_t serial = 0;
+ while (should_continue()) {
+ if (!txn_guard)
+ txn_begin(false);
+ const uint64_t salt = prng64_white(seed) /* mdbx_txn_id(txn_guard.get()) */;
+
+ const unsigned window_width = edge2window(salt, window_max);
+ const unsigned head_count = edge2count(salt, count_max);
+ log_info("ttl: step #%zu (serial %" PRIu64
+ ", window %u, count %u) salt %" PRIu64,
+ nops_completed, serial, window_width, head_count, salt);
+
+ if (window_width) {
+ while (fifo.size() > window_width) {
+ uint64_t tail_serial = fifo.back().first;
+ const unsigned tail_count = fifo.back().second;
+ log_trace("ttl: pop-tail (serial %" PRIu64 ", count %u)", tail_serial,
+ tail_count);
+ fifo.pop_back();
+ for (unsigned n = 0; n < tail_count; ++n) {
+ log_trace("ttl: remove-tail %" PRIu64, serial);
+ generate_pair(tail_serial);
+ int err = mdbx_del(txn_guard.get(), dbi, &key->value, &data->value);
+ if (unlikely(err != MDBX_SUCCESS))
+ failure_perror("mdbx_del(tail)", err);
+ if (unlikely(!keyvalue_maker.increment(tail_serial, 1)))
+ failure("ttl: unexpected key-space overflow on the tail");
+ }
+ }
+ } else {
+ log_trace("ttl: purge state");
+ db_table_clear(dbi);
+ fifo.clear();
+ }
+
+ txn_restart(false, false);
+ fifo.push_front(std::make_pair(serial, head_count));
+
+ for (unsigned n = 0; n < head_count; ++n) {
+ log_trace("ttl: insert-head %" PRIu64, serial);
+ generate_pair(serial);
+ int err = mdbx_put(txn_guard.get(), dbi, &key->value, &data->value,
+ insert_flags);
+ if (unlikely(err != MDBX_SUCCESS))
+ failure_perror("mdbx_put(head)", err);
+
+ if (unlikely(!keyvalue_maker.increment(serial, 1)))
+ failure("uphill: unexpected key-space overflow");
+ }
+
+ txn_end(false);
+ report(1);
+ }
+
+ if (dbi) {
+ if (config.params.drop_table && !mode_readonly()) {
+ txn_begin(false);
+ db_table_drop(dbi);
+ txn_end(false);
+ } else
+ db_table_close(dbi);
+ }
+ return true;
+}
diff --git a/libs/libmdbx/src/test/utils.cc b/libs/libmdbx/src/test/utils.cc
index 326455a693..ddf47a4cd9 100644
--- a/libs/libmdbx/src/test/utils.cc
+++ b/libs/libmdbx/src/test/utils.cc
@@ -252,21 +252,8 @@ uint64_t entropy_ticks(void) {
//-----------------------------------------------------------------------------
-static __inline uint64_t bleach64(uint64_t dirty) {
- return mul_64x64_high(bswap64(dirty), UINT64_C(17048867929148541611));
-}
-
-static __inline uint32_t bleach32(uint32_t dirty) {
- return (uint32_t)((bswap32(dirty) * UINT64_C(2175734609)) >> 32);
-}
-
-uint64_t prng64_careless(uint64_t &state) {
- state = state * UINT64_C(6364136223846793005) + 1;
- return state;
-}
-
uint64_t prng64_white(uint64_t &state) {
- state = state * UINT64_C(6364136223846793005) + UINT64_C(1442695040888963407);
+ state = prng64_map2_careless(state);
return bleach64(state);
}
diff --git a/libs/libmdbx/src/test/utils.h b/libs/libmdbx/src/test/utils.h
index 7bf3abd305..efda8394fc 100644
--- a/libs/libmdbx/src/test/utils.h
+++ b/libs/libmdbx/src/test/utils.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
@@ -327,7 +327,60 @@ std::string format(const char *fmt, ...);
uint64_t entropy_ticks(void);
uint64_t entropy_white(void);
-uint64_t prng64_careless(uint64_t &state);
+static inline uint64_t bleach64(uint64_t v) {
+ // Tommy Ettinger, https://www.blogger.com/profile/04953541827437796598
+ // http://mostlymangling.blogspot.com/2019/01/better-stronger-mixer-and-test-procedure.html
+ v ^= rot64(v, 25) ^ rot64(v, 50);
+ v *= UINT64_C(0xA24BAED4963EE407);
+ v ^= rot64(v, 24) ^ rot64(v, 49);
+ v *= UINT64_C(0x9FB21C651E98DF25);
+ return v ^ v >> 28;
+}
+
+static inline uint32_t bleach32(uint32_t x) {
+ // https://github.com/skeeto/hash-prospector
+ // exact bias: 0.17353355999581582
+ x ^= x >> 16;
+ x *= UINT32_C(0x7feb352d);
+ x ^= 0x3027C563 ^ (x >> 15);
+ x *= UINT32_C(0x846ca68b);
+ x ^= x >> 16;
+ return x;
+}
+
+static inline uint64_t prng64_map1_careless(uint64_t state) {
+ return state * UINT64_C(6364136223846793005) + 1;
+}
+
+static inline uint64_t prng64_map2_careless(uint64_t state) {
+ return (state + UINT64_C(1442695040888963407)) *
+ UINT64_C(6364136223846793005);
+}
+
+static inline uint64_t prng64_map1_white(uint64_t state) {
+ return bleach64(prng64_map1_careless(state));
+}
+
+static inline uint64_t prng64_map2_white(uint64_t state) {
+ return bleach64(prng64_map2_careless(state));
+}
+
+static inline uint64_t prng64_careless(uint64_t &state) {
+ state = prng64_map1_careless(state);
+ return state;
+}
+
+static inline double u64_to_double1(uint64_t v) {
+ union {
+ uint64_t u64;
+ double d;
+ } casting;
+
+ casting.u64 = UINT64_C(0x3ff) << 52 | (v >> 12);
+ assert(casting.d >= 1.0 && casting.d < 2.0);
+ return casting.d - 1.0;
+}
+
uint64_t prng64_white(uint64_t &state);
uint32_t prng32(uint64_t &state);
void prng_fill(uint64_t &state, void *ptr, size_t bytes);