diff options
Diffstat (limited to 'libs/libmdbx/src/test/keygen.cc')
-rw-r--r-- | libs/libmdbx/src/test/keygen.cc | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/libs/libmdbx/src/test/keygen.cc b/libs/libmdbx/src/test/keygen.cc new file mode 100644 index 0000000000..99b46f2976 --- /dev/null +++ b/libs/libmdbx/src/test/keygen.cc @@ -0,0 +1,238 @@ +/* + * Copyright 2017-2018 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" + +namespace keygen { + +static inline __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) */, + const serial_t salt) { + assert(bits > serial_minwith && bits <= serial_maxwith); + + /* LY: All these "magic" prime numbers were found + * and verified with a bit of brute force. */ + + static const uint64_t m[64 - serial_minwith] = { + /* 8 - 24 */ + 113, 157, 397, 653, 1753, 5641, 9697, 23873, 25693, 80833, 105953, 316937, + 309277, 834497, 1499933, 4373441, 10184137, + /* 25 - 64 */ + 10184137, 17279209, 33990377, 67295161, 284404553, 1075238767, 6346721573, + 6924051577, 19204053433, 45840188887, 53625693977, 73447827913, + 141638870249, 745683604649, 1283334050489, 1100828289853, 2201656586197, + 5871903036137, 11238507001417, 45264020802263, 105008404482889, + 81921776907059, 199987980256399, 307207457507641, 946769023178273, + 2420886491930041, 3601632139991929, 11984491914483833, 21805846439714153, + 23171543400565993, 53353226456762893, 155627817337932409, + 227827205384840249, 816509268558278821, 576933057762605689, + 2623957345935638441, 5048241705479929949, 4634245581946485653}; + static const uint8_t s[64 - serial_minwith] = { + /* 8 - 24 */ + 2, 3, 4, 4, 2, 4, 3, 3, 7, 3, 3, 4, 8, 3, 10, 3, 11, + /* 25 - 64 */ + 11, 9, 9, 9, 11, 10, 5, 14, 11, 16, 14, 12, 13, 16, 19, 10, 10, 21, 7, 20, + 10, 14, 22, 19, 3, 21, 18, 19, 26, 24, 2, 21, 25, 29, 24, 10, 11, 14}; + + serial_t result = serial * m[bits - 8]; + if (salt) { + const unsigned left = bits / 2; + const unsigned right = bits - left; + result = (result << left) | ((result & mask(bits)) >> right); + result = (result ^ salt) * m[bits - 8]; + } + + result ^= result << s[bits - 8]; + result &= mask(bits); + log_trace("keygen-injective: serial %" PRIu64 " into %" PRIu64, serial, + result); + return result; +} + +void __hot maker::pair(serial_t serial, const buffer &key, buffer &value, + serial_t value_age) { + assert(mapping.width >= serial_minwith && mapping.width <= serial_maxwith); + assert(mapping.split <= mapping.width); + assert(mapping.mesh <= mapping.width); + assert(mapping.rotate <= mapping.width); + assert(mapping.offset <= mask(mapping.width)); + assert(!(key_essentials.flags & (MDBX_INTEGERDUP | MDBX_REVERSEDUP))); + assert(!(value_essentials.flags & (MDBX_INTEGERKEY | MDBX_REVERSEKEY))); + + log_trace("keygen-pair: serial %" PRIu64 ", data-age %" PRIu64, serial, + value_age); + + if (mapping.mesh >= serial_minwith) { + serial = + (serial & ~mask(mapping.mesh)) | injective(serial, mapping.mesh, salt); + log_trace("keygen-pair: mesh %" PRIu64, serial); + } + + if (mapping.rotate) { + const unsigned right = mapping.rotate; + const unsigned left = mapping.width - right; + serial = (serial << left) | ((serial & mask(mapping.width)) >> right); + log_trace("keygen-pair: rotate %" PRIu64 ", 0x%" PRIx64, serial, serial); + } + + serial = (serial + mapping.offset) & mask(mapping.width); + log_trace("keygen-pair: offset %" PRIu64, serial); + serial += base; + + serial_t key_serial = serial; + serial_t value_serial = value_age; + if (mapping.split) { + key_serial = serial >> mapping.split; + value_serial = + (serial & mask(mapping.split)) | (value_age << mapping.split); + } + + log_trace("keygen-pair: key %" PRIu64 ", value %" PRIu64, key_serial, + value_serial); + + mk(key_serial, key_essentials, *key); + mk(value_serial, value_essentials, *value); + + if (log_enabled(logging::trace)) { + char dump_key[128], dump_value[128]; + log_trace("keygen-pair: key %s, value %s", + mdbx_dkey(&key->value, dump_key, sizeof(dump_key)), + mdbx_dkey(&value->value, dump_value, sizeof(dump_value))); + } +} + +void maker::setup(const config::actor_params_pod &actor, + unsigned thread_number) { + key_essentials.flags = + actor.table_flags & (MDBX_INTEGERKEY | MDBX_REVERSEKEY); + assert(actor.keylen_min < UINT8_MAX); + key_essentials.minlen = (uint8_t)actor.keylen_min; + assert(actor.keylen_max < UINT16_MAX); + key_essentials.maxlen = (uint16_t)actor.keylen_max; + + value_essentials.flags = + actor.table_flags & (MDBX_INTEGERDUP | MDBX_REVERSEDUP); + assert(actor.datalen_min < UINT8_MAX); + value_essentials.minlen = (uint8_t)actor.datalen_min; + assert(actor.datalen_max < UINT16_MAX); + value_essentials.maxlen = (uint16_t)actor.datalen_max; + + assert(thread_number < 2); + (void)thread_number; + mapping = actor.keygen; + salt = actor.keygen.seed * UINT64_C(14653293970879851569); + + // FIXME: TODO + base = 0; +} + +bool maker::increment(serial_t &serial, int delta) { + if (serial > mask(mapping.width)) { + log_extra("keygen-increment: %" PRIu64 " > %" PRIu64 ", overflow", serial, + mask(mapping.width)); + return false; + } + + serial_t target = serial + (int64_t)delta; + if (target > mask(mapping.width)) { + log_extra("keygen-increment: %" PRIu64 "%-d => %" PRIu64 ", overflow", + serial, delta, target); + return false; + } + + log_extra("keygen-increment: %" PRIu64 "%-d => %" PRIu64 ", continue", serial, + delta, target); + serial = target; + return true; +} + +//----------------------------------------------------------------------------- + +size_t length(serial_t serial) { + size_t n = 0; + if (serial > UINT32_MAX) { + n = 4; + serial >>= 32; + } + if (serial > UINT16_MAX) { + n += 2; + serial >>= 16; + } + if (serial > UINT8_MAX) { + n += 1; + serial >>= 8; + } + return (serial > 0) ? n + 1 : n; +} + +buffer alloc(size_t limit) { + result *ptr = (result *)malloc(sizeof(result) + limit); + if (unlikely(ptr == nullptr)) + failure_perror("malloc(keyvalue_buffer)", errno); + ptr->value.iov_base = ptr->bytes; + ptr->value.iov_len = 0; + ptr->limit = limit; + return buffer(ptr); +} + +void __hot maker::mk(const serial_t serial, const essentials ¶ms, + result &out) { + assert(out.limit >= params.maxlen); + assert(params.maxlen >= params.minlen); + assert(params.maxlen >= length(serial)); + + out.value.iov_base = out.bytes; + out.value.iov_len = params.minlen; + + if (params.flags & (MDBX_INTEGERKEY | MDBX_INTEGERDUP)) { + assert(params.maxlen == params.minlen); + assert(params.minlen == 4 || params.minlen == 8); + if (is_byteorder_le() || params.minlen == 8) + out.u64 = serial; + else + 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); + unaligned::store(out.bytes + out.value.iov_len - 8, htobe64(serial)); + } else { + out.u64 = htobe64(serial); + if (out.value.iov_len < 8) { + out.value.iov_len = std::max(length(serial), out.value.iov_len); + out.value.iov_base = out.bytes + 8 - out.value.iov_len; + } + } + } else { + out.u64 = htole64(serial); + if (out.value.iov_len > 8) + memset(out.bytes + 8, '\0', out.value.iov_len - 8); + else + out.value.iov_len = std::max(length(serial), out.value.iov_len); + } + + assert(out.value.iov_len >= params.minlen); + assert(out.value.iov_len <= params.maxlen); + assert(out.value.iov_len >= length(serial)); + assert(out.value.iov_base >= out.bytes); + assert((uint8_t *)out.value.iov_base + out.value.iov_len <= + out.bytes + out.limit); +} + +} /* namespace keygen */ |