libmdbx/test/hill.cc

228 lines
8.3 KiB
C++
Raw Normal View History

/*
* 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"
bool testcase_hill::setup() {
log_trace(">> setup");
if (!inherited::setup())
return false;
/* TODO */
log_trace("<< setup");
return true;
}
bool testcase_hill::run() {
db_open();
2017-05-18 01:10:56 +08:00
txn_begin(false);
2017-05-24 06:42:10 +08:00
MDBX_dbi dbi = db_table_open(true);
2017-05-18 01:10:56 +08:00
txn_end(false);
/* LY: тест "холмиком":
* - сначала наполняем таблицу циклическими CRUD-манипуляциями,
* которые в каждом цикле делают несколько операций, включая удаление,
* но в результате добавляют записи.
* - затем очищаем таблицу также CRUD-манипуляциями, но уже с другой
* пропорцией удалений.
*
* При этом очень многое зависит от порядка перебора ключей:
* - (псевдо)случайное распределение требуется лишь для полноты картины,
* но в целом не покрывает важных кейсов.
* - кроме (псевдо)случайного перебора требуется последовательное
* итерирование ключей интервалами различной ширины, с тем чтобы
* проверить различные варианты как разделения, так и слияния страниц
* внутри движка.
2017-05-24 06:42:10 +08:00
* - при не-уникальных ключах (MDBX_DUPSORT с подвариантами), для каждого
2017-05-18 01:10:56 +08:00
* повтора внутри движка формируется вложенное btree-дерево,
* соответственно требуется соблюдение аналогичных принципов
* итерирования для значений.
*/
/* TODO: работа в несколько потоков */
keyvalue_maker.setup(config.params, 0 /* thread_number */);
keygen::buffer a_key = keygen::alloc(config.params.keylen_max);
keygen::buffer a_data_0 = keygen::alloc(config.params.datalen_max);
keygen::buffer a_data_1 = keygen::alloc(config.params.datalen_max);
keygen::buffer b_key = keygen::alloc(config.params.keylen_max);
keygen::buffer b_data = keygen::alloc(config.params.datalen_max);
2017-05-24 06:42:10 +08:00
const unsigned insert_flags = (config.params.table_flags & MDBX_DUPSORT)
? MDBX_NODUPDATA
: MDBX_NODUPDATA | MDBX_NOOVERWRITE;
const unsigned update_flags =
(config.params.table_flags & MDBX_DUPSORT)
? MDBX_CURRENT | MDBX_NODUPDATA | MDBX_NOOVERWRITE
: MDBX_NODUPDATA;
2017-05-18 01:10:56 +08:00
uint64_t serial_count = 0;
unsigned txn_nops = 0;
if (!txn_guard)
txn_begin(false);
2017-05-18 01:10:56 +08:00
while (should_continue()) {
const keygen::serial_t a_serial = serial_count;
if (unlikely(!keyvalue_maker.increment(serial_count, 1)))
failure("uphill: unexpected key-space overflow");
const keygen::serial_t b_serial = serial_count;
assert(b_serial > a_serial);
// создаем первую запись из пары
const keygen::serial_t age_shift = UINT64_C(1) << (a_serial % 31);
log_trace("uphill: insert-a (age %" PRIu64 ") %" PRIu64, age_shift,
a_serial);
generate_pair(a_serial, a_key, a_data_1, age_shift);
int rc = mdbx_put(txn_guard.get(), dbi, &a_key->value, &a_data_1->value,
insert_flags);
2017-05-24 06:42:10 +08:00
if (unlikely(rc != MDBX_SUCCESS))
2017-05-18 01:10:56 +08:00
failure_perror("mdbx_put(insert-a.1)", rc);
if (++txn_nops >= config.params.batch_write) {
txn_restart(false, false);
2017-05-18 01:10:56 +08:00
txn_nops = 0;
}
// создаем вторую запись из пары
log_trace("uphill: insert-b %" PRIu64, b_serial);
generate_pair(b_serial, b_key, b_data, 0);
rc = mdbx_put(txn_guard.get(), dbi, &b_key->value, &b_data->value,
insert_flags);
2017-05-24 06:42:10 +08:00
if (unlikely(rc != MDBX_SUCCESS))
2017-05-18 01:10:56 +08:00
failure_perror("mdbx_put(insert-b)", rc);
if (++txn_nops >= config.params.batch_write) {
txn_restart(false, false);
2017-05-18 01:10:56 +08:00
txn_nops = 0;
}
// обновляем данные в первой записи
log_trace("uphill: update-a (age %" PRIu64 "->0) %" PRIu64, age_shift,
a_serial);
generate_pair(a_serial, a_key, a_data_0, 0);
rc = mdbx_replace(txn_guard.get(), dbi, &a_key->value, &a_data_0->value,
&a_data_1->value, update_flags);
2017-05-24 06:42:10 +08:00
if (unlikely(rc != MDBX_SUCCESS))
failure_perror("mdbx_replace(update-a: 1->0)", rc);
2017-05-18 01:10:56 +08:00
if (++txn_nops >= config.params.batch_write) {
txn_restart(false, false);
2017-05-18 01:10:56 +08:00
txn_nops = 0;
}
// удаляем вторую запись
log_trace("uphill: delete-b %" PRIu64, b_serial);
rc = mdbx_del(txn_guard.get(), dbi, &b_key->value, &b_data->value);
2017-05-24 06:42:10 +08:00
if (unlikely(rc != MDBX_SUCCESS))
2017-05-18 01:10:56 +08:00
failure_perror("mdbx_del(b)", rc);
if (++txn_nops >= config.params.batch_write) {
txn_restart(false, false);
2017-05-18 01:10:56 +08:00
txn_nops = 0;
}
report(1);
if (!keyvalue_maker.increment(serial_count, 1)) {
// дошли до границы пространства ключей
serial_count = a_serial;
goto overflow;
}
}
while (serial_count > 0) {
if (unlikely(!keyvalue_maker.increment(serial_count, -2)))
failure("downhill: unexpected key-space underflow");
overflow:
const keygen::serial_t a_serial = serial_count;
const keygen::serial_t b_serial = a_serial + 1;
assert(b_serial > a_serial);
// обновляем первую запись из пары
const keygen::serial_t age_shift = UINT64_C(1) << (a_serial % 31);
log_trace("downhill: update-a (age 0->%" PRIu64 ") %" PRIu64, age_shift,
a_serial);
generate_pair(a_serial, a_key, a_data_0, 0);
generate_pair(a_serial, a_key, a_data_1, age_shift);
int rc = mdbx_replace(txn_guard.get(), dbi, &a_key->value, &a_data_1->value,
&a_data_0->value, update_flags);
2017-05-24 06:42:10 +08:00
if (unlikely(rc != MDBX_SUCCESS))
2017-05-18 01:10:56 +08:00
failure_perror("mdbx_put(update-a: 0->1)", rc);
if (++txn_nops >= config.params.batch_write) {
txn_restart(false, false);
2017-05-18 01:10:56 +08:00
txn_nops = 0;
}
// создаем вторую запись из пары
log_trace("downhill: insert-b %" PRIu64, b_serial);
generate_pair(b_serial, b_key, b_data, 0);
rc = mdbx_put(txn_guard.get(), dbi, &b_key->value, &b_data->value,
insert_flags);
2017-05-24 06:42:10 +08:00
if (unlikely(rc != MDBX_SUCCESS))
2017-05-18 01:10:56 +08:00
failure_perror("mdbx_put(insert-b)", rc);
if (++txn_nops >= config.params.batch_write) {
txn_restart(false, false);
2017-05-18 01:10:56 +08:00
txn_nops = 0;
}
// удаляем первую запись
log_trace("downhill: delete-a (age %" PRIu64 ") %" PRIu64, age_shift,
a_serial);
rc = mdbx_del(txn_guard.get(), dbi, &a_key->value, &a_data_1->value);
2017-05-24 06:42:10 +08:00
if (unlikely(rc != MDBX_SUCCESS))
2017-05-18 01:10:56 +08:00
failure_perror("mdbx_del(a)", rc);
if (++txn_nops >= config.params.batch_write) {
txn_restart(false, false);
2017-05-18 01:10:56 +08:00
txn_nops = 0;
}
// удаляем вторую запись
log_trace("downhill: delete-b %" PRIu64, b_serial);
rc = mdbx_del(txn_guard.get(), dbi, &b_key->value, &b_data->value);
2017-05-24 06:42:10 +08:00
if (unlikely(rc != MDBX_SUCCESS))
2017-05-18 01:10:56 +08:00
failure_perror("mdbx_del(b)", rc);
if (++txn_nops >= config.params.batch_write) {
txn_restart(false, false);
2017-05-18 01:10:56 +08:00
txn_nops = 0;
}
report(1);
}
if (txn_guard)
txn_end(false);
if (dbi) {
if (config.params.drop_table && !mode_readonly()) {
txn_begin(false);
2017-05-18 01:10:56 +08:00
db_table_drop(dbi);
txn_end(false);
} else
db_table_close(dbi);
}
return true;
}
bool testcase_hill::teardown() {
log_trace(">> teardown");
return inherited::teardown();
}