2019-09-09 13:40:24 +03:00
|
|
|
|
/*
|
2024-03-13 14:57:38 +03:00
|
|
|
|
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
2017-03-30 18:54:57 +03:00
|
|
|
|
* 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>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
2022-11-08 16:17:14 +03:00
|
|
|
|
#include "base.h++"
|
|
|
|
|
#include "config.h++"
|
|
|
|
|
#include "log.h++"
|
|
|
|
|
#include "utils.h++"
|
2017-03-30 18:54:57 +03:00
|
|
|
|
|
|
|
|
|
namespace keygen {
|
|
|
|
|
|
|
|
|
|
/* Под "генерацией ключей" здесь понимается генерация обоих значений для
|
|
|
|
|
* пар key-value, т.е. не только ключей, но и ассоциированных с ними данных.
|
2020-05-26 18:39:36 +03:00
|
|
|
|
*
|
|
|
|
|
* Генерацию ключей нельзя отнести к простым задачам, так как требования
|
2017-03-30 18:54:57 +03:00
|
|
|
|
* примерно следующие:
|
|
|
|
|
* - генерация разного количества уникальных ключей различной длины
|
|
|
|
|
* в задаваемом диапазоне;
|
|
|
|
|
* - возможность выбора как псевдо-случайного порядка ключей,
|
|
|
|
|
* так и по некоторым специфическим законам (ограниченными упорядоченными
|
|
|
|
|
* последовательностями, в шахматном порядке по граница диапазона и т.д.);
|
|
|
|
|
* - возможность генерации дубликатов с задаваемым законом распределения;
|
|
|
|
|
* - возможность генерации непересекающимися кластерами для параллельного
|
|
|
|
|
* использования в нескольких потоках;
|
|
|
|
|
* - использовать минимум ресурсов, как CPU, так и RAM, в том числе
|
|
|
|
|
* включая cache pollution и ram bandwidth.
|
|
|
|
|
*
|
|
|
|
|
* При этом заведомо известно, что для MDBX не имеет значения:
|
|
|
|
|
* - используемый алфавит (значения байтов);
|
|
|
|
|
* - частотное распределение по алфавиту;
|
|
|
|
|
* - абсолютное значение ключей или разность между отдельными значениями;
|
|
|
|
|
*
|
2017-05-17 20:10:56 +03:00
|
|
|
|
* Соответственно, в общих чертах, схема генерации следующая:
|
2018-08-31 18:50:35 +03:00
|
|
|
|
* - вводится плоская одномерная "координата" serial (uint64_t);
|
2017-05-17 20:10:56 +03:00
|
|
|
|
* - генерация специфических паттернов (последовательностей)
|
|
|
|
|
* реализуется посредством соответствующих преобразований "координат", при
|
|
|
|
|
* этом все подобные преобразования выполняются только над "координатой";
|
2017-03-30 18:54:57 +03:00
|
|
|
|
* - итоговая "координата" преобразуется в 8-байтное суррогатное значение
|
2017-05-17 20:10:56 +03:00
|
|
|
|
* ключа;
|
|
|
|
|
* - для получения ключей длиной МЕНЕЕ 8 байт суррогат может усекаться
|
|
|
|
|
* до ненулевых байт, в том числе до нулевой длины;
|
|
|
|
|
* - для получения ключей длиной БОЛЕЕ 8 байт суррогат дополняется
|
|
|
|
|
* нулями или псевдослучайной последовательностью;
|
|
|
|
|
*
|
|
|
|
|
* Механизм генерации паттернов:
|
|
|
|
|
* - реализованный механизм является компромиссом между скоростью/простотой
|
|
|
|
|
* и гибкостью, необходимой для получения последовательностей, которых
|
|
|
|
|
* будет достаточно для проверки сценариев разделения и слияния страниц
|
|
|
|
|
* с данными внутри mdbx;
|
|
|
|
|
* - псевдо-случайные паттерны реализуются посредством набора инъективных
|
|
|
|
|
* отображающих функций;
|
|
|
|
|
* - не-псевдо-случайные паттерны реализуются посредством параметризируемого
|
|
|
|
|
* трех-этапного преобразования:
|
|
|
|
|
* 1) смещение (сложение) по модулю;
|
|
|
|
|
* 2) циклический сдвиг;
|
|
|
|
|
* 3) добавление абсолютного смещения (базы);
|
2020-05-26 18:39:36 +03:00
|
|
|
|
*
|
|
|
|
|
* Также см. описание параметров генератора ключей и значений в config.h */
|
2017-03-30 18:54:57 +03:00
|
|
|
|
|
|
|
|
|
typedef uint64_t serial_t;
|
|
|
|
|
|
2017-07-05 23:08:45 +03:00
|
|
|
|
enum : serial_t {
|
2017-05-17 20:10:56 +03:00
|
|
|
|
serial_minwith = 8,
|
|
|
|
|
serial_maxwith = sizeof(serial_t) * 8,
|
2018-08-31 18:50:35 +03:00
|
|
|
|
serial_allones = ~(serial_t)0u
|
2017-03-30 18:54:57 +03:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-17 20:10:56 +03:00
|
|
|
|
struct result {
|
2017-05-23 21:05:54 +03:00
|
|
|
|
MDBX_val value;
|
2017-03-30 18:54:57 +03:00
|
|
|
|
size_t limit;
|
|
|
|
|
union {
|
|
|
|
|
uint8_t bytes[sizeof(uint64_t)];
|
|
|
|
|
uint32_t u32;
|
|
|
|
|
uint64_t u64;
|
|
|
|
|
};
|
2018-08-31 22:17:07 +03:00
|
|
|
|
|
|
|
|
|
std::string as_string() const {
|
|
|
|
|
return std::string((const char *)value.iov_base, value.iov_len);
|
|
|
|
|
}
|
2017-03-30 18:54:57 +03:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-17 20:10:56 +03:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2019-09-01 14:04:02 +03:00
|
|
|
|
struct buffer_deleter /* : public std::unary_function<void, result *> */ {
|
2017-05-17 20:10:56 +03:00
|
|
|
|
void operator()(result *buffer) const { free(buffer); }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef std::unique_ptr<result, buffer_deleter> buffer;
|
|
|
|
|
|
|
|
|
|
buffer alloc(size_t limit);
|
|
|
|
|
|
|
|
|
|
class maker {
|
|
|
|
|
config::keygen_params_pod mapping;
|
2020-05-02 22:38:19 +03:00
|
|
|
|
serial_t base{0};
|
|
|
|
|
serial_t salt{0};
|
2017-05-17 20:10:56 +03:00
|
|
|
|
|
|
|
|
|
struct essentials {
|
2020-05-02 22:38:19 +03:00
|
|
|
|
uint16_t minlen{0};
|
2024-03-02 01:08:22 +03:00
|
|
|
|
enum { prng_fill_flag = 1, value_age_minwidth = 5 };
|
2020-05-02 22:38:19 +03:00
|
|
|
|
uint16_t flags{0};
|
|
|
|
|
uint32_t maxlen{0};
|
2024-03-02 01:08:22 +03:00
|
|
|
|
serial_t mask{0};
|
|
|
|
|
unsigned bits;
|
2017-05-17 20:10:56 +03:00
|
|
|
|
} key_essentials, value_essentials;
|
2024-03-02 01:08:22 +03:00
|
|
|
|
unsigned value_age_bits;
|
|
|
|
|
serial_t value_age_mask{0};
|
2017-05-17 20:10:56 +03:00
|
|
|
|
|
2024-02-20 22:51:35 +03:00
|
|
|
|
static serial_t mk_begin(serial_t serial, const essentials ¶ms,
|
|
|
|
|
result &out);
|
2019-11-24 19:04:21 +03:00
|
|
|
|
static void mk_continue(const serial_t serial, const essentials ¶ms,
|
|
|
|
|
result &out);
|
2017-05-17 20:10:56 +03:00
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
void pair(serial_t serial, const buffer &key, buffer &value,
|
2019-11-24 19:04:21 +03:00
|
|
|
|
serial_t value_age, const bool keylen_changeable);
|
2024-03-03 17:38:23 +03:00
|
|
|
|
void setup(const config::actor_params_pod &actor, unsigned thread_number);
|
2019-02-03 22:37:57 +03:00
|
|
|
|
bool is_unordered() const;
|
2021-03-27 16:47:08 +03:00
|
|
|
|
void seek2end(serial_t &serial) const;
|
2017-05-17 20:10:56 +03:00
|
|
|
|
|
2021-07-23 01:27:02 +03:00
|
|
|
|
bool increment(serial_t &serial, int64_t delta) const;
|
|
|
|
|
bool increment_key_part(serial_t &serial, int64_t delta,
|
2020-10-25 10:51:46 +03:00
|
|
|
|
bool reset_value_part = true) const {
|
2021-03-27 16:47:08 +03:00
|
|
|
|
if (reset_value_part) {
|
|
|
|
|
serial_t value_part_bits = ((serial_t(1) << mapping.split) - 1);
|
|
|
|
|
serial |= value_part_bits;
|
|
|
|
|
if (delta >= 0)
|
|
|
|
|
serial &= ~value_part_bits;
|
|
|
|
|
}
|
2021-07-23 01:27:02 +03:00
|
|
|
|
return increment(serial, int64_t(uint64_t(delta) << mapping.split));
|
2020-10-25 10:51:46 +03:00
|
|
|
|
}
|
2024-03-02 01:08:22 +03:00
|
|
|
|
|
|
|
|
|
serial_t remix_age(serial_t serial) const {
|
|
|
|
|
return (UINT64_C(768097847591) * (serial ^ UINT64_C(768097847591))) &
|
|
|
|
|
value_age_mask;
|
|
|
|
|
}
|
2017-05-17 20:10:56 +03:00
|
|
|
|
};
|
|
|
|
|
|
2020-10-24 20:53:52 +03:00
|
|
|
|
void log_pair(logging::loglevel level, const char *prefix, const buffer &key,
|
|
|
|
|
buffer &value);
|
|
|
|
|
|
2017-03-30 18:54:57 +03:00
|
|
|
|
} /* namespace keygen */
|