diff --git a/test/config.cc b/test/config.cc index 2142eb26..5e197971 100644 --- a/test/config.cc +++ b/test/config.cc @@ -395,6 +395,8 @@ void dump(const char *title) { i->params.keygen.split, i->params.keygen.width - i->params.keygen.split); log_verbose("keygen.seed: %u\n", i->params.keygen.seed); + log_verbose("keygen.zerofill: %s\n", + i->params.keygen.zero_fill ? "Yes" : "No"); log_verbose("key: minlen %u, maxlen %u\n", i->params.keylen_min, i->params.keylen_max); log_verbose("data: minlen %u, maxlen %u\n", i->params.datalen_min, diff --git a/test/config.h b/test/config.h index e7f7a55c..30106545 100644 --- a/test/config.h +++ b/test/config.h @@ -231,6 +231,7 @@ struct keygen_params_pod { uint32_t seed{0}; uint64_t offset{0}; keygen_case keycase{kc_random}; + bool zero_fill{false}; }; struct actor_params_pod { diff --git a/test/keygen.cc b/test/keygen.cc index 374537dd..05070afe 100644 --- a/test/keygen.cc +++ b/test/keygen.cc @@ -78,9 +78,11 @@ void __hot maker::pair(serial_t serial, const buffer &key, buffer &value, assert(mapping.mesh <= mapping.width); assert(mapping.rotate <= mapping.width); assert(mapping.offset <= mask(mapping.width)); - assert(!(key_essentials.flags & - ~(MDBX_INTEGERKEY | MDBX_REVERSEKEY | MDBX_DUPSORT))); - assert(!(value_essentials.flags & ~(MDBX_INTEGERDUP | MDBX_REVERSEDUP))); + assert( + !(key_essentials.flags & ~(essentials::prng_fill_flag | MDBX_INTEGERKEY | + MDBX_REVERSEKEY | MDBX_DUPSORT))); + assert(!(value_essentials.flags & + ~(essentials::prng_fill_flag | MDBX_INTEGERDUP | MDBX_REVERSEDUP))); log_trace("keygen-pair: serial %" PRIu64 ", data-age %" PRIu64, serial, value_age); @@ -213,6 +215,11 @@ void maker::setup(const config::actor_params_pod &actor, unsigned actor_id, (uint32_t)actor.datalen_max, (uint32_t)mdbx_limits_valsize_max(actor.pagesize, key_essentials.flags)); + if (!actor.keygen.zero_fill) { + key_essentials.flags |= essentials::prng_fill_flag; + value_essentials.flags |= essentials::prng_fill_flag; + } + (void)thread_number; mapping = actor.keygen; salt = (actor.keygen.seed + actor_id) * UINT64_C(14653293970879851569); @@ -298,6 +305,10 @@ void __hot maker::mk_begin(const serial_t serial, const essentials ¶ms, void __hot maker::mk_continue(const serial_t serial, const essentials ¶ms, result &out) { + static_assert((essentials::prng_fill_flag & + (MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERKEY | + MDBX_INTEGERDUP | MDBX_REVERSEKEY | MDBX_REVERSEDUP)) == 0, + "WTF?"); out.value.iov_base = out.bytes; if (params.flags & (MDBX_INTEGERKEY | MDBX_INTEGERDUP)) { assert(params.maxlen == params.minlen); @@ -308,7 +319,11 @@ void __hot maker::mk_continue(const serial_t serial, const essentials ¶ms, out.u32 = (uint32_t)serial; } else if (params.flags & (MDBX_REVERSEKEY | MDBX_REVERSEDUP)) { if (out.value.iov_len > 8) { - memset(out.bytes, '\0', out.value.iov_len - 8); + if (params.flags & essentials::prng_fill_flag) { + uint64_t state = serial ^ UINT64_C(0x41803711c9b75f19); + prng_fill(state, out.bytes, out.value.iov_len - 8); + } else + memset(out.bytes, '\0', out.value.iov_len - 8); unaligned::store(out.bytes + out.value.iov_len - 8, htobe64(serial)); } else { out.u64 = htobe64(serial); @@ -317,8 +332,13 @@ void __hot maker::mk_continue(const serial_t serial, const essentials ¶ms, } } else { out.u64 = htole64(serial); - if (out.value.iov_len > 8) - memset(out.bytes + 8, '\0', out.value.iov_len - 8); + if (out.value.iov_len > 8) { + if (params.flags & essentials::prng_fill_flag) { + uint64_t state = serial ^ UINT64_C(0x923ab47b7ee6f6e4); + prng_fill(state, out.bytes + 8, out.value.iov_len - 8); + } else + memset(out.bytes + 8, '\0', out.value.iov_len - 8); + } } assert(out.value.iov_len >= params.minlen); diff --git a/test/keygen.h b/test/keygen.h index 052fc7ef..8b251f85 100644 --- a/test/keygen.h +++ b/test/keygen.h @@ -108,6 +108,7 @@ class maker { struct essentials { uint16_t minlen{0}; + enum { prng_fill_flag = 1 }; uint16_t flags{0}; uint32_t maxlen{0}; } key_essentials, value_essentials; diff --git a/test/main.cc b/test/main.cc index fdd59e29..0806914e 100644 --- a/test/main.cc +++ b/test/main.cc @@ -81,6 +81,7 @@ void __noreturn usage(void) { " --keygen.width=N TBD (see the source code)\n" " --keygen.mesh=N TBD (see the source code)\n" " --keygen.seed=N TBD (see the source code)\n" + " --keygen.zerofill=yes|NO TBD (see the source code)\n" " --keygen.split=N TBD (see the source code)\n" " --keygen.rotate=N TBD (see the source code)\n" " --keygen.offset=N TBD (see the source code)\n" @@ -136,6 +137,7 @@ void actor_params::set_defaults(const std::string &tmpdir) { pagesize = -1; keygen.seed = 1; + keygen.zero_fill = false; keygen.keycase = kc_random; keygen.width = (table_flags & MDBX_DUPSORT) ? 32 : 64; keygen.mesh = keygen.width; @@ -329,6 +331,9 @@ int main(int argc, char *const argv[]) { if (config::parse_option(argc, argv, narg, "keygen.seed", params.keygen.seed, config::no_scale)) continue; + if (config::parse_option(argc, argv, narg, "keygen.zerofill", + params.keygen.zero_fill)) + continue; if (config::parse_option(argc, argv, narg, "keygen.split", params.keygen.split, 1, 64)) continue; diff --git a/test/utils.cc b/test/utils.cc index 596e66e3..051671ff 100644 --- a/test/utils.cc +++ b/test/utils.cc @@ -265,22 +265,24 @@ uint32_t prng32(uint64_t &state) { } void prng_fill(uint64_t &state, void *ptr, size_t bytes) { + uint32_t u32 = prng32(state); + while (bytes >= 4) { - *((uint32_t *)ptr) = prng32(state); + memcpy(ptr, &u32, 4); ptr = (uint32_t *)ptr + 1; bytes -= 4; + u32 = prng32(state); } switch (bytes & 3) { - case 3: { - uint32_t u32 = prng32(state); + case 3: memcpy(ptr, &u32, 3); - } break; + break; case 2: - *((uint16_t *)ptr) = (uint16_t)prng32(state); + memcpy(ptr, &u32, 2); break; case 1: - *((uint8_t *)ptr) = (uint8_t)prng32(state); + memcpy(ptr, &u32, 1); break; case 0: break;