libmdbx/test/keygen.h++

154 lines
7.1 KiB
C++
Raw Normal View History

/*
mdbx: выпуск 0.12.10 "СЭМ" Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов в память Героя России гвардии майора Дмитрия Семёнова с позывным "СЭМ". Значимые исправления и доработки: --------------------------------- - Устранение унаследованной от LMDB ошибки приводящей к повреждению БД при использовании `MDBX_DUPFIXED`. - Исправление ложной ошибки `MDBX_CORRUPTED (-30796)` в сценарии работы в режиме `MDBX_DUPFIXED` и нечетной длинной мульти-значений. - Исправление недочета корректировки сопутствующих курсоров при разделении страницы по сценарию добавления пустой страницы слева. - Доработка `rebalance()` ради уменьшения WAF. - Исправление assert-проверки внутри `check_txn()` для случая завершенных транзакций в режиме `MDBX_NO_TLS`. Последствий ошибки, кроме срабатывания assert-проверки в отладочных сборках, нет. - Устранение ошибки при открытии БД на файловой системе только-для-чтения. - Удалены излишне строгие проверки в утилите `mdbx_chk`, которые приводили к ложно-позитивным ошибкам при проверке БД после серии последних доработок. Более подробная информация в [ChangeLog](https://libmdbx.dqdkfa.ru/md__change_log.html). git diff' stat: 19 commits, 57 files changed, 751 insertions(+), 331 deletions(-) Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
2024-03-13 19:57:38 +08:00
* Copyright 2017-2024 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>.
*/
#pragma once
#include "base.h++"
#include "config.h++"
#include "log.h++"
#include "utils.h++"
namespace keygen {
/* Под "генерацией ключей" здесь понимается генерация обоих значений для
* пар key-value, т.е. не только ключей, но и ассоциированных с ними данных.
*
* Генерацию ключей нельзя отнести к простым задачам, так как требования
* примерно следующие:
* - генерация разного количества уникальных ключей различной длины
* в задаваемом диапазоне;
* - возможность выбора как псевдо-случайного порядка ключей,
* так и по некоторым специфическим законам (ограниченными упорядоченными
* последовательностями, в шахматном порядке по граница диапазона и т.д.);
* - возможность генерации дубликатов с задаваемым законом распределения;
* - возможность генерации непересекающимися кластерами для параллельного
* использования в нескольких потоках;
* - использовать минимум ресурсов, как CPU, так и RAM, в том числе
* включая cache pollution и ram bandwidth.
*
* При этом заведомо известно, что для MDBX не имеет значения:
* - используемый алфавит (значения байтов);
* - частотное распределение по алфавиту;
* - абсолютное значение ключей или разность между отдельными значениями;
*
2017-05-18 01:10:56 +08:00
* Соответственно, в общих чертах, схема генерации следующая:
* - вводится плоская одномерная "координата" serial (uint64_t);
2017-05-18 01:10:56 +08:00
* - генерация специфических паттернов (последовательностей)
* реализуется посредством соответствующих преобразований "координат", при
* этом все подобные преобразования выполняются только над "координатой";
* - итоговая "координата" преобразуется в 8-байтное суррогатное значение
2017-05-18 01:10:56 +08:00
* ключа;
* - для получения ключей длиной МЕНЕЕ 8 байт суррогат может усекаться
* до ненулевых байт, в том числе до нулевой длины;
* - для получения ключей длиной БОЛЕЕ 8 байт суррогат дополняется
* нулями или псевдослучайной последовательностью;
*
* Механизм генерации паттернов:
* - реализованный механизм является компромиссом между скоростью/простотой
* и гибкостью, необходимой для получения последовательностей, которых
* будет достаточно для проверки сценариев разделения и слияния страниц
* с данными внутри mdbx;
* - псевдо-случайные паттерны реализуются посредством набора инъективных
* отображающих функций;
* - не-псевдо-случайные паттерны реализуются посредством параметризируемого
* трех-этапного преобразования:
* 1) смещение (сложение) по модулю;
* 2) циклический сдвиг;
* 3) добавление абсолютного смещения (базы);
*
* Также см. описание параметров генератора ключей и значений в config.h */
typedef uint64_t serial_t;
enum : serial_t {
2017-05-18 01:10:56 +08:00
serial_minwith = 8,
serial_maxwith = sizeof(serial_t) * 8,
serial_allones = ~(serial_t)0u
};
2017-05-18 01:10:56 +08:00
struct result {
2017-05-24 02:05:54 +08:00
MDBX_val value;
size_t limit;
union {
uint8_t bytes[sizeof(uint64_t)];
uint32_t u32;
uint64_t u64;
};
std::string as_string() const {
return std::string((const char *)value.iov_base, value.iov_len);
}
};
2017-05-18 01:10:56 +08:00
//-----------------------------------------------------------------------------
struct buffer_deleter /* : public std::unary_function<void, result *> */ {
2017-05-18 01:10:56 +08: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;
serial_t base{0};
serial_t salt{0};
2017-05-18 01:10:56 +08:00
struct essentials {
uint16_t minlen{0};
enum { prng_fill_flag = 1, value_age_minwidth = 5 };
uint16_t flags{0};
uint32_t maxlen{0};
serial_t mask{0};
unsigned bits;
2017-05-18 01:10:56 +08:00
} key_essentials, value_essentials;
unsigned value_age_bits;
serial_t value_age_mask{0};
2017-05-18 01:10:56 +08:00
static serial_t mk_begin(serial_t serial, const essentials &params,
result &out);
static void mk_continue(const serial_t serial, const essentials &params,
result &out);
2017-05-18 01:10:56 +08:00
public:
void pair(serial_t serial, const buffer &key, buffer &value,
serial_t value_age, const bool keylen_changeable);
void setup(const config::actor_params_pod &actor, unsigned thread_number);
bool is_unordered() const;
void seek2end(serial_t &serial) const;
2017-05-18 01:10:56 +08:00
bool increment(serial_t &serial, int64_t delta) const;
bool increment_key_part(serial_t &serial, int64_t delta,
bool reset_value_part = true) const {
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;
}
return increment(serial, int64_t(uint64_t(delta) << mapping.split));
}
serial_t remix_age(serial_t serial) const {
return (UINT64_C(768097847591) * (serial ^ UINT64_C(768097847591))) &
value_age_mask;
}
2017-05-18 01:10:56 +08:00
};
void log_pair(logging::loglevel level, const char *prefix, const buffer &key,
buffer &value);
} /* namespace keygen */