diff options
author | George Hazan <ghazan@miranda.im> | 2019-06-23 12:11:35 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2019-06-23 12:11:35 +0300 |
commit | ede0e5088aa37d1ef710a7bf74ccead5140c9117 (patch) | |
tree | 984ec1470c0c83653e8871953b4b39806fee2b99 /libs/libmdbx/src/test | |
parent | 3632205b947823fa049e91b86a5611e9bbb59673 (diff) |
libmdbx: merge
Diffstat (limited to 'libs/libmdbx/src/test')
-rw-r--r-- | libs/libmdbx/src/test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | libs/libmdbx/src/test/append.cc | 29 | ||||
-rw-r--r-- | libs/libmdbx/src/test/cases.cc | 1 | ||||
-rw-r--r-- | libs/libmdbx/src/test/config.h | 3 | ||||
-rw-r--r-- | libs/libmdbx/src/test/gc.sh | 6 | ||||
-rw-r--r-- | libs/libmdbx/src/test/keygen.cc | 4 | ||||
-rw-r--r-- | libs/libmdbx/src/test/keygen.h | 4 | ||||
-rw-r--r-- | libs/libmdbx/src/test/main.cc | 11 | ||||
-rw-r--r-- | libs/libmdbx/src/test/test.cc | 53 | ||||
-rw-r--r-- | libs/libmdbx/src/test/test.h | 8 | ||||
-rw-r--r-- | libs/libmdbx/src/test/test.vcxproj | 1 | ||||
-rw-r--r-- | libs/libmdbx/src/test/ttl.cc | 137 | ||||
-rw-r--r-- | libs/libmdbx/src/test/utils.cc | 15 | ||||
-rw-r--r-- | libs/libmdbx/src/test/utils.h | 57 |
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 ¶ms, 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); |