mdbx: move key generator linearization into actor::review_params().

Change-Id: I35492f64b6b5eae9702d26f3e0ba9df31f57a4af
This commit is contained in:
Leonid Yuriev 2021-03-16 02:44:28 +03:00
parent f4781b63a8
commit ecc755881e
5 changed files with 60 additions and 63 deletions

View File

@ -21,7 +21,7 @@ public:
bool run() override;
static bool review_params(actor_params &params) {
return testcase::review_params(params);
return testcase::review_params(params) && params.make_keygen_linear();
}
};
REGISTER_TESTCASE(append);
@ -41,7 +41,6 @@ bool testcase_append::run() {
(config.params.table_flags & MDBX_DUPSORT)
? (flipcoin() ? MDBX_APPEND | MDBX_APPENDDUP : MDBX_APPENDDUP)
: MDBX_APPEND;
keyvalue_maker.make_linear();
key = keygen::alloc(config.params.keylen_max);
data = keygen::alloc(config.params.datalen_max);

View File

@ -623,3 +623,36 @@ unsigned actor_params::mdbx_datalen_max() const {
return std::min(unsigned(UINT16_MAX),
unsigned(mdbx_limits_valsize_max(pagesize, table_flags)));
}
bool actor_params::make_keygen_linear() {
const auto base = serial_base();
keygen.mesh = (table_flags & MDBX_DUPSORT) ? 0 : keygen.split;
keygen.rotate = 0;
keygen.offset = 0;
const auto max_serial = serial_mask(keygen.width) + base;
const auto max_key_serial = (keygen.split && (table_flags & MDBX_DUPSORT))
? max_serial >> keygen.split
: max_serial;
const auto max_value_serial = (keygen.split && (table_flags & MDBX_DUPSORT))
? serial_mask(keygen.split)
: 0;
while (keylen_min < 8 &&
(keylen_min == 0 || serial_mask(keylen_min * 8) < max_key_serial)) {
keylen_min += (table_flags & (MDBX_INTEGERKEY | MDBX_INTEGERDUP)) ? 4 : 1;
if (keylen_max < keylen_min)
keylen_max = keylen_min;
}
if (table_flags & MDBX_DUPSORT)
while (
datalen_min < 8 &&
(datalen_min == 0 || serial_mask(datalen_min * 8) < max_value_serial)) {
datalen_min +=
(table_flags & (MDBX_INTEGERKEY | MDBX_INTEGERDUP)) ? 4 : 1;
if (datalen_max < datalen_min)
datalen_max = datalen_min;
}
return true;
}

View File

@ -283,6 +283,15 @@ struct actor_params_pod {
bool ignore_dbfull{false};
bool speculum{false};
bool random_writemap{true};
uint64_t serial_base() const {
// FIXME: TODO
return 0;
}
static MDBX_PURE_FUNCTION uint64_t serial_mask(unsigned bits) {
assert(bits > 0 && bits <= 64);
return (~(uint64_t)0u) >> (64 - bits);
}
};
struct actor_config_pod {
@ -312,6 +321,7 @@ struct actor_params : public config::actor_params_pod {
actor_params() = default;
void set_defaults(const std::string &tmpdir);
bool make_keygen_linear();
unsigned mdbx_keylen_min() const;
unsigned mdbx_keylen_max() const;
unsigned mdbx_datalen_min() const;

View File

@ -16,11 +16,6 @@
namespace keygen {
static inline MDBX_PURE_FUNCTION serial_t mask(unsigned bits) {
assert(bits > 0 && bits <= serial_maxwith);
return serial_allones >> (serial_maxwith - bits);
}
/* LY: https://en.wikipedia.org/wiki/Injective_function */
serial_t injective(const serial_t serial,
const unsigned bits /* at least serial_minwith (8) */,
@ -59,12 +54,13 @@ serial_t injective(const serial_t serial,
if (salt) {
const unsigned left = bits / 2;
const unsigned right = bits - left;
result = (result << left) | ((result & mask(bits)) >> right);
result = (result << left) |
((result & actor_params::serial_mask(bits)) >> right);
result = (result ^ salt) * mult;
}
result ^= result << shift;
result &= mask(bits);
result &= actor_params::serial_mask(bits);
log_trace("keygen-injective: serial %" PRIu64 "/%u @%" PRIx64 ",%u,%" PRIu64
" => %" PRIu64 "/%u",
serial, bits, mult, shift, salt, result, bits);
@ -77,7 +73,7 @@ void __hot maker::pair(serial_t serial, const buffer &key, buffer &value,
assert(mapping.split <= mapping.width);
assert(mapping.mesh <= mapping.width);
assert(mapping.rotate <= mapping.width);
assert(mapping.offset <= mask(mapping.width));
assert(mapping.offset <= actor_params::serial_mask(mapping.width));
assert(!(key_essentials.flags &
~(essentials::prng_fill_flag |
unsigned(MDBX_INTEGERKEY | MDBX_REVERSEKEY | MDBX_DUPSORT))));
@ -89,21 +85,23 @@ void __hot maker::pair(serial_t serial, const buffer &key, buffer &value,
value_age);
if (mapping.mesh >= serial_minwith) {
serial =
(serial & ~mask(mapping.mesh)) | injective(serial, mapping.mesh, salt);
serial = (serial & ~actor_params::serial_mask(mapping.mesh)) |
injective(serial, mapping.mesh, salt);
log_trace("keygen-pair: mesh@%u => %" PRIu64, mapping.mesh, serial);
}
if (mapping.rotate) {
const unsigned right = mapping.rotate;
const unsigned left = mapping.width - right;
serial = (serial << left) | ((serial & mask(mapping.width)) >> right);
serial = (serial << left) |
((serial & actor_params::serial_mask(mapping.width)) >> right);
log_trace("keygen-pair: rotate@%u => %" PRIu64 ", 0x%" PRIx64,
mapping.rotate, serial, serial);
}
if (mapping.offset) {
serial = (serial + mapping.offset) & mask(mapping.width);
serial =
(serial + mapping.offset) & actor_params::serial_mask(mapping.width);
log_trace("keygen-pair: offset@%" PRIu64 " => %" PRIu64, mapping.offset,
serial);
}
@ -117,7 +115,7 @@ void __hot maker::pair(serial_t serial, const buffer &key, buffer &value,
if (mapping.split) {
if (MDBX_db_flags_t(key_essentials.flags) & MDBX_DUPSORT) {
key_serial >>= mapping.split;
value_serial += serial & mask(mapping.split);
value_serial += serial & actor_params::serial_mask(mapping.split);
} else {
/* Без MDBX_DUPSORT требуется уникальность ключей, а для этого нельзя
* отбрасывать какие-либо биты serial после инъективного преобразования.
@ -125,7 +123,7 @@ void __hot maker::pair(serial_t serial, const buffer &key, buffer &value,
* запрошенное количество бит из serial */
value_serial +=
(serial ^ (serial >> mapping.split) * UINT64_C(57035339200100753)) &
mask(mapping.split);
actor_params::serial_mask(mapping.split);
}
value_serial |= value_age << mapping.split;
@ -231,49 +229,7 @@ void maker::setup(const config::actor_params_pod &actor, unsigned actor_id,
mapping = actor.keygen;
salt = (actor.keygen.seed + actor_id) * UINT64_C(14653293970879851569);
// FIXME: TODO
base = 0;
}
void maker::make_linear() {
mapping.mesh = (MDBX_db_flags_t(key_essentials.flags) & MDBX_DUPSORT)
? 0
: mapping.split;
mapping.rotate = 0;
mapping.offset = 0;
const auto max_serial = mask(mapping.width) + base;
const auto max_key_serial =
(mapping.split && (MDBX_db_flags_t(key_essentials.flags) & MDBX_DUPSORT))
? max_serial >> mapping.split
: max_serial;
const auto max_value_serial =
(mapping.split && (MDBX_db_flags_t(key_essentials.flags) & MDBX_DUPSORT))
? mask(mapping.split)
: 0;
while (key_essentials.minlen < 8 &&
(key_essentials.minlen == 0 ||
mask(key_essentials.minlen * 8) < max_key_serial)) {
key_essentials.minlen += (MDBX_db_flags_t(key_essentials.flags) &
(MDBX_INTEGERKEY | MDBX_INTEGERDUP))
? 4
: 1;
if (key_essentials.maxlen < key_essentials.minlen)
key_essentials.maxlen = key_essentials.minlen;
}
if (MDBX_db_flags_t(key_essentials.flags | value_essentials.flags) &
MDBX_DUPSORT)
while (value_essentials.minlen < 8 &&
(value_essentials.minlen == 0 ||
mask(value_essentials.minlen * 8) < max_value_serial)) {
value_essentials.minlen += (MDBX_db_flags_t(value_essentials.flags) &
(MDBX_INTEGERKEY | MDBX_INTEGERDUP))
? 4
: 1;
if (value_essentials.maxlen < value_essentials.minlen)
value_essentials.maxlen = value_essentials.minlen;
}
base = actor.serial_base();
}
bool maker::is_unordered() const {
@ -284,14 +240,14 @@ bool maker::is_unordered() const {
}
bool maker::increment(serial_t &serial, int delta) const {
if (serial > mask(mapping.width)) {
if (serial > actor_params::serial_mask(mapping.width)) {
log_extra("keygen-increment: %" PRIu64 " > %" PRIu64 ", overflow", serial,
mask(mapping.width));
actor_params::serial_mask(mapping.width));
return false;
}
serial_t target = serial + (int64_t)delta;
if (target > mask(mapping.width) ||
if (target > actor_params::serial_mask(mapping.width) ||
((delta > 0) ? target < serial : target > serial)) {
log_extra("keygen-increment: %" PRIu64 "%-d => %" PRIu64 ", overflow",
serial, delta, target);

View File

@ -127,7 +127,6 @@ public:
serial_t value_age, const bool keylen_changeable);
void setup(const config::actor_params_pod &actor, unsigned actor_id,
unsigned thread_number);
void make_linear();
bool is_unordered() const;
bool increment(serial_t &serial, int delta) const;