diff options
Diffstat (limited to 'libs/libmdbx/src/test')
36 files changed, 0 insertions, 8754 deletions
diff --git a/libs/libmdbx/src/test/CMakeLists.txt b/libs/libmdbx/src/test/CMakeLists.txt deleted file mode 100644 index 3e0a929b76..0000000000 --- a/libs/libmdbx/src/test/CMakeLists.txt +++ /dev/null @@ -1,72 +0,0 @@ -add_executable(mdbx_test - base.h - cases.cc - chrono.cc - chrono.h - config.cc - config.h - copy.cc - dead.cc - hill.cc - jitter.cc - keygen.cc - keygen.h - log.cc - log.h - main.cc - osal.h - osal-unix.cc - osal-windows.cc - test.cc - test.h - try.cc - utils.cc - utils.h - append.cc - ttl.cc - nested.cc - ) - -list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_20 HAS_CXX20) -list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_17 HAS_CXX17) -list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_14 HAS_CXX14) -list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_11 HAS_CXX11) -if(NOT DEFINED MDBX_CXX_STANDARD) - if(DEFINED CMAKE_CXX_STANDARD) - set(MDBX_CXX_STANDARD ${CMAKE_CXX_STANDARD}) - elseif(NOT HAS_CXX20 LESS 0) - set(MDBX_CXX_STANDARD 20) - elseif(NOT HAS_CXX17 LESS 0) - set(MDBX_CXX_STANDARD 17) - elseif(NOT HAS_CXX14 LESS 0) - set(MDBX_CXX_STANDARD 14) - elseif(NOT HAS_CXX11 LESS 0) - set(MDBX_CXX_STANDARD 11) - endif() -endif() -if(MDBX_CXX_STANDARD) - message(STATUS "Use C++${MDBX_CXX_STANDARD} for libmdbx") - if(NOT SUBPROJECT OR NOT DEFINED CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD ${MDBX_CXX_STANDARD}) - endif() -endif() - -if(MDBX_CXX_STANDARD) - set_target_properties(mdbx_test PROPERTIES - CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON) -endif() - -set_target_properties(mdbx_test PROPERTIES - INTERPROCEDURAL_OPTIMIZATION $<BOOL:${INTERPROCEDURAL_OPTIMIZATION}>) -target_setup_options(mdbx_test) - -target_link_libraries(mdbx_test ${TOOL_MDBX_LIB} ${LIB_MATH} ${CMAKE_THREAD_LIBS_INIT}) -if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - target_link_libraries(mdbx_test winmm.lib) -endif() - -if(UNIX AND NOT SUBPROJECT) - add_executable(pcrf_test pcrf/pcrf_test.c) - target_include_directories(pcrf_test PRIVATE "${PROJECT_SOURCE_DIR}") - target_link_libraries(pcrf_test ${TOOL_MDBX_LIB}) -endif() diff --git a/libs/libmdbx/src/test/append.cc b/libs/libmdbx/src/test/append.cc deleted file mode 100644 index 2fc8e429da..0000000000 --- a/libs/libmdbx/src/test/append.cc +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2017-2020 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_append::run() { - int err = db_open__begin__table_create_open_clean(dbi); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("append: bailout-prepare due '%s'", mdbx_strerror(err)); - return true; - } - - keyvalue_maker.setup(config.params, config.actor_id, 0 /* thread_number */); - /* LY: тест наполнения таблиц в append-режиме, - * при котором записи добавляются строго в конец (в порядке сортировки) */ - const unsigned flags = (config.params.table_flags & MDBX_DUPSORT) - ? MDBX_APPEND | MDBX_APPENDDUP - : MDBX_APPEND; - keyvalue_maker.make_ordered(); - - key = keygen::alloc(config.params.keylen_max); - data = keygen::alloc(config.params.datalen_max); - keygen::buffer last_key = keygen::alloc(config.params.keylen_max); - keygen::buffer last_data = keygen::alloc(config.params.datalen_max); - last_key->value.iov_base = last_key->bytes; - last_key->value.iov_len = 0; - last_data->value.iov_base = last_data->bytes; - last_data->value.iov_len = 0; - - simple_checksum inserted_checksum; - uint64_t inserted_number = 0; - uint64_t serial_count = 0; - - unsigned txn_nops = 0; - uint64_t commited_inserted_number = inserted_number; - simple_checksum commited_inserted_checksum = inserted_checksum; - while (should_continue()) { - const keygen::serial_t serial = serial_count; - if (!keyvalue_maker.increment(serial_count, 1)) { - // дошли до границы пространства ключей - break; - } - - log_trace("append: append-a %" PRIu64, serial); - generate_pair(serial); - int cmp = inserted_number ? mdbx_cmp(txn_guard.get(), dbi, &key->value, - &last_key->value) - : 1; - if (cmp == 0 && (config.params.table_flags & MDBX_DUPSORT)) - cmp = mdbx_dcmp(txn_guard.get(), dbi, &data->value, &last_data->value); - - err = mdbx_put(txn_guard.get(), dbi, &key->value, &data->value, flags); - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - log_notice("append: bailout-insert due '%s'", mdbx_strerror(err)); - txn_end(true); - inserted_number = commited_inserted_number; - inserted_checksum = commited_inserted_checksum; - break; - } - - if (cmp > 0) { - if (unlikely(err != MDBX_SUCCESS)) - failure_perror("mdbx_put(appenda-a)", err); - - memcpy(last_key->value.iov_base, key->value.iov_base, - last_key->value.iov_len = key->value.iov_len); - memcpy(last_data->value.iov_base, data->value.iov_base, - last_data->value.iov_len = data->value.iov_len); - ++inserted_number; - inserted_checksum.push((uint32_t)inserted_number, key->value); - inserted_checksum.push(10639, data->value); - } else { - if (unlikely(err != MDBX_EKEYMISMATCH)) - failure_perror("mdbx_put(appenda-a) != MDBX_EKEYMISMATCH", err); - } - - if (++txn_nops >= config.params.batch_write) { - err = breakable_restart(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("append: bailout-commit due '%s'", mdbx_strerror(err)); - inserted_number = commited_inserted_number; - inserted_checksum = commited_inserted_checksum; - break; - } - commited_inserted_number = inserted_number; - commited_inserted_checksum = inserted_checksum; - txn_nops = 0; - } - - report(1); - } - - if (txn_guard) { - err = breakable_commit(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("append: bailout-commit due '%s'", mdbx_strerror(err)); - inserted_number = commited_inserted_number; - inserted_checksum = commited_inserted_checksum; - } - } - //---------------------------------------------------------------------------- - txn_begin(true); - cursor_open(dbi); - - MDBX_val check_key, check_data; - err = - mdbx_cursor_get(cursor_guard.get(), &check_key, &check_data, MDBX_FIRST); - if (likely(inserted_number)) { - if (unlikely(err != MDBX_SUCCESS)) - failure_perror("mdbx_cursor_get(MDBX_FIRST)", err); - } - - simple_checksum read_checksum; - uint64_t read_count = 0; - while (err == MDBX_SUCCESS) { - ++read_count; - read_checksum.push((uint32_t)read_count, check_key); - read_checksum.push(10639, check_data); - - err = - mdbx_cursor_get(cursor_guard.get(), &check_key, &check_data, MDBX_NEXT); - } - - if (unlikely(err != MDBX_NOTFOUND)) - failure_perror("mdbx_cursor_get(MDBX_NEXT) != EOF", err); - - if (unlikely(read_count != inserted_number)) - failure("read_count(%" PRIu64 ") != inserted_number(%" PRIu64 ")", - read_count, inserted_number); - - if (unlikely(read_checksum.value != inserted_checksum.value)) - failure("read_checksum(0x%016" PRIu64 ") " - "!= inserted_checksum(0x%016" PRIu64 ")", - read_checksum.value, inserted_checksum.value); - - cursor_close(); - txn_end(true); - //---------------------------------------------------------------------------- - - if (dbi) { - if (config.params.drop_table && !mode_readonly()) { - txn_begin(false); - db_table_drop(dbi); - err = breakable_commit(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("append: bailout-clean due '%s'", mdbx_strerror(err)); - return true; - } - } else - db_table_close(dbi); - } - return true; -} diff --git a/libs/libmdbx/src/test/base.h b/libs/libmdbx/src/test/base.h deleted file mode 100644 index 7fc6cac68c..0000000000 --- a/libs/libmdbx/src/test/base.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2017-2020 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 - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) -#ifdef _MSC_VER -#define _CRT_SECURE_NO_WARNINGS -#pragma warning(push, 1) -#pragma warning(disable : 4548) /* expression before comma has no effect; \ - expected expression with side - effect */ -#pragma warning(disable : 4530) /* C++ exception handler used, but unwind \ - semantics are not enabled. Specify /EHsc */ -#pragma warning(disable : 4577) /* 'noexcept' used with no exception handling \ - mode specified; termination on exception \ - is not guaranteed. Specify /EHsc */ -#endif /* _MSC_VER (warnings) */ - -/* If you wish to build your application for a previous Windows platform, - * include WinSDKVer.h and set the _WIN32_WINNT macro to the platform you - * wish to support before including SDKDDKVer.h. - * - * TODO: #define _WIN32_WINNT WIN32_MUSTDIE */ -#include <SDKDDKVer.h> -#endif /* WINDOWS */ - -#ifdef __APPLE__ -#define _DARWIN_C_SOURCE -#endif - -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) -#include <io.h> -#else -#include <fcntl.h> -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/types.h> -#include <unistd.h> -#endif - -#ifdef _BSD_SOURCE -#include <endian.h> -#endif - -#include <algorithm> -#include <cassert> -#include <cinttypes> // for PRId64, PRIu64 -#include <cstdarg> -#include <cstddef> -#include <cstdint> -#include <map> -#include <memory> -#include <set> -#include <string> -#include <type_traits> -#include <unordered_map> -#include <unordered_set> -#include <vector> - -#define MDBX_INTERNAL_FUNC -#define MDBX_INTERNAL_VAR extern -#define MDBX_TOOLS /* Avoid using internal mdbx_assert() */ -#include "../mdbx.h" -#include "../src/defs.h" -#include "../src/osal.h" - -#if !defined(__thread) && (defined(_MSC_VER) || defined(__DMC__)) -#define __thread __declspec(thread) -#endif /* __thread */ - -#include "../src/options.h" - -#ifdef _MSC_VER -#pragma warning(pop) -#pragma warning(disable : 4201) /* nonstandard extension used : \ - nameless struct / union */ -#pragma warning(disable : 4127) /* conditional expression is constant */ -#if _MSC_VER < 1900 -#pragma warning(disable : 4510) /* default constructor could \ - not be generated */ -#pragma warning(disable : 4512) /* assignment operator could \ - not be generated */ -#pragma warning(disable : 4610) /* user-defined constructor required */ -#ifndef snprintf -#define snprintf(buffer, buffer_size, format, ...) \ - _snprintf_s(buffer, buffer_size, _TRUNCATE, format, __VA_ARGS__) -#endif -#ifndef vsnprintf -#define vsnprintf(buffer, buffer_size, format, args) \ - _vsnprintf_s(buffer, buffer_size, _TRUNCATE, format, args) -#endif -#pragma warning(disable : 4996) /* 'vsnprintf': This function or variable \ - may be unsafe */ -#endif -#endif /* _MSC_VER */ diff --git a/libs/libmdbx/src/test/cases.cc b/libs/libmdbx/src/test/cases.cc deleted file mode 100644 index 98255f52ca..0000000000 --- a/libs/libmdbx/src/test/cases.cc +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2017-2020 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" - -void configure_actor(unsigned &last_space_id, const actor_testcase testcase, - const char *space_id_cstr, const actor_params ¶ms) { - unsigned wait4id = 0; - if (params.waitfor_nops) { - for (auto i = global::actors.rbegin(); i != global::actors.rend(); ++i) { - if (i->is_waitable(params.waitfor_nops)) { - if (i->signal_nops && i->signal_nops != params.waitfor_nops) - failure("Previous waitable actor (id=%u) already linked on %u-ops\n", - i->actor_id, i->signal_nops); - wait4id = i->actor_id; - i->signal_nops = params.waitfor_nops; - break; - } - } - if (!wait4id) - failure("No previous waitable actor for %u-ops\n", params.waitfor_nops); - } - - unsigned space_id = 0; - if (!space_id_cstr || strcmp(space_id_cstr, "auto") == 0) - space_id = last_space_id + 1; - else { - char *end = nullptr; - errno = 0; - space_id = strtoul(space_id_cstr, &end, 0); - if (errno) - failure_perror("Expects an integer value for space-id\n", errno); - if (end && *end) - failure("The '%s' is unexpected for space-id\n", end); - } - - if (space_id > ACTOR_ID_MAX) - failure("Invalid space-id %u\n", space_id); - last_space_id = space_id; - - log_trace("configure_actor: space %u for %s", space_id, - testcase2str(testcase)); - global::actors.emplace_back( - actor_config(testcase, params, space_id, wait4id)); - global::databases.insert(params.pathname_db); -} - -void testcase_setup(const char *casename, actor_params ¶ms, - unsigned &last_space_id) { - if (strcmp(casename, "basic") == 0) { - log_notice(">>> testcase_setup(%s)", casename); - configure_actor(last_space_id, ac_nested, nullptr, params); - configure_actor(last_space_id, ac_hill, nullptr, params); - configure_actor(last_space_id, ac_ttl, nullptr, params); - configure_actor(last_space_id, ac_copy, nullptr, params); - configure_actor(last_space_id, ac_append, nullptr, params); - configure_actor(last_space_id, ac_jitter, nullptr, params); - configure_actor(last_space_id, ac_try, nullptr, params); - configure_actor(last_space_id, ac_jitter, nullptr, params); - configure_actor(last_space_id, ac_try, nullptr, params); - log_notice("<<< testcase_setup(%s): done", casename); - } else { - failure("unknown testcase `%s`", casename); - } -} - -void keycase_setup(const char *casename, actor_params ¶ms) { - if (strcmp(casename, "random") == 0 || strcmp(casename, "prng") == 0) { - log_notice(">>> keycase_setup(%s)", casename); - params.keygen.keycase = kc_random; - // TODO - log_notice("<<< keycase_setup(%s): done", casename); - } else if (strcmp(casename, "dashes") == 0 || - strcmp(casename, "aside") == 0) { - log_notice(">>> keycase_setup(%s)", casename); - params.keygen.keycase = kc_dashes; - // TODO - log_notice("<<< keycase_setup(%s): done", casename); - } else if (strcmp(casename, "custom") == 0) { - log_notice("=== keycase_setup(%s): skip", casename); - params.keygen.keycase = kc_custom; - } else { - failure("unknown keycase `%s`", casename); - } -} - -/* TODO */ diff --git a/libs/libmdbx/src/test/chrono.cc b/libs/libmdbx/src/test/chrono.cc deleted file mode 100644 index 43cd2a370c..0000000000 --- a/libs/libmdbx/src/test/chrono.cc +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2017-2020 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 chrono { - -#ifndef NSEC_PER_SEC -#define NSEC_PER_SEC 1000000000u -#endif /* NSEC_PER_SEC */ - -uint32_t ns2fractional(uint32_t ns) { - assert(ns < NSEC_PER_SEC); - /* LY: здесь и далее используется "длинное деление", которое - * для ясности кода оставлено как есть (без ручной оптимизации). Так как - * GCC, Clang и даже MSVC сами давно умеют конвертировать деление на - * константу в быструю reciprocal-форму. */ - return ((uint64_t)ns << 32) / NSEC_PER_SEC; -} - -uint32_t fractional2ns(uint32_t fractional) { - return (fractional * (uint64_t)NSEC_PER_SEC) >> 32; -} - -#ifndef USEC_PER_SEC -#define USEC_PER_SEC 1000000u -#endif /* USEC_PER_SEC */ -uint32_t us2fractional(uint32_t us) { - assert(us < USEC_PER_SEC); - return ((uint64_t)us << 32) / USEC_PER_SEC; -} - -uint32_t fractional2us(uint32_t fractional) { - return (fractional * (uint64_t)USEC_PER_SEC) >> 32; -} - -#ifndef MSEC_PER_SEC -#define MSEC_PER_SEC 1000u -#endif /* MSEC_PER_SEC */ -uint32_t ms2fractional(uint32_t ms) { - assert(ms < MSEC_PER_SEC); - return ((uint64_t)ms << 32) / MSEC_PER_SEC; -} - -uint32_t fractional2ms(uint32_t fractional) { - return (fractional * (uint64_t)MSEC_PER_SEC) >> 32; -} - -time from_ns(uint64_t ns) { - time result; - result.fixedpoint = ((ns / NSEC_PER_SEC) << 32) | - ns2fractional((uint32_t)(ns % NSEC_PER_SEC)); - return result; -} - -time from_us(uint64_t us) { - time result; - result.fixedpoint = ((us / USEC_PER_SEC) << 32) | - us2fractional((uint32_t)(us % USEC_PER_SEC)); - return result; -} - -time from_ms(uint64_t ms) { - time result; - result.fixedpoint = ((ms / MSEC_PER_SEC) << 32) | - ms2fractional((uint32_t)(ms % MSEC_PER_SEC)); - return result; -} - -time now_realtime() { -#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) - static void(WINAPI * query_time)(LPFILETIME); - if (!query_time) { - query_time = (void(WINAPI *)(LPFILETIME))GetProcAddress( - GetModuleHandle(TEXT("kernel32.dll")), - "GetSystemTimePreciseAsFileTime"); - if (!query_time) - query_time = GetSystemTimeAsFileTime; - } - - FILETIME filetime; - query_time(&filetime); - uint64_t ns100 = - (uint64_t)filetime.dwHighDateTime << 32 | filetime.dwLowDateTime; - return from_ns((ns100 - UINT64_C(116444736000000000)) * 100u); -#else - struct timespec ts; - if (unlikely(clock_gettime(CLOCK_REALTIME, &ts))) - failure_perror("clock_gettime(CLOCK_REALTIME", errno); - - return from_timespec(ts); -#endif -} - -time now_motonic() { -#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) - static uint64_t reciprocal; - static LARGE_INTEGER Frequency; - if (reciprocal == 0) { - if (!QueryPerformanceFrequency(&Frequency)) - failure_perror("QueryPerformanceFrequency()", GetLastError()); - reciprocal = (((UINT64_C(1) << 48) + Frequency.QuadPart / 2 + 1) / - Frequency.QuadPart); - assert(reciprocal); - } - - LARGE_INTEGER Counter; - if (!QueryPerformanceCounter(&Counter)) - failure_perror("QueryPerformanceCounter()", GetLastError()); - - time result; - result.fixedpoint = (Counter.QuadPart / Frequency.QuadPart) << 32; - uint64_t mod = Counter.QuadPart % Frequency.QuadPart; - result.fixedpoint += (mod * reciprocal) >> 16; - return result; -#else - struct timespec ts; - if (unlikely(clock_gettime(CLOCK_MONOTONIC, &ts))) - failure_perror("clock_gettime(CLOCK_MONOTONIC)", errno); - - return from_timespec(ts); -#endif -} - -} /* namespace chrono */ diff --git a/libs/libmdbx/src/test/chrono.h b/libs/libmdbx/src/test/chrono.h deleted file mode 100644 index f3d8debe74..0000000000 --- a/libs/libmdbx/src/test/chrono.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2017-2020 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 "utils.h" - -namespace chrono { - -#pragma pack(push, 1) - -typedef union time { - uint64_t fixedpoint; - __anonymous_struct_extension__ struct { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - uint32_t fractional; - union { - uint32_t utc; - uint32_t integer; - }; -#else - union { - uint32_t utc; - uint32_t integer; - }; - uint32_t fractional; -#endif - }; - - void reset() { fixedpoint = 0; } - uint32_t seconds() const { return utc; } -} time; - -#pragma pack(pop) - -uint32_t ns2fractional(uint32_t); -uint32_t fractional2ns(uint32_t); -uint32_t us2fractional(uint32_t); -uint32_t fractional2us(uint32_t); -uint32_t ms2fractional(uint32_t); -uint32_t fractional2ms(uint32_t); - -time from_ns(uint64_t us); -time from_us(uint64_t ns); -time from_ms(uint64_t ms); - -inline time from_seconds(uint64_t seconds) { - assert(seconds < UINT32_MAX); - time result; - result.fixedpoint = seconds << 32; - return result; -} - -inline time from_utc(time_t utc) { - assert(utc >= 0); - return from_seconds((uint64_t)utc); -} - -inline time infinite() { - time result; - result.fixedpoint = UINT64_MAX; - return result; -} - -#if defined(HAVE_TIMESPEC_TV_NSEC) || defined(__timespec_defined) || \ - defined(CLOCK_REALTIME) -inline time from_timespec(const struct timespec &ts) { - time result; - result.fixedpoint = - ((uint64_t)ts.tv_sec << 32) | ns2fractional((uint32_t)ts.tv_nsec); - return result; -} -#endif /* HAVE_TIMESPEC_TV_NSEC */ - -#if defined(HAVE_TIMEVAL_TV_USEC) || defined(_STRUCT_TIMEVAL) -inline time from_timeval(const struct timeval &tv) { - time result; - result.fixedpoint = - ((uint64_t)tv.tv_sec << 32) | us2fractional((uint32_t)tv.tv_usec); - return result; -} -#endif /* HAVE_TIMEVAL_TV_USEC */ - -time now_realtime(); -time now_motonic(); - -} /* namespace chrono */ diff --git a/libs/libmdbx/src/test/config.cc b/libs/libmdbx/src/test/config.cc deleted file mode 100644 index f8e6866f94..0000000000 --- a/libs/libmdbx/src/test/config.cc +++ /dev/null @@ -1,603 +0,0 @@ -/* - * Copyright 2017-2020 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" - -#if defined(_MSC_VER) && !defined(strcasecmp) -#define strcasecmp(str, len) _stricmp(str, len) -#endif /* _MSC_VER && strcasecmp() */ - -namespace config { - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - const char **value, const char *default_value) { - assert(narg < argc); - const char *current = argv[narg]; - const size_t optlen = strlen(option); - - if (strncmp(current, "--", 2) || strncmp(current + 2, option, optlen)) - return false; - - if (!value) { - if (current[optlen + 2] == '=') - failure("Option '--%s' doen't accept any value\n", option); - return true; - } - - *value = nullptr; - if (current[optlen + 2] == '=') { - *value = ¤t[optlen + 3]; - return true; - } - - if (narg + 1 < argc && strncmp("--", argv[narg + 1], 2) != 0) { - *value = argv[narg + 1]; - if (strcmp(*value, "default") == 0) { - if (!default_value) - failure("Option '--%s' doen't accept default value\n", option); - *value = default_value; - } - ++narg; - return true; - } - - if (default_value) { - *value = default_value; - return true; - } - - failure("No value given for '--%s' option\n", option); -} - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - std::string &value, bool allow_empty) { - return parse_option(argc, argv, narg, option, value, allow_empty, - allow_empty ? "" : nullptr); -} - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - std::string &value, bool allow_empty, - const char *default_value) { - const char *value_cstr; - if (!parse_option(argc, argv, narg, option, &value_cstr, default_value)) - return false; - - if (!allow_empty && strlen(value_cstr) == 0) - failure("Value for option '--%s' could't be empty\n", option); - - value = value_cstr; - return true; -} - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - unsigned &mask, const option_verb *verbs) { - const char *list; - if (!parse_option(argc, argv, narg, option, &list)) - return false; - - unsigned clear = 0; - while (*list) { - if (*list == ',' || *list == ' ' || *list == '\t') { - ++list; - continue; - } - - const char *const comma = strchr(list, ','); - const bool strikethrough = *list == '-' || *list == '~'; - if (strikethrough || *list == '+') - ++list; - else - mask = clear; - const size_t len = (comma) ? comma - list : strlen(list); - const option_verb *scan = verbs; - - while (true) { - if (!scan->verb) - failure("Unknown verb '%.*s', for option '==%s'\n", (int)len, list, - option); - if (strlen(scan->verb) == len && strncmp(list, scan->verb, len) == 0) { - mask = strikethrough ? mask & ~scan->mask : mask | scan->mask; - clear = strikethrough ? clear & ~scan->mask : clear | scan->mask; - list += len; - break; - } - ++scan; - } - } - - return true; -} - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - uint64_t &value, const scale_mode scale, - const uint64_t minval, const uint64_t maxval, - const uint64_t default_value) { - - const char *value_cstr; - if (!parse_option(argc, argv, narg, option, &value_cstr)) - return false; - - if (default_value && strcmp(value_cstr, "default") == 0) { - value = default_value; - return true; - } - - if (strcmp(value_cstr, "min") == 0 || strcmp(value_cstr, "minimal") == 0) { - value = minval; - return true; - } - - if (strcmp(value_cstr, "max") == 0 || strcmp(value_cstr, "maximal") == 0) { - value = maxval; - return true; - } - - char *suffix = nullptr; - errno = 0; - unsigned long long raw = strtoull(value_cstr, &suffix, 0); - if ((suffix && *suffix) || errno) { - suffix = nullptr; - errno = 0; - raw = strtoull(value_cstr, &suffix, 10); - } - if (errno) - failure("Option '--%s' expects a numeric value (%s)\n", option, - test_strerror(errno)); - - uint64_t multipler = 1; - if (suffix && *suffix) { - if (scale == no_scale) - failure("Option '--%s' doen't accepts suffixes, so '%s' is unexpected\n", - option, suffix); - if (strcmp(suffix, "K") == 0 || strcasecmp(suffix, "Kilo") == 0) - multipler = (scale == decimal) ? UINT64_C(1000) : UINT64_C(1024); - else if (strcmp(suffix, "M") == 0 || strcasecmp(suffix, "Mega") == 0) - multipler = - (scale == decimal) ? UINT64_C(1000) * 1000 : UINT64_C(1024) * 1024; - else if (strcmp(suffix, "G") == 0 || strcasecmp(suffix, "Giga") == 0) - multipler = (scale == decimal) ? UINT64_C(1000) * 1000 * 1000 - : UINT64_C(1024) * 1024 * 1024; - else if (strcmp(suffix, "T") == 0 || strcasecmp(suffix, "Tera") == 0) - multipler = (scale == decimal) ? UINT64_C(1000) * 1000 * 1000 * 1000 - : UINT64_C(1024) * 1024 * 1024 * 1024; - else if (scale == duration && - (strcmp(suffix, "s") == 0 || strcasecmp(suffix, "Seconds") == 0)) - multipler = 1; - else if (scale == duration && - (strcmp(suffix, "m") == 0 || strcasecmp(suffix, "Minutes") == 0)) - multipler = 60; - else if (scale == duration && - (strcmp(suffix, "h") == 0 || strcasecmp(suffix, "Hours") == 0)) - multipler = 3600; - else if (scale == duration && - (strcmp(suffix, "d") == 0 || strcasecmp(suffix, "Days") == 0)) - multipler = 3600 * 24; - else - failure( - "Option '--%s' expects a numeric value with Kilo/Mega/Giga/Tera %s" - "suffixes, but '%s' is unexpected\n", - option, (scale == duration) ? "or Seconds/Minutes/Hours/Days " : "", - suffix); - } - - if (raw >= UINT64_MAX / multipler) - failure("The value for option '--%s' is too huge\n", option); - - value = raw * multipler; - if (maxval && value > maxval) - failure("The maximal value for option '--%s' is %" PRIu64 "\n", option, - maxval); - if (value < minval) - failure("The minimal value for option '--%s' is %" PRIu64 "\n", option, - minval); - return true; -} - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - unsigned &value, const scale_mode scale, - const unsigned minval, const unsigned maxval, - const unsigned default_value) { - - uint64_t huge; - if (!parse_option(argc, argv, narg, option, huge, scale, minval, maxval, - default_value)) - return false; - value = (unsigned)huge; - return true; -} - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - uint8_t &value, const uint8_t minval, const uint8_t maxval, - const uint8_t default_value) { - - uint64_t huge; - if (!parse_option(argc, argv, narg, option, huge, no_scale, minval, maxval, - default_value)) - return false; - value = (uint8_t)huge; - return true; -} - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - int64_t &value, const int64_t minval, const int64_t maxval, - const int64_t default_value) { - uint64_t proxy = (uint64_t)value; - if (parse_option(argc, argv, narg, option, proxy, config::binary, - (uint64_t)minval, (uint64_t)maxval, - (uint64_t)default_value)) { - value = (int64_t)proxy; - return true; - } - return false; -} - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - int32_t &value, const int32_t minval, const int32_t maxval, - const int32_t default_value) { - uint64_t proxy = (uint64_t)value; - if (parse_option(argc, argv, narg, option, proxy, config::binary, - (uint64_t)minval, (uint64_t)maxval, - (uint64_t)default_value)) { - value = (int32_t)proxy; - return true; - } - return false; -} - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - bool &value) { - const char *value_cstr = nullptr; - if (!parse_option(argc, argv, narg, option, &value_cstr, "yes")) { - const char *current = argv[narg]; - if (strncmp(current, "--no-", 5) == 0 && strcmp(current + 5, option) == 0) { - value = false; - return true; - } - if (strncmp(current, "--dont-", 7) == 0 && - strcmp(current + 7, option) == 0) { - value = false; - return true; - } - return false; - } - - if (!value_cstr) { - value = true; - return true; - } - - if (strcasecmp(value_cstr, "yes") == 0 || strcasecmp(value_cstr, "1") == 0) { - value = true; - return true; - } - - if (strcasecmp(value_cstr, "no") == 0 || strcasecmp(value_cstr, "0") == 0) { - value = false; - return true; - } - - failure( - "Option '--%s' expects a 'boolean' value Yes/No, so '%s' is unexpected\n", - option, value_cstr); -} - -//----------------------------------------------------------------------------- - -const struct option_verb mode_bits[] = {{"rdonly", MDBX_RDONLY}, - {"mapasync", MDBX_MAPASYNC}, - {"nosync-utterly", MDBX_UTTERLY_NOSYNC}, - {"nosubdir", MDBX_NOSUBDIR}, - {"nosync-safe", MDBX_SAFE_NOSYNC}, - {"nometasync", MDBX_NOMETASYNC}, - {"writemap", MDBX_WRITEMAP}, - {"notls", MDBX_NOTLS}, - {"nordahead", MDBX_NORDAHEAD}, - {"nomeminit", MDBX_NOMEMINIT}, - {"coalesce", MDBX_COALESCE}, - {"lifo", MDBX_LIFORECLAIM}, - {"perturb", MDBX_PAGEPERTURB}, - {"accede", MDBX_ACCEDE}, - {nullptr, 0}}; - -const struct option_verb table_bits[] = { - {"key.reverse", MDBX_REVERSEKEY}, - {"key.integer", MDBX_INTEGERKEY}, - {"data.integer", MDBX_INTEGERDUP | MDBX_DUPFIXED | MDBX_DUPSORT}, - {"data.fixed", MDBX_DUPFIXED | MDBX_DUPSORT}, - {"data.reverse", MDBX_REVERSEDUP | MDBX_DUPSORT}, - {"data.dups", MDBX_DUPSORT}, - {nullptr, 0}}; - -static void dump_verbs(const char *caption, size_t bits, - const struct option_verb *verbs) { - log_verbose("%s: 0x%" PRIx64 " = ", caption, (uint64_t)bits); - - const char *comma = ""; - while (verbs->mask && bits) { - if ((bits & verbs->mask) == verbs->mask) { - logging::feed("%s%s", comma, verbs->verb); - bits -= verbs->mask; - comma = ", "; - } - ++verbs; - } - - logging::feed("%s\n", (*comma == '\0') ? "none" : ""); -} - -static void dump_duration(const char *caption, unsigned duration) { - log_verbose("%s: ", caption); - if (duration) { - if (duration > 24 * 3600) - logging::feed("%u_", duration / (24 * 3600)); - if (duration > 3600) - logging::feed("%02u:", (duration % (24 * 3600)) / 3600); - logging::feed("%02u:%02u", (duration % 3600) / 60, duration % 60); - } else { - logging::feed("INFINITE"); - } - logging::feed("\n"); -} - -void dump(const char *title) { - logging::local_suffix indent(title); - - for (auto i = global::actors.begin(); i != global::actors.end(); ++i) { - log_verbose("#%u, testcase %s, space_id/table %u\n", i->actor_id, - testcase2str(i->testcase), i->space_id); - indent.push(); - - if (i->params.loglevel) { - log_verbose("log: level %u, %s\n", i->params.loglevel, - i->params.pathname_log.empty() - ? "console" - : i->params.pathname_log.c_str()); - } - - log_verbose("database: %s, size %" PRIuPTR "[%" PRIiPTR "..%" PRIiPTR - ", %i %i, %i]\n", - i->params.pathname_db.c_str(), i->params.size_now, - i->params.size_lower, i->params.size_upper, - i->params.shrink_threshold, i->params.growth_step, - i->params.pagesize); - - dump_verbs("mode", i->params.mode_flags, mode_bits); - log_verbose("random-writemap: %s\n", - i->params.random_writemap ? "Yes" : "No"); - dump_verbs("table", i->params.table_flags, table_bits); - - if (i->params.test_nops) - log_verbose("iterations/records %u\n", i->params.test_nops); - else - dump_duration("duration", i->params.test_duration); - - if (i->params.nrepeat) - log_verbose("repeat %u\n", i->params.nrepeat); - else - log_verbose("repeat ETERNALLY\n"); - - log_verbose("threads %u\n", i->params.nthreads); - - log_verbose( - "keygen.params: case %s, width %u, mesh %u, rotate %u, offset %" PRIu64 - ", split %u/%u\n", - keygencase2str(i->params.keygen.keycase), i->params.keygen.width, - i->params.keygen.mesh, i->params.keygen.rotate, i->params.keygen.offset, - i->params.keygen.split, - i->params.keygen.width - i->params.keygen.split); - log_verbose("keygen.seed: %u\n", i->params.keygen.seed); - log_verbose("keygen.zerofill: %s\n", - i->params.keygen.zero_fill ? "Yes" : "No"); - log_verbose("key: minlen %u, maxlen %u\n", i->params.keylen_min, - i->params.keylen_max); - log_verbose("data: minlen %u, maxlen %u\n", i->params.datalen_min, - i->params.datalen_max); - - log_verbose("batch: read %u, write %u\n", i->params.batch_read, - i->params.batch_write); - - if (i->params.waitfor_nops) - log_verbose("wait: actor %u for %u ops\n", i->wait4id, - i->params.waitfor_nops); - else if (i->params.delaystart) - dump_duration("delay", i->params.delaystart); - else - log_verbose("no-delay\n"); - - if (i->params.inject_writefaultn) - log_verbose("inject-writefault on %u ops\n", - i->params.inject_writefaultn); - else - log_verbose("no-inject-writefault\n"); - - log_verbose("limits: readers %u, tables %u, txn-bytes %zu\n", - i->params.max_readers, i->params.max_tables, - mdbx_limits_txnsize_max(i->params.pagesize)); - - log_verbose("drop table: %s\n", i->params.drop_table ? "Yes" : "No"); - log_verbose("ignore MDBX_MAP_FULL error: %s\n", - i->params.ignore_dbfull ? "Yes" : "No"); - log_verbose("verifying by speculum: %s\n", - i->params.speculum ? "Yes" : "No"); - - indent.pop(); - } - - dump_duration("timeout", global::config::timeout_duration_seconds); - log_verbose("cleanup: before %s, after %s\n", - global::config::cleanup_before ? "Yes" : "No", - global::config::cleanup_after ? "Yes" : "No"); - - log_verbose("failfast: %s\n", global::config::failfast ? "Yes" : "No"); - log_verbose("progress indicator: %s\n", - global::config::progress_indicator ? "Yes" : "No"); - log_verbose("console mode: %s\n", - global::config::console_mode ? "Yes" : "No"); -} - -} /* namespace config */ - -//----------------------------------------------------------------------------- - -using namespace config; - -actor_config::actor_config(actor_testcase testcase, const actor_params ¶ms, - unsigned space_id, unsigned wait4id) - : actor_config_pod(1 + unsigned(global::actors.size()), testcase, space_id, - wait4id), - params(params) {} - -const std::string actor_config::serialize(const char *prefix) const { - simple_checksum checksum; - std::string result; - - if (prefix) - result.append(prefix); - - checksum.push(params.pathname_db); - result.append(params.pathname_db); - result.push_back('|'); - - checksum.push(params.pathname_log); - result.append(params.pathname_log); - result.push_back('|'); - - static_assert(std::is_trivially_copyable<actor_params_pod>::value, - "actor_params_pod should by POD"); - result.append(data2hex(static_cast<const actor_params_pod *>(¶ms), - sizeof(actor_params_pod), checksum)); - result.push_back('|'); - - static_assert(std::is_trivially_copyable<actor_config_pod>::value, - "actor_config_pod should by POD"); - result.append(data2hex(static_cast<const actor_config_pod *>(this), - sizeof(actor_config_pod), checksum)); - result.push_back('|'); - result.push_back(global::config::progress_indicator ? 'Y' : 'N'); - checksum.push(global::config::progress_indicator); - result.push_back(global::config::console_mode ? 'Y' : 'N'); - checksum.push(global::config::console_mode); - result.push_back('|'); - - result.append(osal_serialize(checksum)); - result.push_back('|'); - - result.append(std::to_string(checksum.value)); - return result; -} - -bool actor_config::deserialize(const char *str, actor_config &config) { - simple_checksum checksum; - - TRACE(">> actor_config::deserialize: %s\n", str); - - const char *slash = strchr(str, '|'); - if (!slash) { - TRACE("<< actor_config::deserialize: slash-1\n"); - return false; - } - config.params.pathname_db.assign(str, slash - str); - checksum.push(config.params.pathname_db); - str = slash + 1; - - slash = strchr(str, '|'); - if (!slash) { - TRACE("<< actor_config::deserialize: slash-2\n"); - return false; - } - config.params.pathname_log.assign(str, slash - str); - checksum.push(config.params.pathname_log); - str = slash + 1; - - slash = strchr(str, '|'); - if (!slash) { - TRACE("<< actor_config::deserialize: slash-3\n"); - return false; - } - static_assert(std::is_trivially_copyable<actor_params_pod>::value, - "actor_params_pod should by POD"); - if (!hex2data(str, slash, static_cast<actor_params_pod *>(&config.params), - sizeof(actor_params_pod), checksum)) { - TRACE("<< actor_config::deserialize: actor_params_pod(%.*s)\n", - (int)(slash - str), str); - return false; - } - str = slash + 1; - - slash = strchr(str, '|'); - if (!slash) { - TRACE("<< actor_config::deserialize: slash-4\n"); - return false; - } - static_assert(std::is_trivially_copyable<actor_config_pod>::value, - "actor_config_pod should by POD"); - if (!hex2data(str, slash, static_cast<actor_config_pod *>(&config), - sizeof(actor_config_pod), checksum)) { - TRACE("<< actor_config::deserialize: actor_config_pod(%.*s)\n", - (int)(slash - str), str); - return false; - } - str = slash + 1; - - slash = strchr(str, '|'); - if (!slash) { - TRACE("<< actor_config::deserialize: slash-5\n"); - return false; - } - if ((str[0] == 'Y' || str[0] == 'N') && (str[1] == 'Y' || str[1] == 'N')) { - global::config::progress_indicator = str[0] == 'Y'; - checksum.push(global::config::progress_indicator); - global::config::console_mode = str[1] == 'Y'; - checksum.push(global::config::console_mode); - str = slash + 1; - - slash = strchr(str, '|'); - if (!slash) { - TRACE("<< actor_config::deserialize: slash-6\n"); - return false; - } - } - - if (!config.osal_deserialize(str, slash, checksum)) { - TRACE("<< actor_config::deserialize: osal\n"); - return false; - } - str = slash + 1; - - uint64_t verify = std::stoull(std::string(str)); - if (checksum.value != verify) { - TRACE("<< actor_config::deserialize: checksum mismatch\n"); - return false; - } - - TRACE("<< actor_config::deserialize: OK\n"); - return true; -} - -unsigned actor_params::mdbx_keylen_min() const { - return (table_flags & MDBX_INTEGERKEY) ? 4 : 0; -} - -unsigned actor_params::mdbx_keylen_max() const { - return (unsigned)mdbx_limits_keysize_max(pagesize, table_flags); -} - -unsigned actor_params::mdbx_datalen_min() const { - return (table_flags & MDBX_INTEGERDUP) ? 4 : 0; -} - -unsigned actor_params::mdbx_datalen_max() const { - return std::min((unsigned)UINT16_MAX, - (unsigned)mdbx_limits_valsize_max(pagesize, table_flags)); -} diff --git a/libs/libmdbx/src/test/config.h b/libs/libmdbx/src/test/config.h deleted file mode 100644 index 5f0331291b..0000000000 --- a/libs/libmdbx/src/test/config.h +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright 2017-2020 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 "log.h" -#include "utils.h" - -#define ACTOR_ID_MAX INT16_MAX - -enum actor_testcase { - ac_none, - ac_hill, - ac_deadread, - ac_deadwrite, - ac_jitter, - ac_try, - ac_copy, - ac_append, - ac_ttl, - ac_nested -}; - -enum actor_status { - as_unknown, - as_debugging, - as_running, - as_successful, - as_killed, - as_failed, - as_coredump, -}; - -const char *testcase2str(const actor_testcase); -const char *status2str(actor_status status); - -enum keygen_case { - kc_random, /* [ 6.. 2.. 7.. 4.. 0.. 1.. 5.. 3.. ] */ - kc_dashes, /* [ 0123.. 4567.. ] */ - kc_custom, - /* TODO: more cases */ -}; - -const char *keygencase2str(const keygen_case); - -//----------------------------------------------------------------------------- - -namespace config { - -enum scale_mode { no_scale, decimal, binary, duration }; - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - const char **value, const char *default_value = nullptr); - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - std::string &value, bool allow_empty = false); - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - std::string &value, bool allow_empty, - const char *default_value); - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - bool &value); - -struct option_verb { - const char *const verb; - unsigned mask; -}; - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - unsigned &mask, const option_verb *verbs); - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - uint64_t &value, const scale_mode scale, - const uint64_t minval = 0, const uint64_t maxval = INT64_MAX, - const uint64_t default_value = 0); - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - unsigned &value, const scale_mode scale, - const unsigned minval = 0, const unsigned maxval = INT32_MAX, - const unsigned default_value = 0); - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - uint8_t &value, const uint8_t minval = 0, - const uint8_t maxval = 255, const uint8_t default_value = 0); - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - int64_t &value, const int64_t minval, const int64_t maxval, - const int64_t default_value = -1); - -bool parse_option(int argc, char *const argv[], int &narg, const char *option, - int32_t &value, const int32_t minval, const int32_t maxval, - const int32_t default_value = -1); - -inline bool parse_option_intptr(int argc, char *const argv[], int &narg, - const char *option, intptr_t &value, - const intptr_t minval, const intptr_t maxval, - const intptr_t default_value = -1) { - static_assert(sizeof(intptr_t) == 4 || sizeof(intptr_t) == 8, "WTF?"); - if (sizeof(intptr_t) == 8) - return parse_option(argc, argv, narg, option, - *reinterpret_cast<int64_t *>(&value), int64_t(minval), - int64_t(maxval), int64_t(default_value)); - else - return parse_option(argc, argv, narg, option, - *reinterpret_cast<int32_t *>(&value), int32_t(minval), - int32_t(maxval), int32_t(default_value)); -} - -//----------------------------------------------------------------------------- - -#pragma pack(push, 1) - -struct keygen_params_pod { - /* Параметры генератора пар key-value. Также может быть полезным описание - * алгоритма генерации в keygen.h - * - * Ключи и значения генерируются по задаваемым параметрам на основе "плоской" - * исходной координаты. При этом, в общем случае, в процессе тестов исходная - * координата последовательно итерируется в заданном диапазоне, а необходимые - * паттерны/последовательности/узоры получаются за счет преобразования - * исходной координаты, согласно описанным ниже параметрам. - * - * Стоит отметить, что порядок описания параметров для удобства совпадает с - * порядком их использования, т.е. с порядком соответствующих преобразований. - * - * Второе важное замечание касается ограничений одновременной координированной - * генерации паттеров как для ключей, так и для значений. Суть в том, что - * такая возможность не нужна по следующим причинам: - * - libmdbx поддерживает два существенно различающихся вида таблиц, - * "уникальные" (без дубликатов и без multi-value), и так называемые - * "с дубликатами" (c multi-value). - * - Для таблиц "без дубликатов" только размер связанных с ключами значений - * (данных) оказывает влияния на работу движка, непосредственно содержимое - * данных не анализируется движком и не оказывает влияния на его работу. - * - Для таблиц "с дубликатами", при наличии более одного значения для - * некоторого ключа, формируется дочернее btree-поддерево. Это дерево - * формируется во вложенной странице или отдельном "кусте" страниц, - * и обслуживается независимо от окружения родительского ключа. - * - Таким образом, паттерн генерации значений имеет смысл только для - * таблиц "с дубликатами" и только в контексте одного значения ключа. - * Иначе говоря, не имеет смысла взаимная координация при генерации - * значений для разных ключей. Поэтому генерацию значений следует - * рассматривать только в контексте связки с одним значением ключа. - * - Тем не менее, во всех случаях достаточно важным является равновероятное - * распределение всех возможных сочетаний длин ключей и данных. - * - * width: - * Большинство тестов предполагают создание или итерирование некоторого - * количества записей. При этом требуется итерирование или генерация - * значений и ключей из некоторого ограниченного пространства вариантов. - * - * Параметр width задает такую ширину пространства вариантов в битах. - * Таким образом мощность пространства вариантов (пока) всегда равна - * степени двойки. Это ограничение можно снять, но ценой увеличения - * вычислительной сложности, включая потерю простоты и прозрачности. - * - * С другой стороны, не-n-битовый width может быть полезен: - * - Позволит генерировать ключи/значения в точно задаваемом диапазоне. - * Например, перебрать в псевдо-случайном порядке 10001 значение. - * - Позволит поровну разделять заданное пространство (диапазон) - * ключей/значений между количеством потоков некратным степени двойки. - * - * mesh и seed: - * Позволяют получить псевдо-случайные последовательности ключей/значений. - * Параметр mesh задает сколько младших бит исходной плоской координаты - * будет "перемешано" (инъективно отображено), а параметр seed позволяет - * выбрать конкретный вариант "перемешивания". - * - * Перемешивание выполняется при ненулевом значении mesh. Перемешивание - * реализуется посредством применения двух инъективных функций для - * заданного количества бит: - * - применяется первая инъективная функция; - * - к результату добавляется salt полученный из seed; - * - применяется вторая инъективная функция; - * - * Следует отметить, что mesh умышленно позволяет перемешать только младшую - * часть, что при ненулевом значении split (см далее) не позволяет получать - * псевдо-случайные значений ключей без псевдо-случайности в значениях. - * - * Такое ограничение соответствуют внутренней алгоритмике libmdbx. Проще - * говоря, мы можем проверить движок псевдо-случайной последовательностью - * ключей на таблицах без дубликатов (без multi-value), а затем проверить - * корректность работу псевдо-случайной последовательностью значений на - * таблицах с дубликатами (с multi-value), опционально добавляя - * псевдо-случайности к последовательности ключей. Однако, нет смысла - * генерировать псевдо-случайные ключи, одновременно с формированием - * какого-либо паттерна в значениях, так как содержимое в данных либо - * не будет иметь значения (для таблиц без дубликатов), либо будет - * обрабатываться в отдельных btree-поддеревьях. - * - * rotate и offset: - * Для проверки слияния и разделения страниц внутри движка требуются - * генерация ключей/значений в виде не-смежных последовательностей, как-бы - * в виде "пунктира", который постепенно заполняет весь заданный диапазон. - * - * Параметры позволяют генерировать такой "пунктир". Соответственно rotate - * задает циклический сдвиг вправо, а offset задает смещение, точнее говоря - * сложение по модулю внутри диапазона заданного посредством width. - * - * Например, при rotate равном 1 (циклический сдвиг вправо на 1 бит), - * четные и нечетные исходные значения сложатся в две линейные - * последовательности, которые постепенно закроют старшую и младшую - * половины диапазона. - * - * split: - * Для таблиц без дубликатов (без multi-value ключей) фактически требуется - * генерация только ключей, а данные могут быть постоянным. Но для таблиц с - * дубликатами (с multi-value ключами) также требуется генерация значений. - * - * Ненулевое значение параметра split фактически включает генерацию значений, - * при этом значение split определяет сколько бит исходного абстрактного - * номера будет отрезано для генерации значения. - */ - - uint8_t width{0}; - uint8_t mesh{0}; - uint8_t rotate{0}; - uint8_t split{0}; - uint32_t seed{0}; - uint64_t offset{0}; - keygen_case keycase{kc_random}; - bool zero_fill{false}; -}; - -struct actor_params_pod { - unsigned mode_flags{0}; - unsigned table_flags{0}; - intptr_t size_lower{0}; - intptr_t size_now{0}; - intptr_t size_upper{0}; - int shrink_threshold{0}; - int growth_step{0}; - int pagesize{0}; - - unsigned test_duration{0}; - unsigned test_nops{0}; - unsigned nrepeat{0}; - unsigned nthreads{0}; - - unsigned keylen_min{0}, keylen_max{0}; - unsigned datalen_min{0}, datalen_max{0}; - - unsigned batch_read{0}; - unsigned batch_write{0}; - - unsigned delaystart{0}; - unsigned waitfor_nops{0}; - unsigned inject_writefaultn{0}; - - unsigned max_readers{0}; - unsigned max_tables{0}; - keygen_params_pod keygen; - - uint8_t loglevel{0}; - bool drop_table{false}; - bool ignore_dbfull{false}; - bool speculum{false}; - bool random_writemap{true}; -}; - -struct actor_config_pod { - unsigned actor_id{0}, space_id{0}; - actor_testcase testcase{ac_none}; - unsigned wait4id{0}; - unsigned signal_nops{0}; - - actor_config_pod() = default; - actor_config_pod(unsigned actor_id, actor_testcase testcase, - unsigned space_id, unsigned wait4id) - : actor_id(actor_id), space_id(space_id), testcase(testcase), - wait4id(wait4id) {} -}; - -#pragma pack(pop) - -extern const struct option_verb mode_bits[]; -extern const struct option_verb table_bits[]; -void dump(const char *title = "config-dump: "); - -} /* namespace config */ - -struct actor_params : public config::actor_params_pod { - std::string pathname_log; - std::string pathname_db; - actor_params() = default; - - void set_defaults(const std::string &tmpdir); - unsigned mdbx_keylen_min() const; - unsigned mdbx_keylen_max() const; - unsigned mdbx_datalen_min() const; - unsigned mdbx_datalen_max() const; -}; - -struct actor_config : public config::actor_config_pod { - actor_params params; - - bool wanna_event4signalling() const { return true /* TODO ? */; } - - actor_config() = default; - actor_config(actor_testcase testcase, const actor_params ¶ms, - unsigned space_id, unsigned wait4id); - - actor_config(const char *str) : actor_config() { - if (!deserialize(str, *this)) - failure("Invalid internal parameter '%s'\n", str); - } - - const std::string osal_serialize(simple_checksum &) const; - bool osal_deserialize(const char *str, const char *end, simple_checksum &); - - const std::string serialize(const char *prefix) const; - static bool deserialize(const char *str, actor_config &config); - - bool is_waitable(size_t nops) const { - switch (testcase) { - case ac_hill: - if (!params.test_nops || params.test_nops >= nops) - return true; - __fallthrough; - default: - return false; - } - } -}; diff --git a/libs/libmdbx/src/test/copy.cc b/libs/libmdbx/src/test/copy.cc deleted file mode 100644 index ff53153e1a..0000000000 --- a/libs/libmdbx/src/test/copy.cc +++ /dev/null @@ -1,26 +0,0 @@ -#include "test.h" - -void testcase_copy::copy_db(const bool with_compaction) { - int err = osal_removefile(copy_pathname); - if (err != MDBX_SUCCESS && err != MDBX_ENOFILE) - failure_perror("mdbx_removefile()", err); - - err = mdbx_env_copy(db_guard.get(), copy_pathname.c_str(), - with_compaction ? MDBX_CP_COMPACT : 0); - if (unlikely(err != MDBX_SUCCESS)) - failure_perror(with_compaction ? "mdbx_env_copy(MDBX_CP_COMPACT)" - : "mdbx_env_copy(MDBX_CP_ASIS)", - err); -} - -bool testcase_copy::run() { - jitter_delay(); - db_open(); - assert(!txn_guard); - const bool order = flipcoin(); - jitter_delay(); - copy_db(order); - jitter_delay(); - copy_db(!order); - return true; -} diff --git a/libs/libmdbx/src/test/darwin/LICENSE b/libs/libmdbx/src/test/darwin/LICENSE deleted file mode 100644 index 6a0dd3066b..0000000000 --- a/libs/libmdbx/src/test/darwin/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2015, Aleksey Demakov -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/libs/libmdbx/src/test/darwin/README.md b/libs/libmdbx/src/test/darwin/README.md deleted file mode 100644 index a6a8fd1a91..0000000000 --- a/libs/libmdbx/src/test/darwin/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# DarwinPthreadBarrier - -A pthread_barrier_t implementation for Mac OS/X - -There is no pthread_barrier_t in Mac OS/X pthreads. This project fixes -this omission by providing a simple-minded barrier implementation based -on a pair of pthread_mutex_t and pthread_cond_t. - diff --git a/libs/libmdbx/src/test/darwin/pthread_barrier.c b/libs/libmdbx/src/test/darwin/pthread_barrier.c deleted file mode 100644 index 054aa00708..0000000000 --- a/libs/libmdbx/src/test/darwin/pthread_barrier.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2015, Aleksey Demakov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "pthread_barrier.h" - -#include <errno.h> - -#ifdef __APPLE__ - -int pthread_barrierattr_init(pthread_barrierattr_t *attr) { - memset(attr, 0, sizeof(pthread_barrierattr_t)); - int m = pthread_mutexattr_init(&attr->mattr); - int c = pthread_condattr_init(&attr->cattr); - return m ? m : c; -} - -int pthread_barrierattr_destroy(pthread_barrierattr_t *attr) { - int c = pthread_condattr_destroy(&attr->cattr); - int m = pthread_mutexattr_destroy(&attr->mattr); - return m ? m : c; -} - -int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict attr, - int *__restrict pshared) { - return pthread_condattr_getpshared(&attr->cattr, pshared); -} - -int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) { - int m = pthread_mutexattr_setpshared(&attr->mattr, pshared); - int c = pthread_condattr_setpshared(&attr->cattr, pshared); - return m ? m : c; -} - -int pthread_barrier_init(pthread_barrier_t *__restrict barrier, - const pthread_barrierattr_t *__restrict attr, - unsigned count) { - if (count == 0) - return errno = EINVAL; - - int rc = pthread_mutex_init(&barrier->mutex, attr ? &attr->mattr : 0); - if (rc) - return rc; - - rc = pthread_cond_init(&barrier->cond, attr ? &attr->cattr : 0); - if (rc) { - int errno_save = errno; - pthread_mutex_destroy(&barrier->mutex); - errno = errno_save; - return rc; - } - - barrier->limit = count; - barrier->count = 0; - barrier->phase = 0; - return 0; -} - -int pthread_barrier_destroy(pthread_barrier_t *barrier) { - pthread_mutex_destroy(&barrier->mutex); - pthread_cond_destroy(&barrier->cond); - return 0; -} - -int pthread_barrier_wait(pthread_barrier_t *barrier) { - int rc = pthread_mutex_lock(&barrier->mutex); - if (rc) - return rc; - - barrier->count++; - if (barrier->count >= barrier->limit) { - barrier->phase++; - barrier->count = 0; - pthread_cond_broadcast(&barrier->cond); - pthread_mutex_unlock(&barrier->mutex); - return PTHREAD_BARRIER_SERIAL_THREAD; - } else { - unsigned phase = barrier->phase; - do - pthread_cond_wait(&barrier->cond, &barrier->mutex); - while (phase == barrier->phase); - pthread_mutex_unlock(&barrier->mutex); - return 0; - } -} - -#endif /* __APPLE__ */ diff --git a/libs/libmdbx/src/test/darwin/pthread_barrier.h b/libs/libmdbx/src/test/darwin/pthread_barrier.h deleted file mode 100644 index efa9b9b751..0000000000 --- a/libs/libmdbx/src/test/darwin/pthread_barrier.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2015, Aleksey Demakov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PTHREAD_BARRIER_H -#define PTHREAD_BARRIER_H - -#include <pthread.h> - -#ifdef __APPLE__ - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(PTHREAD_BARRIER_SERIAL_THREAD) -#define PTHREAD_BARRIER_SERIAL_THREAD (1) -#endif - -#if !defined(PTHREAD_PROCESS_PRIVATE) -#define PTHREAD_PROCESS_PRIVATE (42) -#endif -#if !defined(PTHREAD_PROCESS_SHARED) -#define PTHREAD_PROCESS_SHARED (43) -#endif - -typedef struct { - pthread_mutexattr_t mattr; - pthread_condattr_t cattr; -} pthread_barrierattr_t; - -typedef struct { - pthread_mutex_t mutex; - pthread_cond_t cond; - unsigned int limit; - unsigned int count; - unsigned int phase; -} pthread_barrier_t; - -int pthread_barrierattr_init(pthread_barrierattr_t *attr); -int pthread_barrierattr_destroy(pthread_barrierattr_t *attr); - -int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict attr, - int *__restrict pshared); -int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared); - -int pthread_barrier_init(pthread_barrier_t *__restrict barrier, - const pthread_barrierattr_t *__restrict attr, - unsigned int count); -int pthread_barrier_destroy(pthread_barrier_t *barrier); - -int pthread_barrier_wait(pthread_barrier_t *barrier); - -#ifdef __cplusplus -} -#endif - -#endif /* __APPLE__ */ - -#endif /* PTHREAD_BARRIER_H */ diff --git a/libs/libmdbx/src/test/dead.cc b/libs/libmdbx/src/test/dead.cc deleted file mode 100644 index 97f326a2f4..0000000000 --- a/libs/libmdbx/src/test/dead.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2017-2020 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_deadread::run() { - db_open(); - txn_begin(true); - cursor_guard.reset(); - txn_guard.reset(); - db_guard.reset(); - return true; -} - -//----------------------------------------------------------------------------- - -bool testcase_deadwrite::run() { - db_open(); - txn_begin(false); - cursor_guard.reset(); - txn_guard.reset(); - db_guard.reset(); - return true; -} diff --git a/libs/libmdbx/src/test/dump-load.sh b/libs/libmdbx/src/test/dump-load.sh deleted file mode 100644 index 55fa5c7f33..0000000000 --- a/libs/libmdbx/src/test/dump-load.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash - -echo "------------------------------------------------------------------------------" - -if [ -z "$1" ]; then - echo "No mdbx-db pathname given"; - exit 2 -elif [ ! -e "$1" ]; then - echo "The mdbx-db '$1' don't exists"; - exit 2 -else - echo ">>>>>>>>>> $1" - RECO="$1.recovered" - rm -f dump1.txt dump2.txt "$RECO" - if ./mdbx_chk "$1"; then - echo ">>>>>>>>>> SOURCE VALID" - (./mdbx_dump -a "$1" > dump1.txt && \ - ./mdbx_load -nf dump1.txt "$RECO" && \ - ./mdbx_chk "$RECO" && \ - echo ">>>>>>>>>> DUMP/LOAD/CHK OK") || (echo ">>>>>>>>>> DUMP/LOAD/CHK FAILED"; exit 1) - REMOVE_RECO=1 - elif ./mdbx_chk -i "$1"; then - echo ">>>>>>>>>> SOURCE HAS WRONG-ORDER, TRY RECOVERY" - (./mdbx_dump -a "$1" > dump1.txt && \ - ./mdbx_load -anf dump1.txt "$RECO" && \ - ./mdbx_chk -i "$RECO" && \ - echo ">>>>>>>>>> DUMP/LOAD/CHK OK") || (echo ">>>>>>>>>> DUMP/LOAD/CHK FAILED"; exit 1) - REMOVE_RECO=0 - else - echo ">>>>>>>>>> SOURCE CORRUPTED, TRY RECOVERY" - (./mdbx_dump -ar "$1" > dump1.txt && \ - ./mdbx_load -ranf dump1.txt "$RECO" && \ - ./mdbx_chk -i "$RECO" && \ - echo ">>>>>>>>>> DUMP/LOAD/CHK OK") || (echo ">>>>>>>>>> DUMP/LOAD/CHK FAILED"; exit 1) - REMOVE_RECO=0 - fi - ./mdbx_dump -a "$RECO" > dump2.txt && diff -u dump1.txt dump2.txt && \ - rm -f dump1.txt dump2.txt && [ $REMOVE_RECO -ne 0 ] && rm -f "$RECO" - exit 0 -fi diff --git a/libs/libmdbx/src/test/hill.cc b/libs/libmdbx/src/test/hill.cc deleted file mode 100644 index efc43abe2a..0000000000 --- a/libs/libmdbx/src/test/hill.cc +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright 2017-2020 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::run() { - int err = db_open__begin__table_create_open_clean(dbi); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("hill: bailout-prepare due '%s'", mdbx_strerror(err)); - return false; - } - speculum.clear(); - speculum_commited.clear(); - - /* LY: тест "холмиком": - * - сначала наполняем таблицу циклическими CRUD-манипуляциями, - * которые в каждом цикле делают несколько операций, включая удаление, - * но в результате добавляют записи. - * - затем очищаем таблицу также CRUD-манипуляциями, но уже с другой - * пропорцией удалений. - * - * При этом очень многое зависит от порядка перебора ключей: - * - (псевдо)случайное распределение требуется лишь для полноты картины, - * но в целом не покрывает важных кейсов. - * - кроме (псевдо)случайного перебора требуется последовательное - * итерирование ключей интервалами различной ширины, с тем чтобы - * проверить различные варианты как разделения, так и слияния страниц - * внутри движка. - * - при не-уникальных ключах (MDBX_DUPSORT с подвариантами), для каждого - * повтора внутри движка формируется вложенное btree-дерево, - * соответственно требуется соблюдение аналогичных принципов - * итерирования для значений. - */ - - /* TODO: работа в несколько потоков */ - keyvalue_maker.setup(config.params, config.actor_id, 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); - - 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; - - uint64_t serial_count = 0; - uint64_t commited_serial = serial_count; - unsigned txn_nops = 0; - - bool rc = false; - while (should_continue()) { - const keygen::serial_t a_serial = serial_count; - if (unlikely(!keyvalue_maker.increment(serial_count, 1))) { - log_notice("uphill: unexpected key-space overflow"); - break; - } - - 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); - - err = insert(a_key, a_data_1, insert_flags); - if (unlikely(err != MDBX_SUCCESS)) { - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - log_notice("uphill: bailout at insert-a due '%s'", mdbx_strerror(err)); - txn_restart(true, false); - serial_count = commited_serial; - speculum = speculum_commited; - break; - } - failure_perror("mdbx_put(insert-a.1)", err); - } - if (!speculum_verify()) { - log_notice("uphill: bailout after insert-a, before commit"); - goto bailout; - } - - if (++txn_nops >= config.params.batch_write) { - err = breakable_restart(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("uphill: bailout at commit due '%s'", mdbx_strerror(err)); - serial_count = commited_serial; - speculum = speculum_commited; - break; - } - speculum_commited = speculum; - commited_serial = a_serial; - txn_nops = 0; - if (!speculum_verify()) { - log_notice("uphill: bailout after insert-a, after commit"); - goto bailout; - } - } - - // создаем вторую запись из пары - log_trace("uphill: insert-b %" PRIu64, b_serial); - generate_pair(b_serial, b_key, b_data, 0); - err = insert(b_key, b_data, insert_flags); - if (unlikely(err != MDBX_SUCCESS)) { - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - log_notice("uphill: bailout at insert-b due '%s'", mdbx_strerror(err)); - txn_restart(true, false); - serial_count = commited_serial; - speculum = speculum_commited; - break; - } - failure_perror("mdbx_put(insert-b)", err); - } - if (!speculum_verify()) { - log_notice("uphill: bailout after insert-b, before commit"); - goto bailout; - } - - if (++txn_nops >= config.params.batch_write) { - err = breakable_restart(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("uphill: bailout at commit due '%s'", mdbx_strerror(err)); - serial_count = commited_serial; - speculum = speculum_commited; - break; - } - speculum_commited = speculum; - commited_serial = a_serial; - txn_nops = 0; - if (!speculum_verify()) { - log_notice("uphill: bailout after insert-b, after commit"); - goto bailout; - } - } - - // обновляем данные в первой записи - log_trace("uphill: update-a (age %" PRIu64 "->0) %" PRIu64, age_shift, - a_serial); - generate_pair(a_serial, a_key, a_data_0, 0); - checkdata("uphill: update-a", dbi, a_key->value, a_data_1->value); - err = replace(a_key, a_data_0, a_data_1, update_flags); - if (unlikely(err != MDBX_SUCCESS)) { - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - log_notice("uphill: bailout at update-a due '%s'", mdbx_strerror(err)); - txn_restart(true, false); - serial_count = commited_serial; - speculum = speculum_commited; - break; - } - failure_perror("mdbx_replace(update-a: 1->0)", err); - } - if (!speculum_verify()) { - log_notice("uphill: bailout after update-a, before commit"); - goto bailout; - } - - if (++txn_nops >= config.params.batch_write) { - err = breakable_restart(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("uphill: bailout at commit due '%s'", mdbx_strerror(err)); - serial_count = commited_serial; - speculum = speculum_commited; - break; - } - speculum_commited = speculum; - commited_serial = a_serial; - txn_nops = 0; - if (!speculum_verify()) { - log_notice("uphill: bailout after update-a, after commit"); - goto bailout; - } - } - - // удаляем вторую запись - log_trace("uphill: delete-b %" PRIu64, b_serial); - checkdata("uphill: delete-b", dbi, b_key->value, b_data->value); - err = remove(b_key, b_data); - if (unlikely(err != MDBX_SUCCESS)) { - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - log_notice("uphill: bailout at delete-b due '%s'", mdbx_strerror(err)); - txn_restart(true, false); - serial_count = commited_serial; - speculum = speculum_commited; - break; - } - failure_perror("mdbx_del(b)", err); - } - if (!speculum_verify()) { - log_notice("uphill: bailout after delete-b, before commit"); - goto bailout; - } - - if (++txn_nops >= config.params.batch_write) { - err = breakable_restart(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("uphill: bailout at commit due '%s'", mdbx_strerror(err)); - serial_count = commited_serial; - speculum = speculum_commited; - break; - } - speculum_commited = speculum; - commited_serial = a_serial; - txn_nops = 0; - if (!speculum_verify()) { - log_notice("uphill: bailout after delete-b, after commit"); - goto bailout; - } - } - - report(1); - if (!keyvalue_maker.increment(serial_count, 1)) { - // дошли до границы пространства ключей - serial_count = a_serial; - goto overflow; - } - } - - if (txn_guard) { - MDBX_stat stat; - err = mdbx_dbi_stat(txn_guard.get(), dbi, &stat, sizeof(stat)); - if (unlikely(err != MDBX_SUCCESS)) - failure_perror("mdbx_dbi_stat()", err); - - uint32_t nested_deepmask; - err = mdbx_dbi_dupsort_depthmask(txn_guard.get(), dbi, &nested_deepmask); - if (unlikely(err != MDBX_SUCCESS && err != MDBX_RESULT_TRUE)) - failure_perror("mdbx_dbi_stat_nested_deepmask()", err); - - if (err != MDBX_SUCCESS) { - log_notice("hill: reached %d tree depth", stat.ms_depth); - } else { - std::string str; - int prev = -2, i = 0; - do { - while (!(nested_deepmask & 1)) - ++i, nested_deepmask >>= 1; - if (prev + 1 == i) { - if (str.back() != '-') - str.push_back('-'); - prev = i; - continue; - } - if (!str.empty()) { - if (str.back() == '-') - str.append(std::to_string(prev)); - str.push_back(','); - } - str.append(std::to_string(i)); - prev = i; - } while (++i, nested_deepmask >>= 1); - if (str.back() == '-') - str.append(std::to_string(prev)); - - log_notice("hill: reached %d tree depth & %s sub-tree depth(s)", - stat.ms_depth, str.c_str()); - } - } - - while (serial_count > 1) { - 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); - checkdata("downhill: update-a", dbi, a_key->value, a_data_0->value); - err = replace(a_key, a_data_1, a_data_0, update_flags); - if (unlikely(err != MDBX_SUCCESS)) { - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - log_notice("downhill: bailout at update-a due '%s'", - mdbx_strerror(err)); - txn_end(true); - speculum = speculum_commited; - break; - } - failure_perror("mdbx_put(update-a: 0->1)", err); - } - if (!speculum_verify()) { - log_notice("downhill: bailout after update-a, before commit"); - break; - } - - if (++txn_nops >= config.params.batch_write) { - err = breakable_restart(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("downhill: bailout at commit due '%s'", mdbx_strerror(err)); - speculum = speculum_commited; - break; - } - speculum_commited = speculum; - txn_nops = 0; - if (!speculum_verify()) { - log_notice("downhill: bailout after update-a, after commit"); - break; - } - } - - // создаем вторую запись из пары - log_trace("downhill: insert-b %" PRIu64, b_serial); - generate_pair(b_serial, b_key, b_data, 0); - err = insert(b_key, b_data, insert_flags); - if (unlikely(err != MDBX_SUCCESS)) { - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - log_notice("downhill: bailout at insert-a due '%s'", - mdbx_strerror(err)); - txn_end(true); - speculum = speculum_commited; - break; - } - failure_perror("mdbx_put(insert-b)", err); - } - if (!speculum_verify()) { - log_notice("downhill: bailout after insert-b, before commit"); - break; - } - - if (++txn_nops >= config.params.batch_write) { - err = breakable_restart(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("downhill: bailout at commit due '%s'", mdbx_strerror(err)); - speculum = speculum_commited; - break; - } - speculum_commited = speculum; - txn_nops = 0; - if (!speculum_verify()) { - log_notice("downhill: bailout after insert-b, after commit"); - break; - } - } - - // удаляем первую запись - log_trace("downhill: delete-a (age %" PRIu64 ") %" PRIu64, age_shift, - a_serial); - checkdata("downhill: delete-a", dbi, a_key->value, a_data_1->value); - err = remove(a_key, a_data_1); - if (unlikely(err != MDBX_SUCCESS)) { - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - log_notice("downhill: bailout at delete-a due '%s'", - mdbx_strerror(err)); - txn_end(true); - speculum = speculum_commited; - break; - } - failure_perror("mdbx_del(a)", err); - } - if (!speculum_verify()) { - log_notice("downhill: bailout after delete-a, before commit"); - break; - } - - if (++txn_nops >= config.params.batch_write) { - err = breakable_restart(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("downhill: bailout at commit due '%s'", mdbx_strerror(err)); - speculum = speculum_commited; - break; - } - speculum_commited = speculum; - txn_nops = 0; - if (!speculum_verify()) { - log_notice("downhill: bailout after delete-a, after commit"); - break; - } - } - - // удаляем вторую запись - log_trace("downhill: delete-b %" PRIu64, b_serial); - checkdata("downhill: delete-b", dbi, b_key->value, b_data->value); - err = remove(b_key, b_data); - if (unlikely(err != MDBX_SUCCESS)) { - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - log_notice("downhill: bailout at delete-b due '%s'", - mdbx_strerror(err)); - txn_end(true); - speculum = speculum_commited; - break; - } - failure_perror("mdbx_del(b)", err); - } - if (!speculum_verify()) { - log_notice("downhill: bailout after delete-b, before commit"); - break; - } - - if (++txn_nops >= config.params.batch_write) { - err = breakable_restart(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("downhill: bailout at commit due '%s'", mdbx_strerror(err)); - speculum = speculum_commited; - break; - } - speculum_commited = speculum; - txn_nops = 0; - if (!speculum_verify()) { - log_notice("downhill: bailout after delete-b, after commit"); - goto bailout; - } - } - - report(1); - } - - rc = speculum_verify(); -bailout: - if (txn_guard) { - err = breakable_commit(); - if (unlikely(err != MDBX_SUCCESS)) - log_notice("downhill: bailout at commit due '%s'", mdbx_strerror(err)); - } - - if (dbi) { - if (config.params.drop_table && !mode_readonly()) { - txn_begin(false); - db_table_drop(dbi); - err = breakable_commit(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("hill: bailout-clean due '%s'", mdbx_strerror(err)); - return rc; - } - } else - db_table_close(dbi); - } - return rc; -} diff --git a/libs/libmdbx/src/test/jitter.cc b/libs/libmdbx/src/test/jitter.cc deleted file mode 100644 index 71d58699de..0000000000 --- a/libs/libmdbx/src/test/jitter.cc +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2017-2020 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_jitter::run() { - int err; - size_t upper_limit = config.params.size_upper; - if (upper_limit < 1) - upper_limit = config.params.size_now * 2; - - while (should_continue()) { - jitter_delay(); - db_open(); - - if (upper_limit < 1) { - MDBX_envinfo info; - err = mdbx_env_info_ex(db_guard.get(), txn_guard.get(), &info, - sizeof(info)); - if (err) - failure_perror("mdbx_env_info_ex()", err); - upper_limit = (info.mi_geo.upper < INTPTR_MAX) - ? (intptr_t)info.mi_geo.upper - : INTPTR_MAX; - } - - if (flipcoin()) { - jitter_delay(); - txn_begin(true); - fetch_canary(); - jitter_delay(); - txn_end(flipcoin()); - } - - const bool coin4size = flipcoin(); - jitter_delay(); - txn_begin(mode_readonly()); - jitter_delay(); - if (!mode_readonly()) { - fetch_canary(); - update_canary(1); - err = mdbx_env_set_geometry( - db_guard.get(), -1, -1, - coin4size ? upper_limit * 2 / 3 : upper_limit * 3 / 2, -1, -1, -1); - if (err != MDBX_SUCCESS && err != MDBX_UNABLE_EXTEND_MAPSIZE && - err != MDBX_MAP_FULL && err != MDBX_TOO_LARGE) - failure_perror("mdbx_env_set_geometry-1", err); - } - txn_end(flipcoin()); - - err = mdbx_env_set_geometry( - db_guard.get(), -1, -1, - !coin4size ? upper_limit * 2 / 3 : upper_limit * 3 / 2, -1, -1, -1); - if (err != MDBX_SUCCESS && err != MDBX_UNABLE_EXTEND_MAPSIZE && - err != MDBX_MAP_FULL && err != MDBX_TOO_LARGE) - failure_perror("mdbx_env_set_geometry-2", err); - - if (flipcoin()) { - jitter_delay(); - txn_begin(true); - jitter_delay(); - txn_end(flipcoin()); - } - - jitter_delay(); - err = - mdbx_env_set_geometry(db_guard.get(), -1, -1, upper_limit, -1, -1, -1); - if (err != MDBX_SUCCESS && err != MDBX_UNABLE_EXTEND_MAPSIZE && - err != MDBX_MAP_FULL && err != MDBX_TOO_LARGE) - failure_perror("mdbx_env_set_geometry-3", err); - - db_close(); - - /* just 'align' nops with other tests with batching */ - const auto batching = - std::max(config.params.batch_read, config.params.batch_write); - report(std::max(1u, batching / 2)); - } - return true; -} diff --git a/libs/libmdbx/src/test/keygen.cc b/libs/libmdbx/src/test/keygen.cc deleted file mode 100644 index 05070afe02..0000000000 --- a/libs/libmdbx/src/test/keygen.cc +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright 2017-2020 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 + 1] = { - /* 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, - 4613509448041658233, 4952535426879925961}; - static const uint8_t s[64 - serial_minwith + 1] = { - /* 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, 20, - 19}; - - const auto mult = m[bits - 8]; - const auto shift = s[bits - 8]; - serial_t result = serial * mult; - if (salt) { - const unsigned left = bits / 2; - const unsigned right = bits - left; - result = (result << left) | ((result & mask(bits)) >> right); - result = (result ^ salt) * mult; - } - - result ^= result << shift; - result &= mask(bits); - log_trace("keygen-injective: serial %" PRIu64 "/%u @%" PRIx64 ",%u,%" PRIu64 - " => %" PRIu64 "/%u", - serial, bits, mult, shift, salt, result, bits); - return result; -} - -void __hot maker::pair(serial_t serial, const buffer &key, buffer &value, - serial_t value_age, const bool keylen_changeable) { - 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 & ~(essentials::prng_fill_flag | MDBX_INTEGERKEY | - MDBX_REVERSEKEY | MDBX_DUPSORT))); - assert(!(value_essentials.flags & - ~(essentials::prng_fill_flag | MDBX_INTEGERDUP | MDBX_REVERSEDUP))); - - 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@%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); - log_trace("keygen-pair: rotate@%u => %" PRIu64 ", 0x%" PRIx64, - mapping.rotate, serial, serial); - } - - if (mapping.offset) { - serial = (serial + mapping.offset) & mask(mapping.width); - log_trace("keygen-pair: offset@%" PRIu64 " => %" PRIu64, mapping.offset, - serial); - } - if (base) { - serial += base; - log_trace("keygen-pair: base@%" PRIu64 " => %" PRIu64, base, serial); - } - - serial_t key_serial = serial; - serial_t value_serial = value_age << mapping.split; - if (mapping.split) { - if (key_essentials.flags & MDBX_DUPSORT) { - key_serial >>= mapping.split; - value_serial += serial & mask(mapping.split); - } else { - /* Без MDBX_DUPSORT требуется уникальность ключей, а для этого нельзя - * отбрасывать какие-либо биты serial после инъективного преобразования. - * Поэтому key_serial не трогаем, а в value_serial нелинейно вмешиваем - * запрошенное количество бит из serial */ - value_serial += - (serial ^ (serial >> mapping.split)) & mask(mapping.split); - } - - value_serial |= value_age << mapping.split; - log_trace("keygen-pair: split@%u => k%" PRIu64 ", v%" PRIu64, mapping.split, - key_serial, value_serial); - } - - log_trace("keygen-pair: key %" PRIu64 ", value %" PRIu64, key_serial, - value_serial); - mk_begin(key_serial, key_essentials, *key); - mk_begin(value_serial, value_essentials, *value); - -#if 0 /* unused for now */ - if (key->value.iov_len + value->value.iov_len > pair_maxlen) { - unsigned extra = key->value.iov_len + value->value.iov_len - pair_maxlen; - if (keylen_changeable && - key->value.iov_len > std::max(8u, (unsigned)key_essentials.minlen)) { -#if defined(__GNUC__) || defined(__clang__) - const bool coin = __builtin_parityll(serial) != 0; -#else - const bool coin = INT64_C(0xF2CEECA9989BD96A) * int64_t(serial) < 0; -#endif - if (coin) { - const unsigned gap = - key->value.iov_len - std::max(8u, (unsigned)key_essentials.minlen); - const unsigned chop = std::min(gap, extra); - log_trace("keygen-pair: chop %u key-len %u -> %u", chop, - (unsigned)key->value.iov_len, - (unsigned)key->value.iov_len - chop); - key->value.iov_len -= chop; - extra -= chop; - } - } - if (extra && value->value.iov_len > - std::max(8u, (unsigned)value_essentials.minlen)) { - const unsigned gap = value->value.iov_len - - std::max(8u, (unsigned)value_essentials.minlen); - const unsigned chop = std::min(gap, extra); - log_trace("keygen-pair: chop %u value-len %u -> %u", chop, - (unsigned)value->value.iov_len, - (unsigned)value->value.iov_len - chop); - value->value.iov_len -= chop; - extra -= chop; - } - if (keylen_changeable && extra && - key->value.iov_len > std::max(8u, (unsigned)key_essentials.minlen)) { - const unsigned gap = - key->value.iov_len - std::max(8u, (unsigned)key_essentials.minlen); - const unsigned chop = std::min(gap, extra); - log_trace("keygen-pair: chop %u key-len %u -> %u", chop, - (unsigned)key->value.iov_len, - (unsigned)key->value.iov_len - chop); - key->value.iov_len -= chop; - extra -= chop; - } - } -#else - (void)keylen_changeable; -#endif /* unused for now */ - - mk_continue(key_serial, key_essentials, *key); - mk_continue(value_serial, value_essentials, *value); - - if (log_enabled(logging::trace)) { - char dump_key[4096], dump_value[4096]; - log_trace("keygen-pair: key %s, value %s", - mdbx_dump_val(&key->value, dump_key, sizeof(dump_key)), - mdbx_dump_val(&value->value, dump_value, sizeof(dump_value))); - } -} - -void maker::setup(const config::actor_params_pod &actor, unsigned actor_id, - unsigned thread_number) { - key_essentials.flags = - actor.table_flags & (MDBX_INTEGERKEY | MDBX_REVERSEKEY | MDBX_DUPSORT); - assert(actor.keylen_min <= UINT16_MAX); - key_essentials.minlen = (uint16_t)actor.keylen_min; - assert(actor.keylen_max <= UINT32_MAX); - key_essentials.maxlen = std::min( - (uint32_t)actor.keylen_max, - (uint32_t)mdbx_limits_keysize_max(actor.pagesize, key_essentials.flags)); - - value_essentials.flags = - actor.table_flags & (MDBX_INTEGERDUP | MDBX_REVERSEDUP); - assert(actor.datalen_min <= UINT16_MAX); - value_essentials.minlen = (uint16_t)actor.datalen_min; - assert(actor.datalen_max <= UINT32_MAX); - value_essentials.maxlen = std::min( - (uint32_t)actor.datalen_max, - (uint32_t)mdbx_limits_valsize_max(actor.pagesize, key_essentials.flags)); - - if (!actor.keygen.zero_fill) { - key_essentials.flags |= essentials::prng_fill_flag; - value_essentials.flags |= essentials::prng_fill_flag; - } - - (void)thread_number; - mapping = actor.keygen; - salt = (actor.keygen.seed + actor_id) * UINT64_C(14653293970879851569); - - // FIXME: TODO - base = 0; -} - -void maker::make_ordered() { - mapping.mesh = 0; - mapping.rotate = 0; -} - -bool maker::is_unordered() const { - return (mapping.mesh >= serial_minwith || mapping.rotate) != 0; -} - -bool maker::increment(serial_t &serial, int delta) const { - 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) || - ((delta > 0) ? target < serial : target > serial)) { - 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; -} - -//----------------------------------------------------------------------------- - -static 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_begin(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_len = - (params.maxlen > params.minlen) - ? params.minlen + serial % (params.maxlen - params.minlen) - : params.minlen; - - if ((params.flags & (MDBX_INTEGERKEY | MDBX_INTEGERDUP)) == 0 && - out.value.iov_len < 8) - out.value.iov_len = std::max(length(serial), out.value.iov_len); -} - -void __hot maker::mk_continue(const serial_t serial, const essentials ¶ms, - result &out) { - static_assert((essentials::prng_fill_flag & - (MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERKEY | - MDBX_INTEGERDUP | MDBX_REVERSEKEY | MDBX_REVERSEDUP)) == 0, - "WTF?"); - out.value.iov_base = out.bytes; - 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) { - if (params.flags & essentials::prng_fill_flag) { - uint64_t state = serial ^ UINT64_C(0x41803711c9b75f19); - prng_fill(state, out.bytes, out.value.iov_len - 8); - } else - 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_base = out.bytes + 8 - out.value.iov_len; - } - } else { - out.u64 = htole64(serial); - if (out.value.iov_len > 8) { - if (params.flags & essentials::prng_fill_flag) { - uint64_t state = serial ^ UINT64_C(0x923ab47b7ee6f6e4); - prng_fill(state, out.bytes + 8, out.value.iov_len - 8); - } else - memset(out.bytes + 8, '\0', out.value.iov_len - 8); - } - } - - 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 */ diff --git a/libs/libmdbx/src/test/keygen.h b/libs/libmdbx/src/test/keygen.h deleted file mode 100644 index c36cc1a2e7..0000000000 --- a/libs/libmdbx/src/test/keygen.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2017-2020 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 не имеет значения: - * - используемый алфавит (значения байтов); - * - частотное распределение по алфавиту; - * - абсолютное значение ключей или разность между отдельными значениями; - * - * Соответственно, в общих чертах, схема генерации следующая: - * - вводится плоская одномерная "координата" serial (uint64_t); - * - генерация специфических паттернов (последовательностей) - * реализуется посредством соответствующих преобразований "координат", при - * этом все подобные преобразования выполняются только над "координатой"; - * - итоговая "координата" преобразуется в 8-байтное суррогатное значение - * ключа; - * - для получения ключей длиной МЕНЕЕ 8 байт суррогат может усекаться - * до ненулевых байт, в том числе до нулевой длины; - * - для получения ключей длиной БОЛЕЕ 8 байт суррогат дополняется - * нулями или псевдослучайной последовательностью; - * - * Механизм генерации паттернов: - * - реализованный механизм является компромиссом между скоростью/простотой - * и гибкостью, необходимой для получения последовательностей, которых - * будет достаточно для проверки сценариев разделения и слияния страниц - * с данными внутри mdbx; - * - псевдо-случайные паттерны реализуются посредством набора инъективных - * отображающих функций; - * - не-псевдо-случайные паттерны реализуются посредством параметризируемого - * трех-этапного преобразования: - * 1) смещение (сложение) по модулю; - * 2) циклический сдвиг; - * 3) добавление абсолютного смещения (базы); - * - * Также см. описание параметров генератора ключей и значений в config.h */ - -typedef uint64_t serial_t; - -enum : serial_t { - serial_minwith = 8, - serial_maxwith = sizeof(serial_t) * 8, - serial_allones = ~(serial_t)0u -}; - -struct result { - 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); - } -}; - -//----------------------------------------------------------------------------- - -struct buffer_deleter /* : public std::unary_function<void, result *> */ { - 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}; - - struct essentials { - uint16_t minlen{0}; - enum { prng_fill_flag = 1 }; - uint16_t flags{0}; - uint32_t maxlen{0}; - } key_essentials, value_essentials; - - static void mk_begin(const serial_t serial, const essentials ¶ms, - result &out); - static void mk_continue(const serial_t serial, const essentials ¶ms, - result &out); - static void mk(const serial_t serial, const essentials ¶ms, result &out) { - mk_begin(serial, params, out); - mk_continue(serial, params, out); - } - -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 actor_id, - unsigned thread_number); - void make_ordered(); - bool is_unordered() const; - - bool increment(serial_t &serial, int delta) const; -}; - -} /* namespace keygen */ diff --git a/libs/libmdbx/src/test/log.cc b/libs/libmdbx/src/test/log.cc deleted file mode 100644 index f568e774fc..0000000000 --- a/libs/libmdbx/src/test/log.cc +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright 2017-2020 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" - -static void fflushall() { fflush(nullptr); } - -void failure(const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - fflushall(); - logging::output_nocheckloglevel_ap(logging::failure, fmt, ap); - va_end(ap); - fflushall(); - exit(EXIT_FAILURE); -} - -const char *test_strerror(int errnum) { - static __thread char buf[1024]; - return mdbx_strerror_r(errnum, buf, sizeof(buf)); -} - -void __noreturn failure_perror(const char *what, int errnum) { - failure("%s failed: %s (%d)\n", what, test_strerror(errnum), errnum); -} - -//----------------------------------------------------------------------------- - -static void mdbx_logger(int priority, const char *function, int line, - const char *msg, va_list args) { - if (!function) - function = "unknown"; - - if (priority == MDBX_LOG_FATAL) - log_error("mdbx: fatal failure: %s, %d", function, line); - - logging::output_nocheckloglevel( - logging::loglevel(priority), - strncmp(function, "mdbx_", 5) == 0 ? "%s: " : "mdbx %s: ", function); - logging::feed_ap(msg, args); -} - -namespace logging { - -static std::string prefix; -static std::string suffix; -static loglevel level; -static FILE *last; - -void setlevel(loglevel priority) { - level = priority; - int rc = mdbx_setup_debug(priority, - MDBX_DBG_ASSERT | MDBX_DBG_AUDIT | MDBX_DBG_JITTER, - mdbx_logger); - log_trace("set mdbx debug-opts: 0x%02x", rc); -} - -void setup(loglevel priority, const std::string &_prefix) { - setlevel(priority); - prefix = _prefix; -} - -void setup(const std::string &_prefix) { prefix = _prefix; } - -const char *level2str(const loglevel alevel) { - switch (alevel) { - default: - return "invalid/unknown"; - case extra: - return "extra"; - case trace: - return "trace"; - case debug: - return "debug"; - case verbose: - return "verbose"; - case notice: - return "notice"; - case warning: - return "warning"; - case error: - return "error"; - case failure: - return "failure"; - } -} - -bool output(const loglevel priority, const char *format, ...) { - if (lower(priority, level)) - return false; - - va_list ap; - va_start(ap, format); - output_nocheckloglevel_ap(priority, format, ap); - va_end(ap); - return true; -} - -void output_nocheckloglevel_ap(const logging::loglevel priority, - const char *format, va_list ap) { - if (last) { - putc('\n', last); - fflush(last); - if (last == stderr) { - putc('\n', stdout); - fflush(stdout); - } - last = nullptr; - } - - chrono::time now = chrono::now_realtime(); - struct tm tm; -#ifdef _MSC_VER - int rc = _localtime32_s(&tm, (const __time32_t *)&now.utc); -#else - time_t time = now.utc; - int rc = localtime_r(&time, &tm) ? MDBX_SUCCESS : errno; -#endif - if (rc != MDBX_SUCCESS) - failure_perror("localtime_r()", rc); - - last = stdout; - fprintf(last, - "[ %02d%02d%02d-%02d:%02d:%02d.%06d_%05lu %-10s %.4s ] %s" /* TODO */, - tm.tm_year - 100, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, - tm.tm_sec, chrono::fractional2us(now.fractional), (long)osal_getpid(), - prefix.c_str(), level2str(priority), suffix.c_str()); - - va_list ones; - memset(&ones, 0, sizeof(ones)) /* zap MSVC and other stupid compilers */; - if (same_or_higher(priority, error)) - va_copy(ones, ap); - vfprintf(last, format, ap); - - size_t len = strlen(format); - char end = len ? format[len - 1] : '\0'; - - switch (end) { - default: - putc('\n', last); - // fall through - case '\n': - fflush(last); - last = nullptr; - // fall through - case ' ': - case '_': - case ':': - case '|': - case ',': - case '\t': - case '\b': - case '\r': - case '\0': - break; - } - - if (same_or_higher(priority, error)) { - if (last != stderr) { - fprintf(stderr, "[ %05lu %-10s %.4s ] %s", (long)osal_getpid(), - prefix.c_str(), level2str(priority), suffix.c_str()); - vfprintf(stderr, format, ones); - if (end == '\n') - fflush(stderr); - else - last = stderr; - } - va_end(ones); - } -} - -bool feed_ap(const char *format, va_list ap) { - if (!last) - return false; - - if (last == stderr) { - va_list ones; - va_copy(ones, ap); - vfprintf(stdout, format, ones); - va_end(ones); - } - vfprintf(last, format, ap); - size_t len = strlen(format); - if (len && format[len - 1] == '\n') { - fflush(last); - if (last == stderr) - fflush(stdout); - last = nullptr; - } - return true; -} - -bool feed(const char *format, ...) { - if (!last) - return false; - - va_list ap; - va_start(ap, format); - feed_ap(format, ap); - va_end(ap); - return true; -} - -local_suffix::local_suffix(const char *c_str) - : trim_pos(suffix.size()), indent(0) { - suffix.append(c_str); -} - -local_suffix::local_suffix(const std::string &str) - : trim_pos(suffix.size()), indent(0) { - suffix.append(str); -} - -void local_suffix::push() { - indent += 1; - suffix.push_back('\t'); -} - -void local_suffix::pop() { - assert(indent > 0); - if (indent > 0) { - indent -= 1; - suffix.pop_back(); - } -} - -local_suffix::~local_suffix() { suffix.erase(trim_pos); } - -void progress_canary(bool active) { - static chrono::time progress_timestamp; - chrono::time now = chrono::now_motonic(); - - if (now.fixedpoint - progress_timestamp.fixedpoint < - chrono::from_ms(42).fixedpoint) - return; - - if (osal_progress_push(active)) { - progress_timestamp = now; - return; - } - - if (progress_timestamp.fixedpoint == 0) { - putc('>', stderr); - progress_timestamp = now; - } else if (global::config::console_mode) { - if (active) { - static int last_point = -1; - int point = (now.fixedpoint >> 29) & 3; - if (point != last_point) { - progress_timestamp = now; - fprintf(stderr, "%c\b", "-\\|/"[last_point = point]); - } - } else if (now.fixedpoint - progress_timestamp.fixedpoint > - chrono::from_seconds(2).fixedpoint) { - progress_timestamp = now; - fprintf(stderr, "%c\b", "@*"[now.utc & 1]); - } - } else { - static int count; - if (active && now.fixedpoint - progress_timestamp.fixedpoint > - chrono::from_seconds(1).fixedpoint) { - putc('.', stderr); - progress_timestamp = now; - ++count; - } else if (now.fixedpoint - progress_timestamp.fixedpoint > - chrono::from_seconds(5).fixedpoint) { - putc("@*"[now.utc & 1], stderr); - progress_timestamp = now; - ++count; - } - if (count == 60) { - count = 0; - putc('\n', stderr); - } - } - fflush(stderr); -} - -} // namespace logging - -void log_extra(const char *msg, ...) { - if (logging::same_or_higher(logging::extra, logging::level)) { - va_list ap; - va_start(ap, msg); - logging::output_nocheckloglevel_ap(logging::extra, msg, ap); - va_end(ap); - } else - logging::last = nullptr; -} - -void log_trace(const char *msg, ...) { - if (logging::same_or_higher(logging::trace, logging::level)) { - va_list ap; - va_start(ap, msg); - logging::output_nocheckloglevel_ap(logging::trace, msg, ap); - va_end(ap); - } else - logging::last = nullptr; -} - -void log_debug(const char *msg, ...) { - if (logging::same_or_higher(logging::debug, logging::level)) { - va_list ap; - va_start(ap, msg); - logging::output_nocheckloglevel_ap(logging::debug, msg, ap); - va_end(ap); - } else - logging::last = nullptr; -} - -void log_verbose(const char *msg, ...) { - if (logging::same_or_higher(logging::verbose, logging::level)) { - va_list ap; - va_start(ap, msg); - logging::output_nocheckloglevel_ap(logging::verbose, msg, ap); - va_end(ap); - } else - logging::last = nullptr; -} - -void log_notice(const char *msg, ...) { - if (logging::same_or_higher(logging::notice, logging::level)) { - va_list ap; - va_start(ap, msg); - logging::output_nocheckloglevel_ap(logging::notice, msg, ap); - va_end(ap); - } else - logging::last = nullptr; -} - -void log_warning(const char *msg, ...) { - if (logging::same_or_higher(logging::warning, logging::level)) { - va_list ap; - va_start(ap, msg); - logging::output_nocheckloglevel_ap(logging::warning, msg, ap); - va_end(ap); - } else - logging::last = nullptr; -} - -void log_error(const char *msg, ...) { - if (logging::same_or_higher(logging::error, logging::level)) { - va_list ap; - va_start(ap, msg); - logging::output_nocheckloglevel_ap(logging::error, msg, ap); - va_end(ap); - } else - logging::last = nullptr; -} - -void log_trouble(const char *where, const char *what, int errnum) { - log_error("%s: %s %s", where, what, test_strerror(errnum)); -} - -bool log_enabled(const logging::loglevel priority) { - return logging::same_or_higher(priority, logging::level); -} - -void log_flush(void) { fflushall(); } diff --git a/libs/libmdbx/src/test/log.h b/libs/libmdbx/src/test/log.h deleted file mode 100644 index bb24893779..0000000000 --- a/libs/libmdbx/src/test/log.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2017-2020 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 "chrono.h" - -void __noreturn usage(void); -void __noreturn __printf_args(1, 2) failure(const char *fmt, ...); -void __noreturn failure_perror(const char *what, int errnum); -const char *test_strerror(int errnum); - -namespace logging { - -enum loglevel { - extra = MDBX_LOG_EXTRA, - trace = MDBX_LOG_TRACE, - debug = MDBX_LOG_DEBUG, - verbose = MDBX_LOG_VERBOSE, - notice = MDBX_LOG_NOTICE, - warning = MDBX_LOG_WARN, - error = MDBX_LOG_ERROR, - failure = MDBX_LOG_FATAL -}; - -inline bool lower(loglevel left, loglevel right) { - static_assert(MDBX_LOG_EXTRA > MDBX_LOG_FATAL, "WTF?"); - return left > right; -} - -inline bool same_or_higher(loglevel left, loglevel right) { - return left <= right; -} - -const char *level2str(const loglevel level); -void setup(loglevel priority, const std::string &prefix); -void setup(const std::string &prefix); -void setlevel(loglevel priority); - -void output_nocheckloglevel_ap(const loglevel priority, const char *format, - va_list ap); -bool __printf_args(2, 3) - output(const loglevel priority, const char *format, ...); -bool feed_ap(const char *format, va_list ap); -bool __printf_args(1, 2) feed(const char *format, ...); - -void inline __printf_args(2, 3) - output_nocheckloglevel(const loglevel priority, const char *format, ...) { - va_list ap; - va_start(ap, format); - output_nocheckloglevel_ap(priority, format, ap); - va_end(ap); -} - -void progress_canary(bool active); - -class local_suffix { -protected: - size_t trim_pos; - int indent; - -public: - local_suffix(const local_suffix &) = delete; - local_suffix(const local_suffix &&) = delete; - const local_suffix &operator=(const local_suffix &) = delete; - - local_suffix(const char *c_str); - local_suffix(const std::string &str); - void push(); - void pop(); - ~local_suffix(); -}; - -} // namespace logging - -void __printf_args(1, 2) log_extra(const char *msg, ...); -void __printf_args(1, 2) log_trace(const char *msg, ...); -void __printf_args(1, 2) log_debug(const char *msg, ...); -void __printf_args(1, 2) log_verbose(const char *msg, ...); -void __printf_args(1, 2) log_notice(const char *msg, ...); -void __printf_args(1, 2) log_warning(const char *msg, ...); -void __printf_args(1, 2) log_error(const char *msg, ...); - -void log_trouble(const char *where, const char *what, int errnum); -void log_flush(void); -bool log_enabled(const logging::loglevel priority); - -#ifdef _DEBUG -#define TRACE(...) log_trace(__VA_ARGS__) -#else -#define TRACE(...) __noop(__VA_ARGS__) -#endif diff --git a/libs/libmdbx/src/test/long_stochastic.sh b/libs/libmdbx/src/test/long_stochastic.sh deleted file mode 100644 index 45d1247af7..0000000000 --- a/libs/libmdbx/src/test/long_stochastic.sh +++ /dev/null @@ -1,271 +0,0 @@ -#!/usr/bin/env bash -if ! which make cc c++ tee lz4 >/dev/null; then - echo "Please install the following prerequisites: make cc c++ tee lz4 banner" >&2 - exit 1 -fi - -BANNER="$(which banner 2>/dev/null | echo echo)" -UNAME="$(uname -s 2>/dev/null || echo Unknown)" -set -euo pipefail - -## NOTE: Valgrind could produce some false-positive warnings -## in multi-process environment with shared memory. -## For instance, when the process "A" explicitly marks a memory -## region as "undefined", the process "B" fill it, -## and after this process "A" read such region, etc. -#VALGRIND="valgrind --trace-children=yes --log-file=valgrind-%p.log --leak-check=full --track-origins=yes --error-exitcode=42 --suppressions=test/valgrind_suppress.txt" - -############################################################################### -# 1. clean data from prev runs and examine available RAM - -if [[ -v VALGRIND && ! -z "$VALGRIND" ]]; then - rm -f valgrind-*.log -else - VALGRIND=time -fi - -WANNA_MOUNT=0 -case ${UNAME} in - Linux) - MAKE=make - if [[ ! -v TESTDB_DIR || -z "$TESTDB_DIR" ]]; then - for old_test_dir in $(ls -d /dev/shm/mdbx-test.[0-9]*); do - rm -rf $old_test_dir - done - TESTDB_DIR="/dev/shm/mdbx-test.$$" - fi - mkdir -p $TESTDB_DIR && rm -f $TESTDB_DIR/* - - if LC_ALL=C free | grep -q -i available; then - ram_avail_mb=$(($(LC_ALL=C free | grep -i Mem: | tr -s [:blank:] ' ' | cut -d ' ' -f 7) / 1024)) - else - ram_avail_mb=$(($(LC_ALL=C free | grep -i Mem: | tr -s [:blank:] ' ' | cut -d ' ' -f 4) / 1024)) - fi - ;; - - FreeBSD) - MAKE=gmake - if [[ ! -v TESTDB_DIR || -z "$TESTDB_DIR" ]]; then - for old_test_dir in $(ls -d /tmp/mdbx-test.[0-9]*); do - umount $old_test_dir && rm -r $old_test_dir - done - TESTDB_DIR="/tmp/mdbx-test.$$" - rm -rf $TESTDB_DIR && mkdir -p $TESTDB_DIR - WANNA_MOUNT=1 - else - mkdir -p $TESTDB_DIR && rm -f $TESTDB_DIR/* - fi - - ram_avail_mb=$(($(LC_ALL=C vmstat -s | grep -ie '[0-9] pages free$' | cut -d p -f 1) * ($(LC_ALL=C vmstat -s | grep -ie '[0-9] bytes per page$' | cut -d b -f 1) / 1024) / 1024)) - ;; - - Darwin) - MAKE=make - if [[ ! -v TESTDB_DIR || -z "$TESTDB_DIR" ]]; then - for vol in $(ls -d /Volumes/mdx[0-9]*[0-9]tst); do - disk=$(mount | grep $vol | cut -d ' ' -f 1) - echo "umount: volume $vol disk $disk" - hdiutil unmount $vol -force - hdiutil detach $disk - done - TESTDB_DIR="/Volumes/mdx$$tst" - WANNA_MOUNT=1 - else - mkdir -p $TESTDB_DIR && rm -f $TESTDB_DIR/* - fi - - pagesize=$(($(LC_ALL=C vm_stat | grep -o 'page size of [0-9]\+ bytes' | cut -d' ' -f 4) / 1024)) - freepages=$(LC_ALL=C vm_stat | grep '^Pages free:' | grep -o '[0-9]\+\.$' | cut -d'.' -f 1) - ram_avail_mb=$((pagesize * freepages / 1024)) - echo "pagesize ${pagesize}K, freepages ${freepages}, ram_avail_mb ${ram_avail_mb}" - - ;; - - *) - echo "FIXME: ${UNAME} not supported by this script" - exit 2 - ;; -esac - -############################################################################### -# 2. estimate reasonable RAM space for test-db - -echo "=== ${ram_avail_mb}M RAM available" -ram_reserve4logs_mb=1234 -if [ $ram_avail_mb -lt $ram_reserve4logs_mb ]; then - echo "=== At least ${ram_reserve4logs_mb}Mb RAM required" - exit 3 -fi - -# -# В режимах отличных от MDBX_WRITEMAP изменения до записи в файл -# будут накапливаться в памяти, что может потребовать свободной -# памяти размером с БД. Кроме этого, в тест входит сценарий -# создания копия БД на ходу. Поэтому БД не может быть больше 1/3 -# от доступной памяти. Однако, следует учесть что malloc() будет -# не сразу возвращать выделенную память системе, а также -# предусмотреть места для логов. -# -# In non-MDBX_WRITEMAP modes, updates (dirty pages) will -# accumulate in memory before writing to the disk, which may -# require a free memory up to the size of a whole database. In -# addition, the test includes a script create a copy of the -# database on the go. Therefore, the database cannot be more 1/3 -# of available memory. Moreover, should be taken into account -# that malloc() will not return the allocated memory to the -# system immediately, as well some space is required for logs. -# -db_size_mb=$(((ram_avail_mb - ram_reserve4logs_mb) / 4)) -if [ $db_size_mb -gt 17408 ]; then - db_size_mb=17408 -fi -echo "=== use ${db_size_mb}M for DB" - -############################################################################### -# 3. Create test-directory in ramfs/tmpfs, i.e. create/format/mount if required -case ${UNAME} in - Linux) - ;; - - FreeBSD) - if [[ WANNA_MOUNT ]]; then - mount -t tmpfs tmpfs $TESTDB_DIR - fi - ;; - - Darwin) - if [[ WANNA_MOUNT ]]; then - ramdisk_size_mb=$((42 + db_size_mb * 2 + ram_reserve4logs_mb)) - number_of_sectors=$((ramdisk_size_mb * 2048)) - ramdev=$(hdiutil attach -nomount ram://${number_of_sectors}) - diskutil erasevolume ExFAT "mdx$$tst" ${ramdev} - fi - ;; - - *) - echo "FIXME: ${UNAME} not supported by this script" - exit 2 - ;; -esac - -############################################################################### -# 4. Run basic test, i.e. `make check` - -${MAKE} TEST_DB=${TESTDB_DIR}/smoke.db TEST_LOG=${TESTDB_DIR}/smoke.log check -rm -f ${TESTDB_DIR}/* - -############################################################################### -# 5. run stochastic iterations - -function join { local IFS="$1"; shift; echo "$*"; } -function bit2option { local -n arr=$1; (( ($2&(1<<$3)) != 0 )) && echo -n '+' || echo -n '-'; echo "${arr[$3]}"; } - -options=(writemap coalesce lifo notls) - -function bits2list { - local -n arr=$1 - local i - local list=() - for ((i=0; i<${#arr[@]}; ++i)) do - list[$i]=$(bit2option $1 $2 $i) - done - join , "${list[@]}" -} - -function probe { - echo "----------------------------------------------- $(date)" - echo "${caption}: $*" - rm -f ${TESTDB_DIR}/* \ - && ${VALGRIND} ./mdbx_test ${speculum} --ignore-dbfull --repeat=3 --pathname=${TESTDB_DIR}/long.db --cleanup-after=no "$@" \ - | tee >(lz4 > ${TESTDB_DIR}/long.log.lz4) | grep -e reach -e achieve \ - && ${VALGRIND} ./mdbx_chk ${TESTDB_DIR}/long.db | tee ${TESTDB_DIR}/long-chk.log \ - && ([ ! -e ${TESTDB_DIR}/long.db-copy ] || ${VALGRIND} ./mdbx_chk ${TESTDB_DIR}/long.db-copy | tee ${TESTDB_DIR}/long-chk-copy.log) \ - || (echo "FAILED"; exit 1) -} - -#------------------------------------------------------------------------------ - -count=0 -cases='?' -for nops in 10 100 1000 10000 100000 1000000 10000000 100000000 1000000000; do - echo "=======================================================================" - wbatch=$((nops / 10 + 1)) - speculum=$([ $nops -le 1000 ] && echo '--speculum' || true) - while true; do - echo "=======================================================================" - ${BANNER} "$nops / $wbatch" - subcase=0 - for ((bits=2**${#options[@]}; --bits >= 0; )); do - seed=$(($(date +%s) + RANDOM)) - - split=30 - caption="Probe #$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - caption="Probe #$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - - split=24 - caption="Probe #$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - caption="Probe #$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - - split=16 - caption="Probe #$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - caption="Probe #$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - caption="Probe #$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - caption="Probe #$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - - split=4 - caption="Probe #$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - caption="Probe #$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \ - --pagesize=min --size-upper=${db_size_mb}M --table=-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \ - --nops=$nops --batch.write=$wbatch --mode=$(bits2list options $bits) \ - --keygen.seed=${seed} basic - done # options - cases="${subcase}" - wbatch=$(((wbatch > 9) ? wbatch / 10 : 1)) - if [ $wbatch -eq 1 -o $((nops / wbatch)) -gt 1000 ]; then break; fi - done # batch (write-ops per txn) -done # n-ops - -echo "=== ALL DONE ====================== $(date)" diff --git a/libs/libmdbx/src/test/main.cc b/libs/libmdbx/src/test/main.cc deleted file mode 100644 index 10016ab3d5..0000000000 --- a/libs/libmdbx/src/test/main.cc +++ /dev/null @@ -1,639 +0,0 @@ -/* - * Copyright 2017-2020 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" - -#if !(defined(_WIN32) || defined(_WIN64)) -#include <sys/resource.h> -#include <sys/time.h> -#endif /* !Windows */ - -void __noreturn usage(void) { - puts( - "usage:\n" - " --help or -h Show this text\n" - "Common parameters:\n" - " --pathname=... Path and/or name of database files\n" - " --repeat=N Set repeat counter\n" - " --threads=N Number of thread (unsunpported for now)\n" - " --timeout=N[s|m|h|d] Set timeout in seconds/minutes/hours/days\n" - " --failfast[=YES/no] Lill all actors on first failure/error\n" - " --max-readers=N See mdbx_env_set_maxreaders() description\n" - " --max-tables=N Se mdbx_env_set_maxdbs() description\n" - " --dump-config[=YES/no] Dump entire test config before run\n" - " --progress[=YES/no] Enable/disable progress `canary`\n" - " --console[=yes/no] Enable/disable console-like output\n" - " --cleanup-before[=YES/no] Cleanup/remove and re-create database\n" - " --cleanup-after[=YES/no] Cleanup/remove database after completion\n" - "Database size control:\n" - " --pagesize=... Database page size: min, max, 256..65536\n" - " --size-lower=N[K|M|G|T] Lower-bound of size in Kb/Mb/Gb/Tb\n" - " --size-upper Upper-bound of size in Kb/Mb/Gb/Tb\n" - " --size Initial size in Kb/Mb/Gb/Tb\n" - " --shrink-threshold Shrink threshold in Kb/Mb/Gb/Tb\n" - " --growth-step Grow step in Kb/Mb/Gb/Tb\n" - "Predefined complext scenarios/cases:\n" - " --case=... Only `basic` scenario implemented for now\n" - " basic == Simultaneous multi-process execution\n" - " of test-actors: nested,hill,ttl,copy,append,jitter,try\n" - "Test actors:\n" - " --hill Fill-up and empty-down\n" - " by CRUD-operation quads\n" - " --ttl Stochastic time-to-live simulation\n" - " --nested Nested transactionы\n" - " with stochastic-size bellows\n" - " --jitter Jitter/delays simulation\n" - " --try Try write-transaction, no more\n" - " --copy Online copy/backup\n" - " --append Append-mode insertions\n" - " --dead.reader Dead-reader simulator\n" - " --dead.writer Dead-writer simulator\n" - "Actor options:\n" - " --batch.read=N Read-operations batch size\n" - " --batch.write=N Write-operations batch size\n" - " --delay=N | --no-delay (no)Delay test-actor before start\n" - " --wait4ops=N | --no-wait4ops (no)Wait for previous test-actor\n" - " completes # ops before start\n" - " --duration=N[s|m|h|d] Define running duration\n" - " --nops=N[K|M|G|T] Define number of operations/steps\n" - " --inject-writefault[=yes|NO] TBD (see the source code)\n" - " --drop[=yes|NO] Drop key-value space/table on " - "completion\n" - " --ignore-dbfull[=yes|NO] Ignore MDBX_MAP_FULL error\n" - " --speculum[=yes|NO] Use internal `speculum` to check " - "dataset\n" - "Keys and Value:\n" - " --keylen.min=N Minimal keys length\n" - " --keylen.max=N Miximal keys length\n" - " --datalen.min=N Minimal data length\n" - " --datalen.max=N Miximal data length\n" - " --keygen.width=N TBD (see the source code)\n" - " --keygen.mesh=N TBD (see the source code)\n" - " --keygen.seed=N TBD (see the source code)\n" - " --keygen.zerofill=yes|NO TBD (see the source code)\n" - " --keygen.split=N TBD (see the source code)\n" - " --keygen.rotate=N TBD (see the source code)\n" - " --keygen.offset=N TBD (see the source code)\n" - " --keygen.case=random Generator case (only `random` for now)\n" - "Database operation mode:\n" - " --mode={[+-]FLAG}[,[+-]FLAG]...\n" - " nosubdir == MDBX_NOSUBDIR\n" - " rdonly == MDBX_RDONLY\n" - " nometasync == MDBX_NOMETASYNC\n" - " lifo == MDBX_LIFORECLAIM\n" - " coalesce == MDBX_COALESCE\n" - " nosync-safe == MDBX_SAFE_NOSYNC\n" - " writemap == MDBX_WRITEMAP\n" - " mapasync == MDBX_MAPASYNC\n" - " nosync-utterly == MDBX_UTTERLY_NOSYNC\n" - " perturb == MDBX_PAGEPERTURB\n" - " notls == MDBX_NOTLS\n" - " nordahead == MDBX_NORDAHEAD\n" - " nomeminit == MDBX_NOMEMINIT\n" - " --random-writemap[=YES|no] Toggle MDBX_WRITEMAP randomly\n" - "Key-value space/table options:\n" - " --table={[+-]FLAG}[,[+-]FLAG]...\n" - " key.reverse == MDBX_REVERSEKEY\n" - " key.integer == MDBX_INTEGERKEY\n" - " data.dups == MDBX_DUPSORT\n" - " data.integer == MDBX_INTEGERDUP | MDBX_DUPFIXED | MDBX_DUPSORT\n" - " data.fixed == MDBX_DUPFIXED | MDBX_DUPSORT\n" - " data.reverse == MDBX_REVERSEDUP | MDBX_DUPSORT\n"); - exit(EXIT_FAILURE); -} - -//----------------------------------------------------------------------------- - -void actor_params::set_defaults(const std::string &tmpdir) { - pathname_log = ""; - loglevel = -#if defined(NDEBUG) || defined(_WIN32) || defined(_WIN64) - logging::verbose; -#else - logging::trace; -#endif - - pathname_db = tmpdir + "mdbx-test.db"; - mode_flags = MDBX_NOSUBDIR | MDBX_WRITEMAP | MDBX_MAPASYNC | MDBX_NOMEMINIT | - MDBX_COALESCE | MDBX_LIFORECLAIM | MDBX_ACCEDE; - table_flags = MDBX_DUPSORT; - - size_lower = -1; - size_now = - intptr_t(1024) * 1024 * ((table_flags & MDBX_DUPSORT) ? 256 : 1024); - size_upper = -1; - shrink_threshold = -1; - growth_step = -1; - pagesize = -1; - - keygen.seed = 1; - keygen.zero_fill = false; - keygen.keycase = kc_random; - keygen.width = (table_flags & MDBX_DUPSORT) ? 32 : 64; - keygen.mesh = keygen.width; - keygen.split = keygen.width / 2; - keygen.rotate = 3; - keygen.offset = 41; - - test_duration = 0; - test_nops = 1000; - nrepeat = 1; - nthreads = 1; - - keylen_min = mdbx_keylen_min(); - keylen_max = mdbx_keylen_max(); - datalen_min = mdbx_datalen_min(); - datalen_max = std::min(mdbx_datalen_max(), 256u * 1024 + 42); - - batch_read = 42; - batch_write = 42; - - delaystart = 0; - waitfor_nops = 0; - inject_writefaultn = 0; - - drop_table = false; - ignore_dbfull = false; - speculum = false; - random_writemap = true; - - max_readers = 42; - max_tables = 42; - - global::config::timeout_duration_seconds = 0 /* infinite */; - global::config::dump_config = true; - global::config::cleanup_before = true; - global::config::cleanup_after = true; - global::config::failfast = true; - global::config::progress_indicator = true; - global::config::console_mode = osal_istty(STDERR_FILENO); -} - -namespace global { - -std::vector<actor_config> actors; -std::unordered_map<unsigned, actor_config *> events; -std::unordered_map<mdbx_pid_t, actor_config *> pid2actor; -std::set<std::string> databases; -unsigned nactors; -chrono::time start_motonic; -chrono::time deadline_motonic; -bool singlemode; - -namespace config { -unsigned timeout_duration_seconds; -bool dump_config; -bool cleanup_before; -bool cleanup_after; -bool failfast; -bool progress_indicator; -bool console_mode; -} /* namespace config */ - -} /* namespace global */ - -//----------------------------------------------------------------------------- - -const char global::thunk_param_prefix[] = "--execute="; - -std::string thunk_param(const actor_config &config) { - return config.serialize(global::thunk_param_prefix); -} - -void cleanup() { - log_trace(">> cleanup"); - for (const auto &db_path : global::databases) { - int err = osal_removefile(db_path); - if (err != MDBX_SUCCESS && err != MDBX_ENOFILE) - failure_perror(db_path.c_str(), err); - } - log_trace("<< cleanup"); -} - -int main(int argc, char *const argv[]) { - -#ifdef _DEBUG - log_trace("#argc = %d", argc); - for (int i = 0; i < argc; ++i) - log_trace("#argv[%d] = %s", i, argv[i]); -#endif /* _DEBUG */ - - if (argc < 2) - failure("No parameters given. Try --help\n"); - - if (argc == 2 && strncmp(argv[1], global::thunk_param_prefix, - strlen(global::thunk_param_prefix)) == 0) - return test_execute( - actor_config(argv[1] + strlen(global::thunk_param_prefix))) - ? EXIT_SUCCESS - : EXIT_FAILURE; - - if (argc == 2 && - (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0)) - usage(); - - actor_params params; - params.set_defaults(osal_tempdir()); - global::config::dump_config = true; - logging::setup((logging::loglevel)params.loglevel, "main"); - unsigned last_space_id = 0; - - for (int narg = 1; narg < argc; ++narg) { - const char *value = nullptr; - - if (config::parse_option(argc, argv, narg, "case", &value)) { - testcase_setup(value, params, last_space_id); - continue; - } - if (config::parse_option(argc, argv, narg, "pathname", params.pathname_db)) - continue; - if (config::parse_option(argc, argv, narg, "mode", params.mode_flags, - config::mode_bits)) - continue; - if (config::parse_option(argc, argv, narg, "random-writemap", - params.random_writemap)) - continue; - if (config::parse_option(argc, argv, narg, "table", params.table_flags, - config::table_bits)) { - if ((params.table_flags & MDBX_DUPFIXED) == 0) - params.table_flags &= ~MDBX_INTEGERDUP; - if ((params.table_flags & MDBX_DUPSORT) == 0) - params.table_flags &= - ~(MDBX_DUPFIXED | MDBX_REVERSEDUP | MDBX_INTEGERDUP); - continue; - } - - if (config::parse_option(argc, argv, narg, "pagesize", params.pagesize, - int(mdbx_limits_pgsize_min()), - int(mdbx_limits_pgsize_max()))) { - const unsigned keylen_max = params.mdbx_keylen_max(); - if (params.keylen_min > keylen_max) - params.keylen_min = keylen_max; - if (params.keylen_max > keylen_max) - params.keylen_max = keylen_max; - const unsigned datalen_max = params.mdbx_datalen_max(); - if (params.datalen_min > datalen_max) - params.datalen_min = datalen_max; - if (params.datalen_max > datalen_max) - params.datalen_max = datalen_max; - continue; - } - if (config::parse_option(argc, argv, narg, "repeat", params.nrepeat, - config::no_scale)) - continue; - if (config::parse_option(argc, argv, narg, "threads", params.nthreads, - config::no_scale, 1, 64)) - continue; - if (config::parse_option(argc, argv, narg, "timeout", - global::config::timeout_duration_seconds, - config::duration, 1)) - continue; - - if (config::parse_option_intptr(argc, argv, narg, "size-lower", - params.size_lower, - mdbx_limits_dbsize_min(params.pagesize), - mdbx_limits_dbsize_max(params.pagesize))) - continue; - if (config::parse_option_intptr(argc, argv, narg, "size-upper", - params.size_upper, - mdbx_limits_dbsize_min(params.pagesize), - mdbx_limits_dbsize_max(params.pagesize))) - continue; - if (config::parse_option_intptr(argc, argv, narg, "size", params.size_now, - mdbx_limits_dbsize_min(params.pagesize), - mdbx_limits_dbsize_max(params.pagesize))) - continue; - if (config::parse_option( - argc, argv, narg, "shrink-threshold", params.shrink_threshold, 0, - (int)std::min((intptr_t)INT_MAX, - mdbx_limits_dbsize_max(params.pagesize) - - mdbx_limits_dbsize_min(params.pagesize)))) - continue; - if (config::parse_option( - argc, argv, narg, "growth-step", params.growth_step, 0, - (int)std::min((intptr_t)INT_MAX, - mdbx_limits_dbsize_max(params.pagesize) - - mdbx_limits_dbsize_min(params.pagesize)))) - continue; - - if (config::parse_option(argc, argv, narg, "keygen.width", - params.keygen.width, 8, 64)) - continue; - if (config::parse_option(argc, argv, narg, "keygen.mesh", - params.keygen.mesh, 0, 64)) - continue; - if (config::parse_option(argc, argv, narg, "keygen.seed", - params.keygen.seed, config::no_scale)) - continue; - if (config::parse_option(argc, argv, narg, "keygen.zerofill", - params.keygen.zero_fill)) - continue; - if (config::parse_option(argc, argv, narg, "keygen.split", - params.keygen.split, 0, 63)) - continue; - if (config::parse_option(argc, argv, narg, "keygen.rotate", - params.keygen.rotate, 0, 63)) - continue; - if (config::parse_option(argc, argv, narg, "keygen.offset", - params.keygen.offset, config::binary)) - continue; - if (config::parse_option(argc, argv, narg, "keygen.case", &value)) { - keycase_setup(value, params); - continue; - } - if (config::parse_option(argc, argv, narg, "keylen.min", params.keylen_min, - config::no_scale, params.mdbx_keylen_min(), - params.mdbx_keylen_max())) { - if ((params.table_flags & MDBX_INTEGERKEY) || - params.keylen_max < params.keylen_min) - params.keylen_max = params.keylen_min; - continue; - } - if (config::parse_option(argc, argv, narg, "keylen.max", params.keylen_max, - config::no_scale, params.mdbx_keylen_min(), - params.mdbx_keylen_max())) { - if ((params.table_flags & MDBX_INTEGERKEY) || - params.keylen_min > params.keylen_max) - params.keylen_min = params.keylen_max; - continue; - } - if (config::parse_option(argc, argv, narg, "datalen.min", - params.datalen_min, config::no_scale, - params.mdbx_datalen_min(), - params.mdbx_datalen_max())) { - if ((params.table_flags & MDBX_DUPFIXED) || - params.datalen_max < params.datalen_min) - params.datalen_max = params.datalen_min; - continue; - } - if (config::parse_option(argc, argv, narg, "datalen.max", - params.datalen_max, config::no_scale, - params.mdbx_datalen_min(), - params.mdbx_datalen_max())) { - if ((params.table_flags & MDBX_DUPFIXED) || - params.datalen_min > params.datalen_max) - params.datalen_min = params.datalen_max; - continue; - } - if (config::parse_option(argc, argv, narg, "batch.read", params.batch_read, - config::no_scale, 1)) - continue; - if (config::parse_option(argc, argv, narg, "batch.write", - params.batch_write, config::no_scale, 1)) - continue; - if (config::parse_option(argc, argv, narg, "delay", params.delaystart, - config::duration)) - continue; - if (config::parse_option(argc, argv, narg, "wait4ops", params.waitfor_nops, - config::decimal)) - continue; - if (config::parse_option(argc, argv, narg, "inject-writefault", - params.inject_writefaultn, config::decimal)) - continue; - if (config::parse_option(argc, argv, narg, "drop", params.drop_table)) - continue; - if (config::parse_option(argc, argv, narg, "ignore-dbfull", - params.ignore_dbfull)) - continue; - if (config::parse_option(argc, argv, narg, "speculum", params.speculum)) - continue; - if (config::parse_option(argc, argv, narg, "dump-config", - global::config::dump_config)) - continue; - if (config::parse_option(argc, argv, narg, "cleanup-before", - global::config::cleanup_before)) - continue; - if (config::parse_option(argc, argv, narg, "cleanup-after", - global::config::cleanup_after)) - continue; - if (config::parse_option(argc, argv, narg, "max-readers", - params.max_readers, config::no_scale, 1, 255)) - continue; - if (config::parse_option(argc, argv, narg, "max-tables", params.max_tables, - config::no_scale, 1, INT16_MAX)) - continue; - - if (config::parse_option(argc, argv, narg, "no-delay", nullptr)) { - params.delaystart = 0; - continue; - } - if (config::parse_option(argc, argv, narg, "no-wait4ops", nullptr)) { - params.waitfor_nops = 0; - continue; - } - if (config::parse_option(argc, argv, narg, "duration", params.test_duration, - config::duration, 1)) { - params.test_nops = 0; - continue; - } - if (config::parse_option(argc, argv, narg, "nops", params.test_nops, - config::decimal, 1)) { - params.test_duration = 0; - continue; - } - if (config::parse_option(argc, argv, narg, "hill", &value, "auto")) { - configure_actor(last_space_id, ac_hill, value, params); - continue; - } - if (config::parse_option(argc, argv, narg, "jitter", nullptr)) { - configure_actor(last_space_id, ac_jitter, value, params); - continue; - } - if (config::parse_option(argc, argv, narg, "dead.reader", nullptr)) { - configure_actor(last_space_id, ac_deadread, value, params); - continue; - } - if (config::parse_option(argc, argv, narg, "dead.writer", nullptr)) { - configure_actor(last_space_id, ac_deadwrite, value, params); - continue; - } - if (config::parse_option(argc, argv, narg, "try", nullptr)) { - configure_actor(last_space_id, ac_try, value, params); - continue; - } - if (config::parse_option(argc, argv, narg, "copy", nullptr)) { - configure_actor(last_space_id, ac_copy, value, params); - continue; - } - if (config::parse_option(argc, argv, narg, "append", nullptr)) { - configure_actor(last_space_id, ac_append, value, params); - continue; - } - if (config::parse_option(argc, argv, narg, "ttl", nullptr)) { - configure_actor(last_space_id, ac_ttl, value, params); - continue; - } - if (config::parse_option(argc, argv, narg, "nested", nullptr)) { - configure_actor(last_space_id, ac_nested, value, params); - continue; - } - if (config::parse_option(argc, argv, narg, "failfast", - global::config::failfast)) - continue; - if (config::parse_option(argc, argv, narg, "progress", - global::config::progress_indicator)) - continue; - if (config::parse_option(argc, argv, narg, "console", - global::config::console_mode)) - continue; - - if (*argv[narg] != '-') - testcase_setup(argv[narg], params, last_space_id); - else - failure("Unknown option '%s'. Try --help\n", argv[narg]); - } - - if (global::config::dump_config) - config::dump(); - - //-------------------------------------------------------------------------- - - if (global::actors.empty()) { - log_notice("no testcase(s) configured, exiting"); - return EXIT_SUCCESS; - } - - bool failed = false; - global::start_motonic = chrono::now_motonic(); - global::deadline_motonic.fixedpoint = - (global::config::timeout_duration_seconds == 0) - ? chrono::infinite().fixedpoint - : global::start_motonic.fixedpoint + - chrono::from_seconds(global::config::timeout_duration_seconds) - .fixedpoint; - - if (global::config::cleanup_before) - cleanup(); - - log_trace(">> probe entropy_ticks()"); - entropy_ticks(); - log_trace("<< probe entropy_ticks()"); - - if (global::actors.size() == 1) { - logging::setup("main"); - global::singlemode = true; - if (!test_execute(global::actors.front())) - failed = true; - } else { - logging::setup("overlord"); - - log_trace("=== preparing..."); - log_trace(">> osal_setup"); - osal_setup(global::actors); - log_trace("<< osal_setup"); - - for (auto &a : global::actors) { - mdbx_pid_t pid; - log_trace(">> actor_start"); - int rc = osal_actor_start(a, pid); - log_trace("<< actor_start"); - if (rc) { - log_trace(">> killall_actors: (%s)", "start failed"); - osal_killall_actors(); - log_trace("<< killall_actors"); - failure("Failed to start actor #%u (%s)\n", a.actor_id, - test_strerror(rc)); - } - global::pid2actor[pid] = &a; - } - - log_trace("=== ready to start..."); - atexit(osal_killall_actors); - log_trace(">> wait4barrier"); - osal_wait4barrier(); - log_trace("<< wait4barrier"); - - size_t left = global::actors.size(); - log_trace("=== polling..."); - while (left > 0) { - unsigned timeout_seconds_left = INT_MAX; - chrono::time now_motonic = chrono::now_motonic(); - if (now_motonic.fixedpoint >= global::deadline_motonic.fixedpoint) - timeout_seconds_left = 0; - else { - chrono::time left_motonic; - left_motonic.fixedpoint = - global::deadline_motonic.fixedpoint - now_motonic.fixedpoint; - timeout_seconds_left = left_motonic.seconds(); - } - - mdbx_pid_t pid; - int rc = osal_actor_poll(pid, timeout_seconds_left); - if (rc) - failure("Poll error: %s (%d)\n", test_strerror(rc), rc); - - if (pid) { - actor_status status = osal_actor_info(pid); - actor_config *actor = global::pid2actor.at(pid); - if (!actor) - continue; - - log_verbose("actor #%u, id %d, pid %ld: %s\n", actor->actor_id, - actor->space_id, (long)pid, status2str(status)); - if (status > as_running) { - left -= 1; - if (status != as_successful) { - if (global::config::failfast && !failed) { - log_trace(">> killall_actors: (%s)", "failfast"); - osal_killall_actors(); - log_trace("<< killall_actors"); - } - failed = true; - } - } - } else { - if (timeout_seconds_left == 0) - failure("Timeout\n"); - } - } - log_trace("=== done..."); - } - - log_notice("RESULT: %s\n", failed ? "Failed" : "Successful"); - if (global::config::cleanup_after) { - if (failed) - log_verbose("skip cleanup"); - else - cleanup(); - } - -#if !(defined(_WIN32) || defined(_WIN64)) - struct rusage spent; - if (!getrusage(global::singlemode ? RUSAGE_SELF : RUSAGE_CHILDREN, &spent)) { - log_notice("%6s: user %f, system %f", "CPU", - spent.ru_utime.tv_sec + spent.ru_utime.tv_usec * 1e-6, - spent.ru_stime.tv_sec + spent.ru_stime.tv_usec * 1e-6); -#if defined(__linux__) || defined(__gnu_linux__) || defined(__FreeBSD__) || \ - defined(__NetBSD__) || defined(__OpenBSD__) || defined(__BSD__) || \ - defined(__bsdi__) || defined(__DragonFly__) || defined(__APPLE__) || \ - defined(__MACH__) || defined(__sun) - log_notice("%6s: read %ld, write %ld", "IOPs", spent.ru_inblock, - spent.ru_oublock); - if (spent.ru_maxrss > 0) - log_notice("%6s: %ld Kb", "RAM", - spent.ru_maxrss -#if defined(__sun) - * getpagesize() / 1024u -#elif defined(__APPLE__) - / 1024u -#endif - ); - log_notice("%6s: reclaims %ld, faults %ld, swaps %ld", "Paging", - spent.ru_minflt, spent.ru_majflt, spent.ru_nswap); -#endif /* Linux */ - } -#endif /* !Windows */ - - return failed ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/libs/libmdbx/src/test/nested.cc b/libs/libmdbx/src/test/nested.cc deleted file mode 100644 index 85df6fa62b..0000000000 --- a/libs/libmdbx/src/test/nested.cc +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright 2017-2020 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" -#include <cmath> - -/* LY: тест "эмуляцией time-to-live" с вложенными транзакциями: - * - организуется "скользящее окно", которое каждую транзакцию сдвигается - * вперед вдоль числовой оси. - * - по переднему краю "скользящего окна" записи добавляются в таблицу, - * а по заднему удаляются. - * - количество добавляемых/удаляемых записей псевдослучайно зависит - * от номера транзакции, но с экспоненциальным распределением. - * - размер "скользящего окна" также псевдослучайно зависит от номера - * транзакции с "отрицательным" экспоненциальным распределением - * MAX_WIDTH - exp(rnd(N)), при уменьшении окна сдвигается задний - * край и удаляются записи позади него. - * - групповое добавление данных в начало окна и групповое удаление в конце, - * преимущественно выполняются во вложенных транзакциях. - * - меньшая часть запускаемых вложенных транзакций отменяется, с последующим - * продолжением итераций с состояния предыдущиего коммита. - * - * Таким образом имитируется поведение таблицы с TTL: записи стохастически - * добавляются и удаляются, и изредка происходят массивные удаления. */ - -bool testcase_nested::setup() { - if (!inherited::setup()) - return false; - int err = db_open__begin__table_create_open_clean(dbi); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("nested: bailout-prepare due '%s'", mdbx_strerror(err)); - return false; - } - - keyvalue_maker.setup(config.params, config.actor_id, 0 /* thread_number */); - key = keygen::alloc(config.params.keylen_max); - data = keygen::alloc(config.params.datalen_max); - serial = 0; - fifo.clear(); - speculum.clear(); - assert(stack.empty()); - stack.emplace(nullptr, serial, fifo, speculum); - return true; -} - -bool testcase_nested::teardown() { - while (!stack.empty()) - pop_txn(true); - - bool ok = true; - if (dbi) { - if (config.params.drop_table && !mode_readonly()) { - txn_begin(false); - db_table_drop(dbi); - int err = breakable_commit(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("nested: bailout-clean due '%s'", mdbx_strerror(err)); - ok = false; - } - } else - db_table_close(dbi); - dbi = 0; - } - return inherited::teardown() && ok; -} - -void testcase_nested::push_txn() { - MDBX_txn *txn; - unsigned flags = - prng32() & (MDBX_SAFE_NOSYNC | MDBX_NOMETASYNC | MDBX_MAPASYNC); - int err = mdbx_txn_begin(db_guard.get(), txn_guard.get(), flags, &txn); - if (unlikely(err != MDBX_SUCCESS)) - failure_perror("mdbx_txn_begin(nested)", err); - stack.emplace(scoped_txn_guard(txn), serial, fifo, speculum); - std::swap(txn_guard, std::get<0>(stack.top())); - log_verbose("begin level#%zu txn #%" PRIu64 ", flags 0x%x, serial %" PRIu64, - stack.size(), mdbx_txn_id(txn), flags, serial); -} - -bool testcase_nested::pop_txn(bool abort) { - assert(txn_guard && !stack.empty()); - bool should_continue = true; - MDBX_txn *txn = txn_guard.release(); - bool commited = false; - if (abort) { - log_verbose( - "abort level#%zu txn #%" PRIu64 ", undo serial %" PRIu64 " <- %" PRIu64, - stack.size(), mdbx_txn_id(txn), serial, std::get<1>(stack.top())); - int err = mdbx_txn_abort(txn); - if (unlikely(err != MDBX_SUCCESS)) - failure_perror("mdbx_txn_abort()", err); - } else { - log_verbose("commit level#%zu txn, nested serial %" PRIu64 " -> %" PRIu64, - stack.size(), serial, std::get<1>(stack.top())); - int err = mdbx_txn_commit(txn); - if (likely(err == MDBX_SUCCESS)) - commited = true; - else { - should_continue = false; - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - err = mdbx_txn_abort(txn); - if (unlikely(err != MDBX_SUCCESS && err != MDBX_THREAD_MISMATCH && - err != MDBX_BAD_TXN)) - failure_perror("mdbx_txn_abort()", err); - } else - failure_perror("mdbx_txn_commit()", err); - } - } - - std::swap(txn_guard, std::get<0>(stack.top())); - if (!commited) { - serial = std::get<1>(stack.top()); - std::swap(fifo, std::get<2>(stack.top())); - std::swap(speculum, std::get<3>(stack.top())); - } - stack.pop(); - return should_continue; -} - -bool testcase_nested::stochastic_breakable_restart_with_nested( - bool force_restart) { - log_trace(">> stochastic_breakable_restart_with_nested%s", - force_restart ? ": force_restart" : ""); - - if (force_restart) - while (txn_guard) - pop_txn(true); - - bool should_continue = true; - while (!stack.empty() && - (flipcoin() || txn_underutilization_x256(txn_guard.get()) < 42)) - should_continue &= pop_txn(); - - if (should_continue) - while (stack.empty() || - (is_nested_txn_available() && flipcoin() && stack.size() < 5)) - push_txn(); - - log_trace("<< stochastic_breakable_restart_with_nested: should_continue=%s", - should_continue ? "yes" : "no"); - return should_continue; -} - -bool testcase_nested::trim_tail(unsigned window_width) { - if (window_width || flipcoin()) { - clear_stepbystep_passed += window_width == 0; - while (fifo.size() > window_width) { - uint64_t tail_serial = fifo.back().first; - const unsigned tail_count = fifo.back().second; - log_verbose("nested: pop-tail (serial %" PRIu64 ", count %u)", - tail_serial, tail_count); - fifo.pop_back(); - for (unsigned n = 0; n < tail_count; ++n) { - log_trace("nested: remove-tail %" PRIu64, tail_serial); - generate_pair(tail_serial); - int err = remove(key, data); - if (unlikely(err != MDBX_SUCCESS)) { - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - log_notice("nested: tail-bailout due '%s'", mdbx_strerror(err)); - return false; - } - failure_perror("mdbx_del(tail)", err); - } - if (unlikely(!keyvalue_maker.increment(tail_serial, 1))) - failure("nested: unexpected key-space overflow on the tail"); - } - report(tail_count); - } - } else if (!fifo.empty()) { - log_verbose("nested: purge state %" PRIu64 " - %" PRIu64 ", fifo-items %zu", - fifo.front().first, fifo.back().first + fifo.back().second, - fifo.size()); - db_table_clear(dbi, txn_guard.get()); - fifo.clear(); - clear_wholetable_passed += 1; - report(1); - } - return true; -} - -bool testcase_nested::grow_head(unsigned head_count) { - const unsigned insert_flags = (config.params.table_flags & MDBX_DUPSORT) - ? MDBX_NODUPDATA - : MDBX_NODUPDATA | MDBX_NOOVERWRITE; -retry: - fifo.push_front(std::make_pair(serial, head_count)); - for (unsigned n = 0; n < head_count; ++n) { - log_trace("nested: insert-head %" PRIu64, serial); - generate_pair(serial); - int err = insert(key, data, insert_flags); - if (unlikely(err != MDBX_SUCCESS)) { - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - log_notice("nested: head-insert skip due '%s'", mdbx_strerror(err)); - head_count = n; - stochastic_breakable_restart_with_nested(true); - dbfull_passed += 1; - goto retry; - } - failure_perror("mdbx_put(head)", err); - } - - if (unlikely(!keyvalue_maker.increment(serial, 1))) { - log_notice("nested: unexpected key-space overflow"); - keyspace_overflow = true; - head_count = n; - stochastic_breakable_restart_with_nested(true); - goto retry; - } - } - - return true; -} - -bool testcase_nested::run() { - uint64_t seed = - prng64_map2_white(config.params.keygen.seed) + config.actor_id; - - clear_wholetable_passed = 0; - clear_stepbystep_passed = 0; - dbfull_passed = 0; - unsigned loops = 0; - while (true) { - const uint64_t salt = prng64_white(seed) /* mdbx_txn_id(txn_guard.get()) */; - const unsigned window_width = - (!should_continue() || flipcoin_x4()) ? 0 : edge2window(salt); - const unsigned head_count = edge2count(salt); - log_debug("nested: step #%" PRIu64 " (serial %" PRIu64 - ", window %u, count %u) salt %" PRIu64, - nops_completed, serial, window_width, head_count, salt); - - if (!trim_tail(window_width)) - return false; - if (!stochastic_breakable_restart_with_nested()) { - log_notice("nested: bailout at commit/restart after tail-trim"); - return false; - } - if (!speculum_verify()) { - log_notice("nested: bailout after tail-trim"); - return false; - } - - if (!keyspace_overflow && (should_continue() || !clear_wholetable_passed || - !clear_stepbystep_passed)) { - unsigned underutilization_x256 = - txn_underutilization_x256(txn_guard.get()); - if (dbfull_passed > underutilization_x256) { - log_notice("nested: skip head-grow to avoid one more dbfull (was %u, " - "underutilization %.2f%%)", - dbfull_passed, underutilization_x256 / 2.560); - continue; - } - if (!grow_head(head_count)) - return false; - if (!stochastic_breakable_restart_with_nested()) - log_notice("nested: skip commit/restart after head-grow"); - if (!speculum_verify()) { - log_notice("nested: bailout after head-grow"); - return false; - } - loops += 1; - } else if (fifo.empty()) { - log_notice("nested: done %u whole loops, %" PRIu64 " ops, %" PRIu64 - " items", - loops, nops_completed, serial); - break; - } else { - log_notice("nested: done, wait for empty, skip head-grow"); - } - } - - while (!stack.empty()) - pop_txn(false); - - return speculum_verify(); -} diff --git a/libs/libmdbx/src/test/osal-unix.cc b/libs/libmdbx/src/test/osal-unix.cc deleted file mode 100644 index a85ce32a11..0000000000 --- a/libs/libmdbx/src/test/osal-unix.cc +++ /dev/null @@ -1,537 +0,0 @@ -/* - * Copyright 2017-2020 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" - -#if !(defined(_WIN32) || defined(_WIN64)) - -#include <pthread.h> -#include <signal.h> -#include <sys/mman.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include <atomic> - -#ifndef MDBX_LOCKING -#error "Opps, MDBX_LOCKING is undefined!" -#endif - -#if defined(__APPLE__) && (MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || \ - MDBX_LOCKING == MDBX_LOCKING_POSIX2008) -#include "darwin/pthread_barrier.c" -#endif /* __APPLE__ && MDBX_LOCKING >= MDBX_LOCKING_POSIX2001 */ - -#if MDBX_LOCKING == MDBX_LOCKING_SYSV -#include <sys/ipc.h> -#include <sys/sem.h> -#endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */ - -#if MDBX_LOCKING == MDBX_LOCKING_POSIX1988 -#include <semaphore.h> - -#if __cplusplus >= 201103L -#include <atomic> -static __inline __maybe_unused int atomic_decrement(std::atomic_int *p) { - return std::atomic_fetch_sub(p, 1) - 1; -} -#else -static __inline __maybe_unused int atomic_decrement(volatile int *p) { -#if defined(__GNUC__) || defined(__clang__) - return __sync_sub_and_fetch(p, 1); -#elif defined(_MSC_VER) - STATIC_ASSERT(sizeof(volatile long) == sizeof(volatile int)); - return _InterlockedDecrement((volatile long *)p); -#elif defined(__APPLE__) - return OSAtomicDecrement32Barrier((volatile int *)p); -#else -#error FIXME: Unsupported compiler -#endif -} -#endif /* C++11 */ -#endif /* MDBX_LOCKING == MDBX_LOCKING_POSIX1988 */ - -#if MDBX_LOCKING == MDBX_LOCKING_SYSV -static int ipc; -static pid_t ipc_overlord_pid; -static void ipc_remove(void) { - if (ipc_overlord_pid == getpid()) - semctl(ipc, 0, IPC_RMID, nullptr); -} - -#else -struct shared_t { -#if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || \ - MDBX_LOCKING == MDBX_LOCKING_POSIX2008 - pthread_barrier_t barrier; - pthread_mutex_t mutex; - size_t count; - pthread_cond_t events[1]; -#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988 - struct { -#if __cplusplus >= 201103L - std::atomic_int countdown; -#else - volatile int countdown; -#endif /* C++11 */ - sem_t sema; - } barrier; - size_t count; - sem_t events[1]; -#else -#error "FIXME" -#endif /* MDBX_LOCKING */ -}; -static shared_t *shared; -#endif /* MDBX_LOCKING != MDBX_LOCKING_SYSV */ - -void osal_wait4barrier(void) { -#if MDBX_LOCKING == MDBX_LOCKING_SYSV - struct sembuf op; - op.sem_num = 0; - op.sem_op = -1; - op.sem_flg = IPC_NOWAIT; - if (semop(ipc, &op, 1)) - failure_perror("semop(dec)", errno); - op.sem_op = 0; - op.sem_flg = 0; - if (semop(ipc, &op, 1)) - failure_perror("semop(wait)", errno); -#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || \ - MDBX_LOCKING == MDBX_LOCKING_POSIX2008 - assert(shared != nullptr && shared != MAP_FAILED); - int err = pthread_barrier_wait(&shared->barrier); - if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) - failure_perror("pthread_barrier_wait(shared)", err); -#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988 - assert(shared != nullptr && shared != MAP_FAILED); - int err = (atomic_decrement(&shared->barrier.countdown) > 0 && - sem_wait(&shared->barrier.sema)) - ? errno - : 0; - if (err != 0) - failure_perror("sem_wait(shared)", err); - if (sem_post(&shared->barrier.sema)) - failure_perror("sem_post(shared)", errno); -#else -#error "FIXME" -#endif /* MDBX_LOCKING */ -} - -void osal_setup(const std::vector<actor_config> &actors) { -#if MDBX_LOCKING == MDBX_LOCKING_SYSV - if (ipc_overlord_pid) - failure("ipc already created by %ld pid", (long)ipc_overlord_pid); - ipc_overlord_pid = getpid(); -#ifndef SEM_A -#define SEM_A S_IRUSR -#endif -#ifndef SEM_R -#define SEM_R S_IWUSR -#endif - ipc = semget(IPC_PRIVATE, actors.size() + 2, IPC_CREAT | SEM_A | SEM_R); - if (ipc < 0) - failure_perror("semget(IPC_PRIVATE, shared_sems)", errno); - if (atexit(ipc_remove)) - failure_perror("atexit(ipc_remove)", errno); - if (semctl(ipc, 0, SETVAL, (int)(actors.size() + 1))) - failure_perror("semctl(SETVAL.0, shared_sems)", errno); - for (size_t i = 1; i < actors.size() + 2; ++i) - if (semctl(ipc, i, SETVAL, 1)) - failure_perror("semctl(SETVAL.N, shared_sems)", errno); -#else - assert(shared == nullptr); - shared = (shared_t *)mmap( - nullptr, sizeof(shared_t) + actors.size() * sizeof(shared->events[0]), - PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS -#ifdef MAP_HASSEMAPHORE - | MAP_HASSEMAPHORE -#endif - , - -1, 0); - if (MAP_FAILED == (void *)shared) - failure_perror("mmap(shared_conds)", errno); - - shared->count = actors.size() + 1; - -#if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || \ - MDBX_LOCKING == MDBX_LOCKING_POSIX2008 - pthread_barrierattr_t barrierattr; - int err = pthread_barrierattr_init(&barrierattr); - if (err) - failure_perror("pthread_barrierattr_init()", err); - err = pthread_barrierattr_setpshared(&barrierattr, PTHREAD_PROCESS_SHARED); - if (err) - failure_perror("pthread_barrierattr_setpshared()", err); - - err = pthread_barrier_init(&shared->barrier, &barrierattr, shared->count); - if (err) - failure_perror("pthread_barrier_init(shared)", err); - pthread_barrierattr_destroy(&barrierattr); - - pthread_mutexattr_t mutexattr; - err = pthread_mutexattr_init(&mutexattr); - if (err) - failure_perror("pthread_mutexattr_init()", err); - err = pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED); - if (err) - failure_perror("pthread_mutexattr_setpshared()", err); - - pthread_condattr_t condattr; - err = pthread_condattr_init(&condattr); - if (err) - failure_perror("pthread_condattr_init()", err); - err = pthread_condattr_setpshared(&condattr, PTHREAD_PROCESS_SHARED); - if (err) - failure_perror("pthread_condattr_setpshared()", err); - - err = pthread_mutex_init(&shared->mutex, &mutexattr); - if (err) - failure_perror("pthread_mutex_init(shared)", err); - - for (size_t i = 0; i < shared->count; ++i) { - pthread_cond_t *event = &shared->events[i]; - err = pthread_cond_init(event, &condattr); - if (err) - failure_perror("pthread_cond_init(shared)", err); - log_trace("osal_setup: event(shared pthread_cond) %" PRIuPTR " -> %p", i, - __Wpedantic_format_voidptr(event)); - } - pthread_condattr_destroy(&condattr); - pthread_mutexattr_destroy(&mutexattr); -#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988 - shared->barrier.countdown = shared->count; - if (sem_init(&shared->barrier.sema, true, 1)) - failure_perror("sem_init(shared.barrier)", errno); - for (size_t i = 0; i < shared->count; ++i) { - sem_t *event = &shared->events[i]; - if (sem_init(event, true, 0)) - failure_perror("sem_init(shared.event)", errno); - log_trace("osal_setup: event(shared sem_init) %" PRIuPTR " -> %p", i, - __Wpedantic_format_voidptr(event)); - } -#else -#error "FIXME" -#endif /* MDBX_LOCKING */ -#endif /* MDBX_LOCKING != MDBX_LOCKING_SYSV */ -} - -void osal_broadcast(unsigned id) { - log_trace("osal_broadcast: event %u", id); -#if MDBX_LOCKING == MDBX_LOCKING_SYSV - if (semctl(ipc, id + 1, SETVAL, 0)) - failure_perror("semctl(SETVAL)", errno); -#else - assert(shared != nullptr && shared != MAP_FAILED); - if (id >= shared->count) - failure("osal_broadcast: id > limit"); -#if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || \ - MDBX_LOCKING == MDBX_LOCKING_POSIX2008 - int err = pthread_cond_broadcast(shared->events + id); - if (err) - failure_perror("pthread_cond_broadcast(shared)", err); -#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988 - if (sem_post(shared->events + id)) - failure_perror("sem_post(shared)", errno); -#else -#error "FIXME" -#endif /* MDBX_LOCKING */ -#endif /* MDBX_LOCKING != MDBX_LOCKING_SYSV */ -} - -int osal_waitfor(unsigned id) { - log_trace("osal_waitfor: event %u", id); -#if MDBX_LOCKING == MDBX_LOCKING_SYSV - struct sembuf op; - memset(&op, 0, sizeof(op)); - op.sem_num = (short)(id + 1); - int rc = semop(ipc, &op, 1) ? errno : MDBX_SUCCESS; -#else - assert(shared != nullptr && shared != MAP_FAILED); - if (id >= shared->count) - failure("osal_waitfor: id > limit"); - -#if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || \ - MDBX_LOCKING == MDBX_LOCKING_POSIX2008 - int rc = pthread_mutex_lock(&shared->mutex); - if (rc != 0) - failure_perror("pthread_mutex_lock(shared)", rc); - - rc = pthread_cond_wait(shared->events + id, &shared->mutex); - if (rc && rc != EINTR) - failure_perror("pthread_cond_wait(shared)", rc); - - rc = pthread_mutex_unlock(&shared->mutex); - if (rc != 0) - failure_perror("pthread_mutex_unlock(shared)", rc); -#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988 - int rc = sem_wait(shared->events + id) ? errno : 0; - if (rc == 0 && sem_post(shared->events + id)) - failure_perror("sem_post(shared)", errno); -#else -#error "FIXME" -#endif /* MDBX_LOCKING */ -#endif /* MDBX_LOCKING != MDBX_LOCKING_SYSV */ - - return (rc == 0) ? true : false; -} - -//----------------------------------------------------------------------------- - -const std::string -actor_config::osal_serialize(simple_checksum &checksum) const { - (void)checksum; - /* not used in workload, but just for testing */ - return "unix.fork"; -} - -bool actor_config::osal_deserialize(const char *str, const char *end, - simple_checksum &checksum) { - (void)checksum; - /* not used in workload, but just for testing */ - return strncmp(str, "unix.fork", 9) == 0 && str + 9 == end; -} - -//----------------------------------------------------------------------------- - -static pid_t overlord_pid; - -static std::atomic<int> sigusr1_head, sigusr2_head; -static void handler_SIGUSR(int signum) { - switch (signum) { - case SIGUSR1: - ++sigusr1_head; - return; - case SIGUSR2: - ++sigusr2_head; - return; - default: - abort(); - } -} - -bool osal_progress_push(bool active) { - if (overlord_pid) { - if (kill(overlord_pid, active ? SIGUSR1 : SIGUSR2)) - failure_perror("osal_progress_push: kill(overload)", errno); - return true; - } - - return false; -} - -//----------------------------------------------------------------------------- - -static std::unordered_map<pid_t, actor_status> childs; - -static std::atomic<int> sigalarm_head; -static void handler_SIGCHLD(int signum) { - if (signum == SIGALRM) - ++sigalarm_head; -} - -mdbx_pid_t osal_getpid(void) { return getpid(); } - -int osal_delay(unsigned seconds) { return sleep(seconds) ? errno : 0; } - -int osal_actor_start(const actor_config &config, mdbx_pid_t &pid) { - if (childs.empty()) { - struct sigaction act; - memset(&act, 0, sizeof(act)); - act.sa_handler = handler_SIGCHLD; - sigaction(SIGCHLD, &act, nullptr); - sigaction(SIGALRM, &act, nullptr); - act.sa_handler = handler_SIGUSR; - sigaction(SIGUSR1, &act, nullptr); - sigaction(SIGUSR2, &act, nullptr); - - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGCHLD); - sigaddset(&mask, SIGUSR1); - sigaddset(&mask, SIGUSR2); - sigprocmask(SIG_UNBLOCK, &mask, nullptr); - } - - pid = fork(); - - if (pid == 0) { - overlord_pid = getppid(); - const bool result = test_execute(config); - exit(result ? EXIT_SUCCESS : EXIT_FAILURE); - } - - if (pid < 0) - return errno; - - log_trace("osal_actor_start: fork pid %ld for %u", (long)pid, - config.actor_id); - childs[pid] = as_running; - return 0; -} - -actor_status osal_actor_info(const mdbx_pid_t pid) { return childs.at(pid); } - -void osal_killall_actors(void) { - for (auto &pair : childs) { - kill(pair.first, SIGKILL); - pair.second = as_killed; - } -} - -int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) { - static sig_atomic_t sigalarm_tail; - alarm(0) /* cancel prev timeout */; - sigalarm_tail = sigalarm_head /* reset timeout flag */; - - int options = WNOHANG; - if (timeout) { - alarm((timeout > INT_MAX) ? INT_MAX : timeout); - options = 0; - } - -#ifdef WUNTRACED - options |= WUNTRACED; -#endif -#ifdef WCONTINUED - options |= WCONTINUED; -#endif - - while (sigalarm_tail == sigalarm_head) { - int status; - pid = waitpid(0, &status, options); - - if (pid > 0) { - if (WIFEXITED(status)) - childs[pid] = - (WEXITSTATUS(status) == EXIT_SUCCESS) ? as_successful : as_failed; - else if (WCOREDUMP(status)) - childs[pid] = as_coredump; - else if (WIFSIGNALED(status)) - childs[pid] = as_killed; - else if (WIFSTOPPED(status)) - childs[pid] = as_debugging; - else if (WIFCONTINUED(status)) - childs[pid] = as_running; - else { - assert(false); - } - return 0; - } - - static sig_atomic_t sigusr1_tail, sigusr2_tail; - if (sigusr1_tail != sigusr1_head) { - sigusr1_tail = sigusr1_head; - logging::progress_canary(true); - if (pid < 0 && errno == EINTR) - continue; - } - if (sigusr2_tail != sigusr2_head) { - sigusr2_tail = sigusr2_head; - logging::progress_canary(false); - if (pid < 0 && errno == EINTR) - continue; - } - - if (pid == 0) - break; - - int err = errno; - if (err != EINTR) - return err; - } - return 0 /* timeout */; -} - -void osal_yield(void) { - if (sched_yield()) - failure_perror("sched_yield()", errno); -} - -void osal_udelay(unsigned us) { - chrono::time until, now = chrono::now_motonic(); - until.fixedpoint = now.fixedpoint + chrono::from_us(us).fixedpoint; - struct timespec ts; - - static unsigned threshold_us; - if (threshold_us == 0) { -#if defined(_POSIX_CPUTIME) && _POSIX_CPUTIME > -1 && \ - defined(CLOCK_PROCESS_CPUTIME_ID) - if (clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts)) { - int rc = errno; - log_warning("clock_getres(CLOCK_PROCESS_CPUTIME_ID), failed errno %d", - rc); - } -#endif /* CLOCK_PROCESS_CPUTIME_ID */ - if (threshold_us == 0 && clock_getres(CLOCK_MONOTONIC, &ts)) { - int rc = errno; - failure_perror("clock_getres(CLOCK_MONOTONIC)", rc); - } - chrono::time threshold = chrono::from_timespec(ts); - assert(threshold.seconds() == 0); - - threshold_us = chrono::fractional2us(threshold.fractional); - if (threshold_us < 1000) - threshold_us = 1000; - } - - ts.tv_sec = ts.tv_nsec = 0; - if (us > threshold_us) { - ts.tv_sec = us / 1000000u; - ts.tv_nsec = (us % 1000000u) * 1000u; - } - - do { - if (us > threshold_us) { - if (nanosleep(&ts, &ts)) { - int rc = errno; - /* if (rc == EINTR) { ... } ? */ - failure_perror("usleep()", rc); - } - us = ts.tv_sec * 1000000u + ts.tv_nsec / 1000u; - } - cpu_relax(); - - now = chrono::now_motonic(); - } while (until.fixedpoint > now.fixedpoint); -} - -bool osal_istty(int fd) { return isatty(fd) == 1; } - -std::string osal_tempdir(void) { - const char *tempdir = getenv("TMPDIR"); - if (!tempdir) - tempdir = getenv("TMP"); - if (!tempdir) - tempdir = getenv("TEMPDIR"); - if (!tempdir) - tempdir = getenv("TEMP"); - if (tempdir && *tempdir) { - std::string dir(tempdir); - if (dir.back() != '/') - dir.append("/"); - return dir; - } - if (access("/dev/shm/", R_OK | W_OK | X_OK) == 0) - return "/dev/shm/"; - return ""; -} - -int osal_removefile(const std::string &pathname) { - return unlink(pathname.c_str()) ? errno : MDBX_SUCCESS; -} - -#endif /* !Windows */ diff --git a/libs/libmdbx/src/test/osal-windows.cc b/libs/libmdbx/src/test/osal-windows.cc deleted file mode 100644 index 9bde047a2c..0000000000 --- a/libs/libmdbx/src/test/osal-windows.cc +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright 2017-2020 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" - -#if defined(_WIN32) || defined(_WIN64) - -static std::unordered_map<unsigned, HANDLE> events; -static HANDLE hBarrierSemaphore, hBarrierEvent; -static HANDLE hProgressActiveEvent, hProgressPassiveEvent; - -static int waitstatus2errcode(DWORD result) { - switch (result) { - case WAIT_OBJECT_0: - return MDBX_SUCCESS; - case WAIT_FAILED: - return GetLastError(); - case WAIT_ABANDONED: - return ERROR_ABANDONED_WAIT_0; - case WAIT_IO_COMPLETION: - return ERROR_USER_APC; - case WAIT_TIMEOUT: - return ERROR_TIMEOUT; - default: - return ERROR_UNHANDLED_ERROR; - } -} - -void osal_wait4barrier(void) { - DWORD rc = WaitForSingleObject(hBarrierSemaphore, 0); - switch (rc) { - default: - failure_perror("WaitForSingleObject(BarrierSemaphore)", - waitstatus2errcode(rc)); - case WAIT_OBJECT_0: - rc = WaitForSingleObject(hBarrierEvent, INFINITE); - if (rc != WAIT_OBJECT_0) - failure_perror("WaitForSingleObject(BarrierEvent)", - waitstatus2errcode(rc)); - break; - case WAIT_TIMEOUT: - if (!SetEvent(hBarrierEvent)) - failure_perror("SetEvent(BarrierEvent)", GetLastError()); - break; - } -} - -static HANDLE make_inheritable(HANDLE hHandle) { - assert(hHandle != NULL && hHandle != INVALID_HANDLE_VALUE); - if (!DuplicateHandle(GetCurrentProcess(), hHandle, GetCurrentProcess(), - &hHandle, 0, TRUE, - DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) - failure_perror("DuplicateHandle()", GetLastError()); - return hHandle; -} - -void osal_setup(const std::vector<actor_config> &actors) { - assert(events.empty()); - const size_t n = actors.size() + 1; - events.reserve(n); - - for (unsigned i = 0; i < n; ++i) { - HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!hEvent) - failure_perror("CreateEvent()", GetLastError()); - hEvent = make_inheritable(hEvent); - log_trace("osal_setup: event %" PRIuPTR " -> %p", i, hEvent); - events[i] = hEvent; - } - - hBarrierSemaphore = CreateSemaphore(NULL, 0, (LONG)actors.size(), NULL); - if (!hBarrierSemaphore) - failure_perror("CreateSemaphore(BarrierSemaphore)", GetLastError()); - hBarrierSemaphore = make_inheritable(hBarrierSemaphore); - - hBarrierEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!hBarrierEvent) - failure_perror("CreateEvent(BarrierEvent)", GetLastError()); - hBarrierEvent = make_inheritable(hBarrierEvent); - - hProgressActiveEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!hProgressActiveEvent) - failure_perror("CreateEvent(ProgressActiveEvent)", GetLastError()); - hProgressActiveEvent = make_inheritable(hProgressActiveEvent); - - hProgressPassiveEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!hProgressPassiveEvent) - failure_perror("CreateEvent(ProgressPassiveEvent)", GetLastError()); - hProgressPassiveEvent = make_inheritable(hProgressPassiveEvent); -} - -void osal_broadcast(unsigned id) { - log_trace("osal_broadcast: event %u", id); - if (!SetEvent(events.at(id))) - failure_perror("SetEvent()", GetLastError()); -} - -int osal_waitfor(unsigned id) { - log_trace("osal_waitfor: event %u", id); - DWORD rc = WaitForSingleObject(events.at(id), INFINITE); - return waitstatus2errcode(rc); -} - -mdbx_pid_t osal_getpid(void) { return GetCurrentProcessId(); } - -int osal_delay(unsigned seconds) { - Sleep(seconds * 1000u); - return 0; -} - -//----------------------------------------------------------------------------- - -const std::string -actor_config::osal_serialize(simple_checksum &checksum) const { - checksum.push(hBarrierSemaphore); - checksum.push(hBarrierEvent); - checksum.push(hProgressActiveEvent); - checksum.push(hProgressPassiveEvent); - - HANDLE hWait = INVALID_HANDLE_VALUE; - if (wait4id) { - hWait = events.at(wait4id); - checksum.push(hWait); - } - - HANDLE hSignal = INVALID_HANDLE_VALUE; - if (wanna_event4signalling()) { - hSignal = events.at(actor_id); - checksum.push(hSignal); - } - - return format("%p.%p.%p.%p.%p.%p", hBarrierSemaphore, hBarrierEvent, hWait, - hSignal, hProgressActiveEvent, hProgressPassiveEvent); -} - -bool actor_config::osal_deserialize(const char *str, const char *end, - simple_checksum &checksum) { - - std::string copy(str, end - str); - TRACE(">> osal_deserialize(%s)\n", copy.c_str()); - - assert(hBarrierSemaphore == 0); - assert(hBarrierEvent == 0); - assert(hProgressActiveEvent == 0); - assert(hProgressPassiveEvent == 0); - assert(events.empty()); - - HANDLE hWait, hSignal; - if (sscanf_s(copy.c_str(), "%p.%p.%p.%p.%p.%p", &hBarrierSemaphore, - &hBarrierEvent, &hWait, &hSignal, &hProgressActiveEvent, - &hProgressPassiveEvent) != 6) { - TRACE("<< osal_deserialize: failed\n"); - return false; - } - - checksum.push(hBarrierSemaphore); - checksum.push(hBarrierEvent); - checksum.push(hProgressActiveEvent); - checksum.push(hProgressPassiveEvent); - - if (wait4id) { - checksum.push(hWait); - events[wait4id] = hWait; - } - - if (wanna_event4signalling()) { - checksum.push(hSignal); - events[actor_id] = hSignal; - } - - TRACE("<< osal_deserialize: OK\n"); - return true; -} - -//----------------------------------------------------------------------------- - -typedef std::pair<HANDLE, actor_status> child; -static std::unordered_map<mdbx_pid_t, child> childs; - -bool osal_progress_push(bool active) { - if (!childs.empty()) { - if (!SetEvent(active ? hProgressActiveEvent : hProgressPassiveEvent)) - failure_perror("osal_progress_push: SetEvent(overlord.progress)", - GetLastError()); - return true; - } - - return false; -} - -static void ArgvQuote(std::string &CommandLine, const std::string &Argument, - bool Force = false) - -/*++ - -https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ - -Routine Description: - - This routine appends the given argument to a command line such - that CommandLineToArgvW will return the argument string unchanged. - Arguments in a command line should be separated by spaces; this - function does not add these spaces. - -Arguments: - - Argument - Supplies the argument to encode. - - CommandLine - Supplies the command line to which we append the encoded -argument string. - - Force - Supplies an indication of whether we should quote - the argument even if it does not contain any characters that would - ordinarily require quoting. - -Return Value: - - None. - -Environment: - - Arbitrary. - ---*/ - -{ - // - // Unless we're told otherwise, don't quote unless we actually - // need to do so --- hopefully avoid problems if programs won't - // parse quotes properly - // - - if (Force == false && Argument.empty() == false && - Argument.find_first_of(" \t\n\v\"") == Argument.npos) { - CommandLine.append(Argument); - } else { - CommandLine.push_back('"'); - - for (auto It = Argument.begin();; ++It) { - unsigned NumberBackslashes = 0; - - while (It != Argument.end() && *It == '\\') { - ++It; - ++NumberBackslashes; - } - - if (It == Argument.end()) { - // - // Escape all backslashes, but let the terminating - // double quotation mark we add below be interpreted - // as a metacharacter. - // - CommandLine.append(NumberBackslashes * 2, '\\'); - break; - } else if (*It == L'"') { - // - // Escape all backslashes and the following - // double quotation mark. - // - CommandLine.append(NumberBackslashes * 2 + 1, '\\'); - CommandLine.push_back(*It); - } else { - // - // Backslashes aren't special here. - // - CommandLine.append(NumberBackslashes, '\\'); - CommandLine.push_back(*It); - } - } - - CommandLine.push_back('"'); - } -} - -int osal_actor_start(const actor_config &config, mdbx_pid_t &pid) { - if (childs.size() == MAXIMUM_WAIT_OBJECTS) - failure("Could't manage more that %u actors on Windows\n", - MAXIMUM_WAIT_OBJECTS); - - _flushall(); - - STARTUPINFOA StartupInfo; - GetStartupInfoA(&StartupInfo); - - char exename[_MAX_PATH + 1]; - DWORD exename_size = sizeof(exename); - if (!QueryFullProcessImageNameA(GetCurrentProcess(), 0, exename, - &exename_size)) - failure_perror("QueryFullProcessImageName()", GetLastError()); - - if (exename[1] != ':') { - exename_size = GetModuleFileName(NULL, exename, sizeof(exename)); - if (exename_size >= sizeof(exename)) - return ERROR_BAD_LENGTH; - } - - std::string cmdline = "$ "; - ArgvQuote(cmdline, thunk_param(config)); - - if (cmdline.size() >= 32767) - return ERROR_BAD_LENGTH; - - PROCESS_INFORMATION ProcessInformation; - if (!CreateProcessA(exename, const_cast<char *>(cmdline.c_str()), - NULL, // Retuned process handle is not inheritable. - NULL, // Retuned thread handle is not inheritable. - TRUE, // Child inherits all inheritable handles. - NORMAL_PRIORITY_CLASS | INHERIT_PARENT_AFFINITY, - NULL, // Inherit the parent's environment. - NULL, // Inherit the parent's current directory. - &StartupInfo, &ProcessInformation)) - failure_perror(exename, GetLastError()); - - CloseHandle(ProcessInformation.hThread); - pid = ProcessInformation.dwProcessId; - childs[pid] = std::make_pair(ProcessInformation.hProcess, as_running); - return 0; -} - -actor_status osal_actor_info(const mdbx_pid_t pid) { - actor_status status = childs.at(pid).second; - if (status > as_running) - return status; - - DWORD ExitCode; - if (!GetExitCodeProcess(childs.at(pid).first, &ExitCode)) - failure_perror("GetExitCodeProcess()", GetLastError()); - - switch (ExitCode) { - case STILL_ACTIVE: - return as_running; - case EXIT_SUCCESS: - status = as_successful; - break; - case EXCEPTION_BREAKPOINT: - case EXCEPTION_SINGLE_STEP: - status = as_debugging; - break; - case STATUS_CONTROL_C_EXIT: - status = as_killed; - break; - case EXCEPTION_ACCESS_VIOLATION: - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - case EXCEPTION_DATATYPE_MISALIGNMENT: - case EXCEPTION_STACK_OVERFLOW: - case EXCEPTION_INVALID_DISPOSITION: - case EXCEPTION_ILLEGAL_INSTRUCTION: - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - status = as_coredump; - break; - default: - status = as_failed; - break; - } - - childs.at(pid).second = status; - return status; -} - -void osal_killall_actors(void) { - for (auto &pair : childs) - TerminateProcess(pair.second.first, STATUS_CONTROL_C_EXIT); -} - -int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) { - std::vector<HANDLE> handles; - handles.reserve(childs.size() + 2); - handles.push_back(hProgressActiveEvent); - handles.push_back(hProgressPassiveEvent); - for (const auto &pair : childs) - if (pair.second.second <= as_running) - handles.push_back(pair.second.first); - - while (true) { - DWORD rc = - MsgWaitForMultipleObjectsEx((DWORD)handles.size(), &handles[0], - (timeout > 60) ? 60 * 1000 : timeout * 1000, - QS_ALLINPUT | QS_ALLPOSTMESSAGE, 0); - - if (rc == WAIT_OBJECT_0) { - logging::progress_canary(true); - continue; - } - if (rc == WAIT_OBJECT_0 + 1) { - logging::progress_canary(false); - continue; - } - - if (rc >= WAIT_OBJECT_0 + 2 && rc < WAIT_OBJECT_0 + handles.size()) { - pid = 0; - for (const auto &pair : childs) - if (pair.second.first == handles[rc - WAIT_OBJECT_0]) { - pid = pair.first; - break; - } - return 0; - } - - if (rc == WAIT_TIMEOUT) { - pid = 0; - return 0; - } - - return waitstatus2errcode(rc); - } -} - -void osal_yield(void) { SwitchToThread(); } - -void osal_udelay(unsigned us) { - chrono::time until, now = chrono::now_motonic(); - until.fixedpoint = now.fixedpoint + chrono::from_us(us).fixedpoint; - - static unsigned threshold_us; - if (threshold_us == 0) { - unsigned timeslice_ms = 1; - while (timeBeginPeriod(timeslice_ms) == TIMERR_NOCANDO) - ++timeslice_ms; - threshold_us = timeslice_ms * 1500u; - assert(threshold_us > 0); - } - - do { - if (us > threshold_us && us > 1000) { - DWORD rc = SleepEx(us / 1000, TRUE); - if (rc) - failure_perror("SleepEx()", waitstatus2errcode(rc)); - us = 0; - } - - YieldProcessor(); - now = chrono::now_motonic(); - } while (now.fixedpoint < until.fixedpoint); -} - -bool osal_istty(int fd) { return _isatty(fd) != 0; } - -std::string osal_tempdir(void) { - char buf[MAX_PATH + 1]; - DWORD len = GetTempPathA(sizeof(buf), buf); - return std::string(buf, len); -} - -int osal_removefile(const std::string &pathname) { - return DeleteFileA(pathname.c_str()) ? MDBX_SUCCESS : GetLastError(); -} - -#endif /* Windows */ diff --git a/libs/libmdbx/src/test/osal.h b/libs/libmdbx/src/test/osal.h deleted file mode 100644 index e47450b931..0000000000 --- a/libs/libmdbx/src/test/osal.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2017-2020 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" - -void osal_setup(const std::vector<actor_config> &actors); -void osal_broadcast(unsigned id); -int osal_waitfor(unsigned id); - -int osal_actor_start(const actor_config &config, mdbx_pid_t &pid); -actor_status osal_actor_info(const mdbx_pid_t pid); -void osal_killall_actors(void); -int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout); -void osal_wait4barrier(void); - -bool osal_progress_push(bool active); - -mdbx_pid_t osal_getpid(void); -int osal_delay(unsigned seconds); -void osal_udelay(unsigned us); -void osal_yield(void); -bool osal_istty(int fd); -std::string osal_tempdir(void); -int osal_removefile(const std::string &pathname); - -#ifdef _MSC_VER -#ifndef STDIN_FILENO -#define STDIN_FILENO _fileno(stdin) -#endif -#ifndef STDOUT_FILENO -#define STDOUT_FILENO _fileno(stdout) -#endif -#ifndef STDERR_FILENO -#define STDERR_FILENO _fileno(stderr) -#endif -#endif /* _MSC_VER */ diff --git a/libs/libmdbx/src/test/pcrf/README.md b/libs/libmdbx/src/test/pcrf/README.md deleted file mode 100644 index b2c9b5ce95..0000000000 --- a/libs/libmdbx/src/test/pcrf/README.md +++ /dev/null @@ -1,2 +0,0 @@ -PCRF Session DB emulation test - diff --git a/libs/libmdbx/src/test/pcrf/pcrf_test.c b/libs/libmdbx/src/test/pcrf/pcrf_test.c deleted file mode 100644 index 2db58a023a..0000000000 --- a/libs/libmdbx/src/test/pcrf/pcrf_test.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * Copyright 2016-2020 Leonid Yuriev <leo@yuriev.ru>. - * Copyright 2015 Vladimir Romanov - * <https://www.linkedin.com/in/vladimirromanov>, Yota Lab. - * - * This file is part of libmdbx. - * - * ReOpenMDBX is free software; you can redistribute it and/or modify it under - * the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * ReOpenMDBX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <sys/stat.h> -#include <sys/time.h> - -#include "mdbx.h" -#include <assert.h> -#include <inttypes.h> -#include <limits.h> -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define IP_PRINTF_ARG_HOST(addr) \ - (int)((addr) >> 24), (int)((addr) >> 16 & 0xff), (int)((addr) >> 8 & 0xff), \ - (int)((addr)&0xff) - -char opt_db_path[PATH_MAX] = "./mdbx_bench2"; -static MDBX_env *env; -#define REC_COUNT 10240000 -int64_t ids[REC_COUNT * 10]; -int32_t ids_count = 0; - -int64_t mdbx_add_count = 0; -int64_t mdbx_del_count = 0; -uint64_t mdbx_add_time = 0; -uint64_t mdbx_del_time = 0; -int64_t obj_id = 0; -int64_t mdbx_data_size = 0; -int64_t mdbx_key_size = 0; - -typedef struct { - char session_id1[100]; - char session_id2[100]; - char ip[20]; - uint8_t fill[100]; -} session_data_t; - -typedef struct { - int64_t obj_id; - int8_t event_type; -} __attribute__((__packed__)) event_data_t; - -static void add_id_to_pool(int64_t id) { - ids[ids_count] = id; - ids_count++; -} - -static inline int64_t getClockUs(void) { - struct timespec val; -#ifdef CYGWIN - clock_gettime(CLOCK_REALTIME, &val); -#else - clock_gettime(CLOCK_MONOTONIC, &val); -#endif - return val.tv_sec * ((int64_t)1000000) + val.tv_nsec / 1000; -} - -static int64_t get_id_from_pool() { - if (ids_count == 0) { - return -1; - } - int32_t index = rand() % ids_count; - int64_t id = ids[index]; - ids[index] = ids[ids_count - 1]; - ids_count--; - return id; -} - -#define MDBX_CHECK(x) \ - do { \ - const int rc = (x); \ - if (rc != MDBX_SUCCESS) { \ - printf("Error [%d] %s in %s at %s:%d\n", rc, mdbx_strerror(rc), #x, \ - __FILE__, __LINE__); \ - exit(EXIT_FAILURE); \ - } \ - } while (0) - -static void db_connect() { - MDBX_dbi dbi_session; - MDBX_dbi dbi_session_id; - MDBX_dbi dbi_event; - MDBX_dbi dbi_ip; - - MDBX_CHECK(mdbx_env_create(&env)); - MDBX_CHECK(mdbx_env_set_geometry( - env, 0, 0, REC_COUNT * sizeof(session_data_t) * 10, -1, -1, -1)); - MDBX_CHECK(mdbx_env_set_maxdbs(env, 30)); - MDBX_CHECK(mdbx_env_open(env, opt_db_path, - MDBX_CREATE | MDBX_WRITEMAP | MDBX_MAPASYNC | - MDBX_SAFE_NOSYNC | MDBX_LIFORECLAIM, - 0664)); - MDBX_txn *txn; - - // transaction init - MDBX_CHECK(mdbx_txn_begin(env, NULL, 0, &txn)); - // open database in read-write mode - MDBX_CHECK(mdbx_dbi_open(txn, "session", MDBX_CREATE, &dbi_session)); - MDBX_CHECK(mdbx_dbi_open(txn, "session_id", MDBX_CREATE, &dbi_session_id)); - MDBX_CHECK(mdbx_dbi_open(txn, "event", MDBX_CREATE, &dbi_event)); - MDBX_CHECK(mdbx_dbi_open(txn, "ip", MDBX_CREATE, &dbi_ip)); - // transaction commit - MDBX_CHECK(mdbx_txn_commit(txn)); - printf("Connection open\n"); -} - -static void create_record(uint64_t record_id) { - MDBX_dbi dbi_session; - MDBX_dbi dbi_session_id; - MDBX_dbi dbi_event; - MDBX_dbi dbi_ip; - event_data_t event; - MDBX_txn *txn; - session_data_t data; - // transaction init - snprintf(data.session_id1, sizeof(data.session_id1), - "prefix%02u_%02u.fill.fill.fill.fill.fill.fill;%" PRIu64, - (unsigned)(record_id % 3) + 1, (unsigned)(record_id % 9) + 1, - record_id); - snprintf(data.session_id2, sizeof(data.session_id2), - "dprefix%" PRIu64 ";%" PRIu64 ".fill.fill.;suffix", record_id, - (record_id + UINT64_C(1442695040888963407)) % - UINT64_C(6364136223846793005)); - snprintf(data.ip, sizeof(data.ip), "%d.%d.%d.%d", - IP_PRINTF_ARG_HOST(record_id & 0xFFFFFFFF)); - event.obj_id = record_id; - event.event_type = 1; - - MDBX_val _session_id1_rec = {data.session_id1, strlen(data.session_id1)}; - MDBX_val _session_id2_rec = {data.session_id2, strlen(data.session_id2)}; - MDBX_val _ip_rec = {data.ip, strlen(data.ip)}; - MDBX_val _obj_id_rec = {&record_id, sizeof(record_id)}; - MDBX_val _data_rec = {&data, offsetof(session_data_t, fill) + - (rand() % sizeof(data.fill))}; - MDBX_val _event_rec = {&event, sizeof(event)}; - - uint64_t start = getClockUs(); - MDBX_CHECK(mdbx_txn_begin(env, NULL, 0, &txn)); - MDBX_CHECK(mdbx_dbi_open(txn, "session", MDBX_CREATE, &dbi_session)); - MDBX_CHECK(mdbx_dbi_open(txn, "session_id", MDBX_CREATE, &dbi_session_id)); - MDBX_CHECK(mdbx_dbi_open(txn, "event", MDBX_CREATE, &dbi_event)); - MDBX_CHECK(mdbx_dbi_open(txn, "ip", MDBX_CREATE, &dbi_ip)); - MDBX_CHECK(mdbx_put(txn, dbi_session, &_obj_id_rec, &_data_rec, - MDBX_NOOVERWRITE | MDBX_NODUPDATA)); - MDBX_CHECK(mdbx_put(txn, dbi_session_id, &_session_id1_rec, &_obj_id_rec, - MDBX_NOOVERWRITE | MDBX_NODUPDATA)); - MDBX_CHECK(mdbx_put(txn, dbi_session_id, &_session_id2_rec, &_obj_id_rec, - MDBX_NOOVERWRITE | MDBX_NODUPDATA)); - MDBX_CHECK(mdbx_put(txn, dbi_ip, &_ip_rec, &_obj_id_rec, 0)); - MDBX_CHECK(mdbx_put(txn, dbi_event, &_event_rec, &_obj_id_rec, 0)); - MDBX_CHECK(mdbx_txn_commit(txn)); - - mdbx_data_size += (_data_rec.iov_len + _obj_id_rec.iov_len * 4); - mdbx_key_size += - (_obj_id_rec.iov_len + _session_id1_rec.iov_len + - _session_id2_rec.iov_len + _ip_rec.iov_len + _event_rec.iov_len); - - // transaction commit - mdbx_add_count++; - mdbx_add_time += (getClockUs() - start); -} - -static void delete_record(int64_t record_id) { - MDBX_dbi dbi_session; - MDBX_dbi dbi_session_id; - MDBX_dbi dbi_event; - MDBX_dbi dbi_ip; - event_data_t event; - MDBX_txn *txn; - - // transaction init - uint64_t start = getClockUs(); - MDBX_CHECK(mdbx_txn_begin(env, NULL, 0, &txn)); - // open database in read-write mode - MDBX_CHECK(mdbx_dbi_open(txn, "session", MDBX_CREATE, &dbi_session)); - MDBX_CHECK(mdbx_dbi_open(txn, "session_id", MDBX_CREATE, &dbi_session_id)); - MDBX_CHECK(mdbx_dbi_open(txn, "event", MDBX_CREATE, &dbi_event)); - MDBX_CHECK(mdbx_dbi_open(txn, "ip", MDBX_CREATE, &dbi_ip)); - // put data - MDBX_val _obj_id_rec = {&record_id, sizeof(record_id)}; - MDBX_val _data_rec; - // get data - MDBX_CHECK(mdbx_get(txn, dbi_session, &_obj_id_rec, &_data_rec)); - session_data_t *data = (session_data_t *)_data_rec.iov_base; - - MDBX_val _session_id1_rec = {data->session_id1, strlen(data->session_id1)}; - MDBX_val _session_id2_rec = {data->session_id2, strlen(data->session_id2)}; - MDBX_val _ip_rec = {data->ip, strlen(data->ip)}; - MDBX_CHECK(mdbx_del(txn, dbi_session_id, &_session_id1_rec, NULL)); - MDBX_CHECK(mdbx_del(txn, dbi_session_id, &_session_id2_rec, NULL)); - MDBX_CHECK(mdbx_del(txn, dbi_ip, &_ip_rec, NULL)); - event.obj_id = record_id; - event.event_type = 1; - MDBX_val _event_rec = {&event, sizeof(event)}; - MDBX_CHECK(mdbx_del(txn, dbi_event, &_event_rec, NULL)); - MDBX_CHECK(mdbx_del(txn, dbi_session, &_obj_id_rec, NULL)); - - mdbx_data_size -= (_data_rec.iov_len + _obj_id_rec.iov_len * 4); - mdbx_key_size -= - (_obj_id_rec.iov_len + _session_id1_rec.iov_len + - _session_id2_rec.iov_len + _ip_rec.iov_len + _event_rec.iov_len); - - // transaction commit - MDBX_CHECK(mdbx_txn_commit(txn)); - mdbx_del_count++; - mdbx_del_time += (getClockUs() - start); -} - -static void db_disconnect() { - mdbx_env_close(env); - printf("Connection closed\n"); -} - -static void get_db_stat(const char *db, int64_t *ms_branch_pages, - int64_t *ms_leaf_pages) { - MDBX_txn *txn; - MDBX_stat stat; - MDBX_dbi dbi; - - MDBX_CHECK(mdbx_txn_begin(env, NULL, MDBX_RDONLY, &txn)); - MDBX_CHECK(mdbx_dbi_open(txn, db, MDBX_CREATE, &dbi)); - MDBX_CHECK(mdbx_dbi_stat(txn, dbi, &stat, sizeof(stat))); - mdbx_txn_abort(txn); - printf("%15s | %15" PRIu64 " | %5u | %10" PRIu64 " | %10" PRIu64 - " | %11" PRIu64 " |\n", - db, stat.ms_branch_pages, stat.ms_depth, stat.ms_entries, - stat.ms_leaf_pages, stat.ms_overflow_pages); - (*ms_branch_pages) += stat.ms_branch_pages; - (*ms_leaf_pages) += stat.ms_leaf_pages; -} - -static void periodic_stat(void) { - int64_t ms_branch_pages = 0; - int64_t ms_leaf_pages = 0; - MDBX_stat mst; - MDBX_envinfo mei; - MDBX_CHECK(mdbx_env_stat_ex(env, NULL, &mst, sizeof(mst))); - MDBX_CHECK(mdbx_env_info_ex(env, NULL, &mei, sizeof(mei))); - printf("Environment Info\n"); - printf(" Pagesize: %u\n", mst.ms_psize); - if (mei.mi_geo.lower != mei.mi_geo.upper) { - printf(" Dynamic datafile: %" PRIu64 "..%" PRIu64 " bytes (+%" PRIu64 - "/-%" PRIu64 "), %" PRIu64 "..%" PRIu64 " pages (+%" PRIu64 - "/-%" PRIu64 ")\n", - mei.mi_geo.lower, mei.mi_geo.upper, mei.mi_geo.grow, - mei.mi_geo.shrink, mei.mi_geo.lower / mst.ms_psize, - mei.mi_geo.upper / mst.ms_psize, mei.mi_geo.grow / mst.ms_psize, - mei.mi_geo.shrink / mst.ms_psize); - printf(" Current datafile: %" PRIu64 " bytes, %" PRIu64 " pages\n", - mei.mi_geo.current, mei.mi_geo.current / mst.ms_psize); - } else { - printf(" Fixed datafile: %" PRIu64 " bytes, %" PRIu64 " pages\n", - mei.mi_geo.current, mei.mi_geo.current / mst.ms_psize); - } - printf(" Current mapsize: %" PRIu64 " bytes, %" PRIu64 " pages \n", - mei.mi_mapsize, mei.mi_mapsize / mst.ms_psize); - printf(" Number of pages used: %" PRIu64 "\n", mei.mi_last_pgno + 1); - printf(" Last transaction ID: %" PRIu64 "\n", mei.mi_recent_txnid); - printf(" Tail transaction ID: %" PRIu64 " (%" PRIi64 ")\n", - mei.mi_latter_reader_txnid, - mei.mi_latter_reader_txnid - mei.mi_recent_txnid); - printf(" Max readers: %u\n", mei.mi_maxreaders); - printf(" Number of readers used: %u\n", mei.mi_numreaders); - - printf(" Name | ms_branch_pages | depth | entries | leaf_pages " - "| overf_pages |\n"); - get_db_stat("session", &ms_branch_pages, &ms_leaf_pages); - get_db_stat("session_id", &ms_branch_pages, &ms_leaf_pages); - get_db_stat("event", &ms_branch_pages, &ms_leaf_pages); - get_db_stat("ip", &ms_branch_pages, &ms_leaf_pages); - printf("%15s | %15" PRIu64 " | %5s | %10s | %10" PRIu64 " | %11s |\n", "", - ms_branch_pages, "", "", ms_leaf_pages, ""); - - static int64_t prev_add_count; - static int64_t prev_del_count; - static uint64_t prev_add_time; - static uint64_t prev_del_time; - static int64_t t = -1; - if (t > 0) { - int64_t delta = (getClockUs() - t); - printf("CPS: add %" PRIu64 ", delete %" PRIu64 - ", items processed - %" PRIu64 "K data=%" PRIu64 "K key=%" PRIu64 - "K\n", - (mdbx_add_count - prev_add_count) * 1000000 / delta, - (mdbx_del_count - prev_del_count) * 1000000 / delta, obj_id / 1024, - mdbx_data_size / 1024, mdbx_key_size / 1024); - printf("usage data=%" PRIu64 "%%", - ((mdbx_data_size + mdbx_key_size) * 100) / - ((ms_leaf_pages + ms_branch_pages) * 4096)); - if (prev_add_time != mdbx_add_time) { - printf(" Add : %" PRIu64 " c/s", (mdbx_add_count - prev_add_count) * - 1000000 / - (mdbx_add_time - prev_add_time)); - } - if (prev_del_time != mdbx_del_time) { - printf(" Del : %" PRIu64 " c/s", (mdbx_del_count - prev_del_count) * - 1000000 / - (mdbx_del_time - prev_del_time)); - } - if (mdbx_add_time) { - printf(" tAdd : %" PRIu64 " c/s", - mdbx_add_count * 1000000 / mdbx_add_time); - } - if (mdbx_del_time) { - printf(" tDel : %" PRIu64 " c/s", - mdbx_del_count * 1000000 / mdbx_del_time); - } - puts(""); - } - t = getClockUs(); - prev_add_count = mdbx_add_count; - prev_del_count = mdbx_del_count; - prev_add_time = mdbx_add_time; - prev_del_time = mdbx_del_time; -} - -#if 0 /* unused */ -static void periodic_add_rec() { - for (int i = 0; i < 10240; i++) { - if (ids_count <= REC_COUNT) { - int64_t id = obj_id++; - create_record(id); - add_id_to_pool(id); - } - if (ids_count > REC_COUNT) { - int64_t id = get_id_from_pool(); - delete_record(id); - } - } - periodic_stat(); -} -#endif - -int main(int argc, char **argv) { - (void)argc; - (void)argv; - - char filename[PATH_MAX]; - int i; - - strcpy(filename, opt_db_path); - strcat(filename, MDBX_DATANAME); - remove(filename); - - strcpy(filename, opt_db_path); - strcat(filename, MDBX_LOCKNAME); - remove(filename); - - puts("Open DB..."); - db_connect(); - puts("Create data..."); - int64_t t = getClockUs(); - for (i = 0; i < REC_COUNT; i++) { - int64_t id = obj_id++; - create_record(id); - add_id_to_pool(id); - if (i % 1000 == 0) { - int64_t now = getClockUs(); - if ((now - t) > 1000000L) { - periodic_stat(); - t = now; - } - } - } - periodic_stat(); - while (1) { - int i; - for (i = 0; i < 1000; i++) { - int64_t id = obj_id++; - create_record(id); - add_id_to_pool(id); - id = get_id_from_pool(); - delete_record(id); - } - for (i = 0; i < 50; i++) { - int64_t id = obj_id++; - create_record(id); - add_id_to_pool(id); - } - int64_t id = obj_id++; - create_record(id); - add_id_to_pool(id); - int64_t now = getClockUs(); - if ((now - t) > 10000000L) { - periodic_stat(); - t = now; - } - } - db_disconnect(); - return 0; -} diff --git a/libs/libmdbx/src/test/test.cc b/libs/libmdbx/src/test/test.cc deleted file mode 100644 index 9af04ac9b0..0000000000 --- a/libs/libmdbx/src/test/test.cc +++ /dev/null @@ -1,755 +0,0 @@ -/* - * Copyright 2017-2020 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" - -const char *testcase2str(const actor_testcase testcase) { - switch (testcase) { - default: - assert(false); - return "?!"; - case ac_none: - return "none"; - case ac_hill: - return "hill"; - case ac_deadread: - return "deadread"; - case ac_deadwrite: - return "deadwrite"; - case ac_jitter: - return "jitter"; - case ac_try: - return "try"; - case ac_copy: - return "copy"; - case ac_append: - return "append"; - case ac_ttl: - return "ttl"; - case ac_nested: - return "nested"; - } -} - -const char *status2str(actor_status status) { - switch (status) { - default: - assert(false); - return "?!"; - case as_debugging: - return "debugging"; - case as_running: - return "running"; - case as_successful: - return "successful"; - case as_killed: - return "killed"; - case as_failed: - return "failed"; - case as_coredump: - return "coredump"; - } -} - -const char *keygencase2str(const keygen_case keycase) { - switch (keycase) { - default: - assert(false); - return "?!"; - case kc_random: - return "random"; - case kc_dashes: - return "dashes"; - case kc_custom: - return "custom"; - } -} - -//----------------------------------------------------------------------------- - -int testcase::oom_callback(MDBX_env *env, mdbx_pid_t pid, mdbx_tid_t tid, - uint64_t txn, unsigned gap, size_t space, - int retry) { - - testcase *self = (testcase *)mdbx_env_get_userctx(env); - - if (retry == 0) - log_notice("oom_callback: waitfor pid %lu, thread %" PRIuPTR - ", txn #%" PRIu64 ", gap %d, scape %zu", - (long)pid, (size_t)tid, txn, gap, space); - - if (self->should_continue(true)) { - osal_yield(); - if (retry > 0) - osal_udelay(retry * 100); - return 0 /* always retry */; - } - - return -1; -} - -void testcase::db_prepare() { - log_trace(">> db_prepare"); - assert(!db_guard); - - MDBX_env *env = nullptr; - int rc = mdbx_env_create(&env); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_env_create()", rc); - - assert(env != nullptr); - db_guard.reset(env); - - rc = mdbx_env_set_userctx(env, this); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_env_set_userctx()", rc); - - rc = mdbx_env_set_maxreaders(env, config.params.max_readers); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_env_set_maxreaders()", rc); - - rc = mdbx_env_set_maxdbs(env, config.params.max_tables); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_env_set_maxdbs()", rc); - - rc = mdbx_env_set_oomfunc(env, testcase::oom_callback); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_env_set_oomfunc()", rc); - - rc = mdbx_env_set_geometry( - env, config.params.size_lower, config.params.size_now, - config.params.size_upper, config.params.growth_step, - config.params.shrink_threshold, config.params.pagesize); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_env_set_mapsize()", rc); - - log_trace("<< db_prepare"); -} - -void testcase::db_open() { - log_trace(">> db_open"); - - if (!db_guard) - db_prepare(); - - jitter_delay(true); - - unsigned mode = (unsigned)config.params.mode_flags; - if (config.params.random_writemap && flipcoin()) - mode ^= MDBX_WRITEMAP; - - actual_db_mode = mode; - int rc = mdbx_env_open(db_guard.get(), config.params.pathname_db.c_str(), - mode, 0640); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_env_open()", rc); - - log_trace("<< db_open"); -} - -void testcase::db_close() { - log_trace(">> db_close"); - cursor_guard.reset(); - txn_guard.reset(); - db_guard.reset(); - log_trace("<< db_close"); -} - -void testcase::txn_begin(bool readonly, unsigned flags) { - assert((flags & MDBX_RDONLY) == 0); - log_trace(">> txn_begin(%s, 0x%04X)", readonly ? "read-only" : "read-write", - flags); - assert(!txn_guard); - - MDBX_txn *txn = nullptr; - int rc = mdbx_txn_begin(db_guard.get(), nullptr, - readonly ? flags | MDBX_RDONLY : flags, &txn); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_txn_begin()", rc); - txn_guard.reset(txn); - need_speculum_assign = config.params.speculum && !readonly; - - log_trace("<< txn_begin(%s, 0x%04X)", readonly ? "read-only" : "read-write", - flags); -} - -int testcase::breakable_commit() { - log_trace(">> txn_commit"); - assert(txn_guard); - - MDBX_txn *txn = txn_guard.release(); - txn_inject_writefault(txn); - int rc = mdbx_txn_commit(txn); - if (unlikely(rc != MDBX_SUCCESS) && - (rc != MDBX_MAP_FULL || !config.params.ignore_dbfull)) - failure_perror("mdbx_txn_commit()", rc); - - if (need_speculum_assign) { - need_speculum_assign = false; - if (unlikely(rc != MDBX_SUCCESS)) - speculum = speculum_commited; - else - speculum_commited = speculum; - } - - log_trace("<< txn_commit: %s", rc ? "failed" : "Ok"); - return rc; -} - -unsigned testcase::txn_underutilization_x256(MDBX_txn *txn) const { - if (txn) { - MDBX_txn_info info; - int err = mdbx_txn_info(txn, &info, false); - if (unlikely(err != MDBX_SUCCESS)) - failure_perror("mdbx_txn_info()", err); - const size_t left = size_t(info.txn_space_leftover); - const size_t total = - size_t(info.txn_space_leftover) + size_t(info.txn_space_dirty); - return (unsigned)(left / (total >> 8)); - } - return 0; -} - -void testcase::txn_end(bool abort) { - log_trace(">> txn_end(%s)", abort ? "abort" : "commit"); - assert(txn_guard); - - MDBX_txn *txn = txn_guard.release(); - if (abort) { - int err = mdbx_txn_abort(txn); - if (unlikely(err != MDBX_SUCCESS)) - failure_perror("mdbx_txn_abort()", err); - if (need_speculum_assign) - speculum = speculum_commited; - } else { - txn_inject_writefault(txn); - int err = mdbx_txn_commit(txn); - if (unlikely(err != MDBX_SUCCESS)) - failure_perror("mdbx_txn_commit()", err); - if (need_speculum_assign) - speculum_commited = speculum; - } - - log_trace("<< txn_end(%s)", abort ? "abort" : "commit"); -} - -void testcase::cursor_open(MDBX_dbi handle) { - log_trace(">> cursor_open(%u)", handle); - assert(!cursor_guard); - assert(txn_guard); - - MDBX_cursor *cursor = nullptr; - int rc = mdbx_cursor_open(txn_guard.get(), handle, &cursor); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_cursor_open()", rc); - cursor_guard.reset(cursor); - - log_trace("<< cursor_open(%u)", handle); -} - -void testcase::cursor_close() { - log_trace(">> cursor_close()"); - assert(cursor_guard); - MDBX_cursor *cursor = cursor_guard.release(); - mdbx_cursor_close(cursor); - log_trace("<< cursor_close()"); -} - -int testcase::breakable_restart() { - int rc = MDBX_SUCCESS; - if (txn_guard) - rc = breakable_commit(); - if (cursor_guard) - cursor_close(); - txn_begin(false, 0); - return rc; -} - -void testcase::txn_restart(bool abort, bool readonly, unsigned flags) { - if (txn_guard) - txn_end(abort); - if (cursor_guard) - cursor_close(); - txn_begin(readonly, flags); -} - -void testcase::txn_inject_writefault(void) { - if (txn_guard) - txn_inject_writefault(txn_guard.get()); -} - -void testcase::txn_inject_writefault(MDBX_txn *txn) { - if (config.params.inject_writefaultn && txn) { - if (config.params.inject_writefaultn <= nops_completed && - (mdbx_txn_flags(txn) & MDBX_RDONLY) == 0) { - log_verbose( - "== txn_inject_writefault(): got %u nops or more, inject FAULT", - config.params.inject_writefaultn); - log_flush(); -#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) - TerminateProcess(GetCurrentProcess(), 42); -#else - raise(SIGKILL); -#endif - } - } -} - -bool testcase::wait4start() { - if (config.wait4id) { - log_trace(">> wait4start(%u)", config.wait4id); - assert(!global::singlemode); - int rc = osal_waitfor(config.wait4id); - if (rc) { - log_trace("<< wait4start(%u), failed %s", config.wait4id, - test_strerror(rc)); - return false; - } - } else { - log_trace("== skip wait4start: not needed"); - } - - if (config.params.delaystart) { - int rc = osal_delay(config.params.delaystart); - if (rc) { - log_trace("<< delay(%u), failed %s", config.params.delaystart, - test_strerror(rc)); - return false; - } - } else { - log_trace("== skip delay: not needed"); - } - - return true; -} - -void testcase::kick_progress(bool active) const { - if (!global::config::progress_indicator) - return; - logging::progress_canary(active); -} - -void testcase::report(size_t nops_done) { - assert(nops_done > 0); - if (!nops_done) - return; - - nops_completed += nops_done; - log_debug("== complete +%" PRIuPTR " iteration, total %" PRIu64 " done", - nops_done, nops_completed); - - kick_progress(true); - - if (config.signal_nops && !signalled && - config.signal_nops <= nops_completed) { - log_trace(">> signal(n-ops %" PRIu64 ")", nops_completed); - if (!global::singlemode) - osal_broadcast(config.actor_id); - signalled = true; - log_trace("<< signal(n-ops %" PRIu64 ")", nops_completed); - } -} - -void testcase::signal() { - if (!signalled) { - log_trace(">> signal(forced)"); - if (!global::singlemode) - osal_broadcast(config.actor_id); - signalled = true; - log_trace("<< signal(forced)"); - } -} - -bool testcase::setup() { - db_prepare(); - if (!wait4start()) - return false; - - start_timestamp = chrono::now_motonic(); - nops_completed = 0; - return true; -} - -bool testcase::teardown() { - log_trace(">> testcase::teardown"); - signal(); - db_close(); - log_trace("<< testcase::teardown"); - return true; -} - -bool testcase::should_continue(bool check_timeout_only) const { - bool result = true; - - if (config.params.test_duration) { - chrono::time since; - since.fixedpoint = - chrono::now_motonic().fixedpoint - start_timestamp.fixedpoint; - if (since.seconds() >= config.params.test_duration) - result = false; - } - - if (!check_timeout_only && config.params.test_nops && - nops_completed >= config.params.test_nops) - result = false; - - if (result) - kick_progress(false); - - return result; -} - -void testcase::fetch_canary() { - mdbx_canary canary_now; - log_trace(">> fetch_canary"); - - int rc = mdbx_canary_get(txn_guard.get(), &canary_now); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_canary_get()", rc); - - if (canary_now.v < last.canary.v) - failure("fetch_canary: %" PRIu64 "(canary-now.v) < %" PRIu64 - "(canary-last.v)", - canary_now.v, last.canary.v); - if (canary_now.y < last.canary.y) - failure("fetch_canary: %" PRIu64 "(canary-now.y) < %" PRIu64 - "(canary-last.y)", - canary_now.y, last.canary.y); - - last.canary = canary_now; - log_trace("<< fetch_canary: db-sequence %" PRIu64 - ", db-sequence.txnid %" PRIu64, - last.canary.y, last.canary.v); -} - -void testcase::update_canary(uint64_t increment) { - mdbx_canary canary_now = last.canary; - - log_trace(">> update_canary: sequence %" PRIu64 " += %" PRIu64, canary_now.y, - increment); - canary_now.y += increment; - - int rc = mdbx_canary_put(txn_guard.get(), &canary_now); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_canary_put()", rc); - - log_trace("<< update_canary: sequence = %" PRIu64, canary_now.y); -} - -int testcase::db_open__begin__table_create_open_clean(MDBX_dbi &handle) { - db_open(); - - int err, retry_left = 42; - for (;;) { - txn_begin(false); - handle = db_table_open(true); - db_table_clear(handle); - err = breakable_commit(); - if (likely(err == MDBX_SUCCESS)) { - txn_begin(false); - return MDBX_SUCCESS; - } - if (--retry_left == 0) - break; - jitter_delay(true); - } - log_notice("db_begin_table_create_open_clean: bailout due '%s'", - mdbx_strerror(err)); - return err; -} - -MDBX_dbi testcase::db_table_open(bool create) { - log_trace(">> testcase::db_table_create"); - - char tablename_buf[16]; - const char *tablename = nullptr; - if (config.space_id) { - int rc = snprintf(tablename_buf, sizeof(tablename_buf), "TBL%04u", - config.space_id); - if (rc < 4 || rc >= (int)sizeof(tablename_buf) - 1) - failure("snprintf(tablename): %d", rc); - tablename = tablename_buf; - } - log_debug("use %s table", tablename ? tablename : "MAINDB"); - - MDBX_dbi handle = 0; - int rc = mdbx_dbi_open(txn_guard.get(), tablename, - (create ? MDBX_CREATE : 0) | config.params.table_flags, - &handle); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_dbi_open()", rc); - - log_trace("<< testcase::db_table_create, handle %u", handle); - return handle; -} - -void testcase::db_table_drop(MDBX_dbi handle) { - log_trace(">> testcase::db_table_drop, handle %u", handle); - - if (config.params.drop_table) { - int rc = mdbx_drop(txn_guard.get(), handle, true); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_drop(delete=true)", rc); - speculum.clear(); - log_trace("<< testcase::db_table_drop"); - } else { - log_trace("<< testcase::db_table_drop: not needed"); - } -} - -void testcase::db_table_clear(MDBX_dbi handle, MDBX_txn *txn) { - log_trace(">> testcase::db_table_clear, handle %u", handle); - int rc = mdbx_drop(txn ? txn : txn_guard.get(), handle, false); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_drop(delete=false)", rc); - speculum.clear(); - log_trace("<< testcase::db_table_clear"); -} - -void testcase::db_table_close(MDBX_dbi handle) { - log_trace(">> testcase::db_table_close, handle %u", handle); - assert(!txn_guard); - int rc = mdbx_dbi_close(db_guard.get(), handle); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_dbi_close()", rc); - log_trace("<< testcase::db_table_close"); -} - -void testcase::checkdata(const char *step, MDBX_dbi handle, MDBX_val key2check, - MDBX_val expected_valued) { - MDBX_val actual_value = expected_valued; - int rc = mdbx_get_nearest(txn_guard.get(), handle, &key2check, &actual_value); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror(step, rc); - if (!is_samedata(&actual_value, &expected_valued)) - failure("%s data mismatch", step); -} - -//----------------------------------------------------------------------------- - -bool test_execute(const actor_config &config_const) { - const mdbx_pid_t pid = osal_getpid(); - actor_config config = config_const; - - if (global::singlemode) { - logging::setup(format("single_%s", testcase2str(config.testcase))); - } else { - logging::setup((logging::loglevel)config.params.loglevel, - format("child_%u.%u", config.actor_id, config.space_id)); - log_trace(">> wait4barrier"); - osal_wait4barrier(); - log_trace("<< wait4barrier"); - } - - try { - std::unique_ptr<testcase> test; - switch (config.testcase) { - case ac_hill: - test.reset(new testcase_hill(config, pid)); - break; - case ac_deadread: - test.reset(new testcase_deadread(config, pid)); - break; - case ac_deadwrite: - test.reset(new testcase_deadwrite(config, pid)); - break; - case ac_jitter: - test.reset(new testcase_jitter(config, pid)); - break; - case ac_try: - test.reset(new testcase_try(config, pid)); - break; - case ac_copy: - test.reset(new testcase_copy(config, pid)); - break; - case ac_append: - test.reset(new testcase_append(config, pid)); - break; - case ac_ttl: - test.reset(new testcase_ttl(config, pid)); - break; - case ac_nested: - test.reset(new testcase_nested(config, pid)); - break; - default: - test.reset(new testcase(config, pid)); - break; - } - - size_t iter = 0; - do { - iter++; - if (!test->setup()) { - log_notice("test setup failed"); - return false; - } - if (!test->run()) { - log_notice("test failed"); - return false; - } - if (!test->teardown()) { - log_notice("test teardown failed"); - return false; - } - - if (config.params.nrepeat == 1) - log_verbose("test successed"); - else { - if (config.params.nrepeat) - log_verbose("test successed (iteration %zi of %zi)", iter, - size_t(config.params.nrepeat)); - else - log_verbose("test successed (iteration %zi)", iter); - config.params.keygen.seed += INT32_C(0xA4F4D37B); - } - - } while (config.params.nrepeat == 0 || iter < config.params.nrepeat); - return true; - } catch (const std::exception &pipets) { - failure("***** Exception: %s *****", pipets.what()); - return false; - } -} - -//----------------------------------------------------------------------------- - -int testcase::insert(const keygen::buffer &akey, const keygen::buffer &adata, - unsigned flags) { - int err = mdbx_put(txn_guard.get(), dbi, &akey->value, &adata->value, flags); - if (err == MDBX_SUCCESS && config.params.speculum) { - const auto S_key = S(akey); - const auto S_data = S(adata); - const bool inserted = speculum.emplace(S_key, S_data).second; - assert(inserted); - (void)inserted; - } - return err; -} - -int testcase::replace(const keygen::buffer &akey, - const keygen::buffer &new_data, - const keygen::buffer &old_data, unsigned flags) { - if (config.params.speculum) { - const auto S_key = S(akey); - const auto S_old = S(old_data); - const auto S_new = S(new_data); - const auto removed = speculum.erase(SET::key_type(S_key, S_old)); - assert(removed == 1); - (void)removed; - const bool inserted = speculum.emplace(S_key, S_new).second; - assert(inserted); - (void)inserted; - } - return mdbx_replace(txn_guard.get(), dbi, &akey->value, &new_data->value, - &old_data->value, flags); -} - -int testcase::remove(const keygen::buffer &akey, const keygen::buffer &adata) { - if (config.params.speculum) { - const auto S_key = S(akey); - const auto S_data = S(adata); - const auto removed = speculum.erase(SET::key_type(S_key, S_data)); - assert(removed == 1); - (void)removed; - } - return mdbx_del(txn_guard.get(), dbi, &akey->value, &adata->value); -} - -bool testcase::speculum_verify() { - if (!config.params.speculum) - return true; - - if (!txn_guard) - txn_begin(true); - - char dump_key[128], dump_value[128]; - char dump_mkey[128], dump_mvalue[128]; - - MDBX_cursor *cursor; - int err = mdbx_cursor_open(txn_guard.get(), dbi, &cursor); - if (err != MDBX_SUCCESS) - failure_perror("mdbx_cursor_open()", err); - - bool rc = true; - MDBX_val akey, avalue; - MDBX_val mkey, mvalue; - err = mdbx_cursor_get(cursor, &akey, &avalue, MDBX_FIRST); - - unsigned extra = 0, lost = 0, n = 0; - assert(std::is_sorted(speculum.cbegin(), speculum.cend(), ItemCompare(this))); - auto it = speculum.cbegin(); - while (true) { - if (err != MDBX_SUCCESS) { - akey.iov_len = avalue.iov_len = 0; - akey.iov_base = avalue.iov_base = nullptr; - } - const auto S_key = S(akey); - const auto S_data = S(avalue); - if (it != speculum.cend()) { - mkey.iov_base = (void *)it->first.c_str(); - mkey.iov_len = it->first.size(); - mvalue.iov_base = (void *)it->second.c_str(); - mvalue.iov_len = it->second.size(); - } - if (err == MDBX_SUCCESS && it != speculum.cend() && S_key == it->first && - S_data == it->second) { - ++it; - err = mdbx_cursor_get(cursor, &akey, &avalue, MDBX_NEXT); - } else if (err == MDBX_SUCCESS && - (it == speculum.cend() || S_key < it->first || - (S_key == it->first && S_data < it->second))) { - extra += 1; - if (it != speculum.cend()) { - log_error("extra pair %u/%u: db{%s, %s} < mi{%s, %s}", n, extra, - mdbx_dump_val(&akey, dump_key, sizeof(dump_key)), - mdbx_dump_val(&avalue, dump_value, sizeof(dump_value)), - mdbx_dump_val(&mkey, dump_mkey, sizeof(dump_mkey)), - mdbx_dump_val(&mvalue, dump_mvalue, sizeof(dump_mvalue))); - } else { - log_error("extra pair %u/%u: db{%s, %s} < mi.END", n, extra, - mdbx_dump_val(&akey, dump_key, sizeof(dump_key)), - mdbx_dump_val(&avalue, dump_value, sizeof(dump_value))); - } - err = mdbx_cursor_get(cursor, &akey, &avalue, MDBX_NEXT); - rc = false; - } else if (it != speculum.cend() && - (err == MDBX_NOTFOUND || S_key > it->first || - (S_key == it->first && S_data > it->second))) { - lost += 1; - if (err == MDBX_NOTFOUND) { - log_error("lost pair %u/%u: db.END > mi{%s, %s}", n, lost, - mdbx_dump_val(&mkey, dump_mkey, sizeof(dump_mkey)), - mdbx_dump_val(&mvalue, dump_mvalue, sizeof(dump_mvalue))); - } else { - log_error("lost pair %u/%u: db{%s, %s} > mi{%s, %s}", n, lost, - mdbx_dump_val(&akey, dump_key, sizeof(dump_key)), - mdbx_dump_val(&avalue, dump_value, sizeof(dump_value)), - mdbx_dump_val(&mkey, dump_mkey, sizeof(dump_mkey)), - mdbx_dump_val(&mvalue, dump_mvalue, sizeof(dump_mvalue))); - } - ++it; - rc = false; - } else if (err == MDBX_NOTFOUND && it == speculum.cend()) { - break; - } else if (err != MDBX_SUCCESS) { - failure_perror("mdbx_cursor_get()", err); - } else { - assert(!"WTF?"); - } - n += 1; - } - - mdbx_cursor_close(cursor); - return rc; -} diff --git a/libs/libmdbx/src/test/test.h b/libs/libmdbx/src/test/test.h deleted file mode 100644 index 43c6c03848..0000000000 --- a/libs/libmdbx/src/test/test.h +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright 2017-2020 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 "chrono.h" -#include "config.h" -#include "keygen.h" -#include "log.h" -#include "osal.h" -#include "utils.h" - -#include <deque> -#include <set> -#include <stack> -#include <tuple> - -#ifndef HAVE_cxx17_std_string_view -#if __cplusplus >= 201703L && __has_include(<string_view>) -#include <string_view> -#define HAVE_cxx17_std_string_view 1 -#else -#define HAVE_cxx17_std_string_view 0 -#endif -#endif /* HAVE_cxx17_std_string_view */ - -#if HAVE_cxx17_std_string_view -#include <string_view> -#endif - -bool test_execute(const actor_config &config); -std::string thunk_param(const actor_config &config); -void testcase_setup(const char *casename, actor_params ¶ms, - unsigned &last_space_id); -void configure_actor(unsigned &last_space_id, const actor_testcase testcase, - const char *space_id_cstr, const actor_params ¶ms); -void keycase_setup(const char *casename, actor_params ¶ms); - -namespace global { - -extern const char thunk_param_prefix[]; -extern std::vector<actor_config> actors; -extern std::unordered_map<unsigned, actor_config *> events; -extern std::unordered_map<mdbx_pid_t, actor_config *> pid2actor; -extern std::set<std::string> databases; -extern unsigned nactors; -extern chrono::time start_motonic; -extern chrono::time deadline_motonic; -extern bool singlemode; - -namespace config { -extern unsigned timeout_duration_seconds; -extern bool dump_config; -extern bool cleanup_before; -extern bool cleanup_after; -extern bool failfast; -extern bool progress_indicator; -extern bool console_mode; -} /* namespace config */ - -} /* namespace global */ - -//----------------------------------------------------------------------------- - -struct db_deleter /* : public std::unary_function<void, MDBX_env *> */ { - void operator()(MDBX_env *env) const { mdbx_env_close(env); } -}; - -struct txn_deleter /* : public std::unary_function<void, MDBX_txn *> */ { - void operator()(MDBX_txn *txn) const { - int rc = mdbx_txn_abort(txn); - if (rc) - log_trouble(__func__, "mdbx_txn_abort()", rc); - } -}; - -struct cursor_deleter /* : public std::unary_function<void, MDBX_cursor *> */ { - void operator()(MDBX_cursor *cursor) const { mdbx_cursor_close(cursor); } -}; - -typedef std::unique_ptr<MDBX_env, db_deleter> scoped_db_guard; -typedef std::unique_ptr<MDBX_txn, txn_deleter> scoped_txn_guard; -typedef std::unique_ptr<MDBX_cursor, cursor_deleter> scoped_cursor_guard; - -//----------------------------------------------------------------------------- - -class testcase { -protected: -#if HAVE_cxx17_std_string_view - using data_view = std::string_view; -#else - using data_view = std::string; -#endif - static inline data_view S(const MDBX_val &v) { - return (v.iov_base && v.iov_len) - ? data_view(static_cast<const char *>(v.iov_base), v.iov_len) - : data_view(); - } - static inline data_view S(const keygen::buffer &b) { return S(b->value); } - - using Item = std::pair<std::string, std::string>; - struct ItemCompare { - const testcase *context; - ItemCompare(const testcase *owner) : context(owner) {} - - bool operator()(const Item &a, const Item &b) const { - MDBX_val va, vb; - va.iov_base = (void *)a.first.data(); - va.iov_len = a.first.size(); - vb.iov_base = (void *)b.first.data(); - vb.iov_len = b.first.size(); - int cmp = mdbx_cmp(context->txn_guard.get(), context->dbi, &va, &vb); - if (cmp == 0 && - (context->config.params.table_flags & MDBX_DUPSORT) != 0) { - va.iov_base = (void *)a.second.data(); - va.iov_len = a.second.size(); - vb.iov_base = (void *)b.second.data(); - vb.iov_len = b.second.size(); - cmp = mdbx_dcmp(context->txn_guard.get(), context->dbi, &va, &vb); - } - return cmp < 0; - } - }; - - // for simplify the set<pair<key,value>> - // is used instead of multimap<key,value> - using SET = std::set<Item, ItemCompare>; - - const actor_config &config; - const mdbx_pid_t pid; - - MDBX_dbi dbi{0}; - scoped_db_guard db_guard; - scoped_txn_guard txn_guard; - scoped_cursor_guard cursor_guard; - bool signalled{false}; - bool need_speculum_assign{false}; - - uint64_t nops_completed{0}; - chrono::time start_timestamp; - keygen::buffer key; - keygen::buffer data; - keygen::maker keyvalue_maker; - - struct { - mdbx_canary canary; - } last; - - SET speculum{ItemCompare(this)}, speculum_commited{ItemCompare(this)}; - bool speculum_verify(); - int insert(const keygen::buffer &akey, const keygen::buffer &adata, - unsigned flags); - int replace(const keygen::buffer &akey, const keygen::buffer &new_value, - const keygen::buffer &old_value, unsigned flags); - int remove(const keygen::buffer &akey, const keygen::buffer &adata); - - static int oom_callback(MDBX_env *env, mdbx_pid_t pid, mdbx_tid_t tid, - uint64_t txn, unsigned gap, size_t space, int retry); - - unsigned actual_db_mode{0}; - bool is_nested_txn_available() const { - return (actual_db_mode & MDBX_WRITEMAP) == 0; - } - void kick_progress(bool active) const; - void db_prepare(); - void db_open(); - void db_close(); - void txn_begin(bool readonly, unsigned flags = 0); - int breakable_commit(); - void txn_end(bool abort); - int breakable_restart(); - void txn_restart(bool abort, bool readonly, unsigned flags = 0); - void cursor_open(MDBX_dbi handle); - void cursor_close(); - void txn_inject_writefault(void); - void txn_inject_writefault(MDBX_txn *txn); - void fetch_canary(); - void update_canary(uint64_t increment); - void checkdata(const char *step, MDBX_dbi handle, MDBX_val key2check, - MDBX_val expected_valued); - unsigned txn_underutilization_x256(MDBX_txn *txn) const; - - MDBX_dbi db_table_open(bool create); - void db_table_drop(MDBX_dbi handle); - void db_table_clear(MDBX_dbi handle, MDBX_txn *txn = nullptr); - void db_table_close(MDBX_dbi handle); - int db_open__begin__table_create_open_clean(MDBX_dbi &handle); - - bool wait4start(); - void report(size_t nops_done); - void signal(); - bool should_continue(bool check_timeout_only = false) const; - - void generate_pair(const keygen::serial_t serial, keygen::buffer &out_key, - keygen::buffer &out_value, keygen::serial_t data_age) { - keyvalue_maker.pair(serial, out_key, out_value, data_age, false); - } - - void generate_pair(const keygen::serial_t serial) { - keyvalue_maker.pair(serial, key, data, 0, true); - } - - bool mode_readonly() const { - return (config.params.mode_flags & MDBX_RDONLY) ? true : false; - } - -public: - testcase(const actor_config &config, const mdbx_pid_t pid) - : config(config), pid(pid) { - start_timestamp.reset(); - memset(&last, 0, sizeof(last)); - } - - virtual bool setup(); - virtual bool run() { return true; } - virtual bool teardown(); - virtual ~testcase() {} -}; - -class testcase_hill : public testcase { -public: - testcase_hill(const actor_config &config, const mdbx_pid_t pid) - : testcase(config, pid) {} - bool run() override; -}; - -class testcase_append : public testcase { -public: - testcase_append(const actor_config &config, const mdbx_pid_t pid) - : testcase(config, pid) {} - bool run() override; -}; - -class testcase_deadread : public testcase { -public: - testcase_deadread(const actor_config &config, const mdbx_pid_t pid) - : testcase(config, pid) {} - bool run() override; -}; - -class testcase_deadwrite : public testcase { -public: - testcase_deadwrite(const actor_config &config, const mdbx_pid_t pid) - : testcase(config, pid) {} - bool run() override; -}; - -class testcase_jitter : public testcase { -public: - testcase_jitter(const actor_config &config, const mdbx_pid_t pid) - : testcase(config, pid) {} - bool run() override; -}; - -class testcase_try : public testcase { -public: - testcase_try(const actor_config &config, const mdbx_pid_t pid) - : testcase(config, pid) {} - bool run() override; -}; - -class testcase_copy : public testcase { - const std::string copy_pathname; - void copy_db(const bool with_compaction); - -public: - testcase_copy(const actor_config &config, const mdbx_pid_t pid) - : testcase(config, pid), - copy_pathname(config.params.pathname_db + "-copy") {} - bool run() override; -}; - -class testcase_ttl : public testcase { - using inherited = testcase; - -protected: - struct { - unsigned max_window_size{0}; - unsigned max_step_size{0}; - } sliding; - unsigned edge2window(uint64_t edge); - unsigned edge2count(uint64_t edge); - -public: - testcase_ttl(const actor_config &config, const mdbx_pid_t pid) - : inherited(config, pid) {} - bool setup() override; - bool run() override; -}; - -class testcase_nested : public testcase_ttl { - using inherited = testcase_ttl; - using FIFO = std::deque<std::pair<uint64_t, unsigned>>; - - uint64_t serial{0}; - unsigned clear_wholetable_passed{0}; - unsigned clear_stepbystep_passed{0}; - unsigned dbfull_passed{0}; - bool keyspace_overflow{false}; - FIFO fifo; - std::stack<std::tuple<scoped_txn_guard, uint64_t, FIFO, SET>> stack; - - bool trim_tail(unsigned window_width); - bool grow_head(unsigned head_count); - bool pop_txn(bool abort); - bool pop_txn() { - return pop_txn(inherited::is_nested_txn_available() ? flipcoin_x3() - : flipcoin_x2()); - } - void push_txn(); - bool stochastic_breakable_restart_with_nested(bool force_restart = false); - -public: - testcase_nested(const actor_config &config, const mdbx_pid_t pid) - : inherited(config, pid) {} - bool setup() override; - bool run() override; - bool teardown() override; -}; diff --git a/libs/libmdbx/src/test/try.cc b/libs/libmdbx/src/test/try.cc deleted file mode 100644 index adb0113096..0000000000 --- a/libs/libmdbx/src/test/try.cc +++ /dev/null @@ -1,20 +0,0 @@ -#include "test.h" - -bool testcase_try::run() { - db_open(); - assert(!txn_guard); - - MDBX_txn *txn = nullptr; - MDBX_txn *txn2 = nullptr; - int rc = mdbx_txn_begin(db_guard.get(), nullptr, 0, &txn); - if (unlikely(rc != MDBX_SUCCESS)) - failure_perror("mdbx_txn_begin(MDBX_TRYTXN)", rc); - else { - rc = mdbx_txn_begin(db_guard.get(), nullptr, MDBX_TRYTXN, &txn2); - if (unlikely(rc != MDBX_BUSY)) - failure_perror("mdbx_txn_begin(MDBX_TRYTXN)", rc); - } - - txn_guard.reset(txn); - return true; -} diff --git a/libs/libmdbx/src/test/ttl.cc b/libs/libmdbx/src/test/ttl.cc deleted file mode 100644 index e3927d9cd4..0000000000 --- a/libs/libmdbx/src/test/ttl.cc +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright 2017-2020 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" -#include <cmath> -#include <deque> - -/* LY: тест "эмуляцией time-to-live": - * - организуется "скользящее окно", которое двигается вперед вдоль - * числовой оси каждую транзакцию. - * - по переднему краю "скользящего окна" записи добавляются в таблицу, - * а по заднему удаляются. - * - количество добавляемых/удаляемых записей псевдослучайно зависит - * от номера транзакции, но с экспоненциальным распределением. - * - размер "скользящего окна" также псевдослучайно зависит от номера - * транзакции с "отрицательным" экспоненциальным распределением - * MAX_WIDTH - exp(rnd(N)), при уменьшении окна сдвигается задний - * край и удаляются записи позади него. - * - * Таким образом имитируется поведение таблицы с TTL: записи стохастически - * добавляются и удаляются, но изредка происходит массивное удаление. - */ - -unsigned testcase_ttl::edge2count(uint64_t edge) { - const double rnd = u64_to_double1(prng64_map1_white(edge)); - const unsigned count = std::lrint(std::pow(sliding.max_step_size, rnd)); - // average value: (X - 1) / ln(X), where X = sliding.max_step_size - return count; -} - -unsigned testcase_ttl::edge2window(uint64_t edge) { - const double rnd = u64_to_double1(bleach64(edge)); - const unsigned size = sliding.max_window_size - - std::lrint(std::pow(sliding.max_window_size, rnd)); - // average value: Y - (Y - 1) / ln(Y), where Y = sliding.max_window_size - return size; -} - -static inline double estimate(const double x, const double y) { - /* среднее кол-во операций N = X' * Y', где X' и Y' средние значения - * размера окна и кол-ва добавляемых за один шаг записей: - * X' = (X - 1) / ln(X), где X = sliding.max_step_size - * Y' = Y - (Y - 1) / ln(Y), где Y = sliding.max_window_size */ - return (x - 1) / std::log(x) * (y - (y - 1) / std::log(y)); -} - -bool testcase_ttl::setup() { - const unsigned window_top_lower = - 7 /* нижний предел для верхней границы диапазона, в котором будет - стохастически колебаться размер окна */ - ; - const unsigned count_top_lower = - 7 /* нижний предел для верхней границы диапазона, в котором будет - стохастически колебаться кол-во записей добавляемых на одном шаге */ - ; - - /* для параметризации используем подходящие параметры, - * которые не имеют здесь смысла в первоначальном значении. */ - const double ratio = - double(config.params.batch_read ? config.params.batch_read : 1) / - double(config.params.batch_write ? config.params.batch_write : 1); - - /* проще найти двоичным поиском (вариация метода Ньютона) */ - double hi = config.params.test_nops, lo = 1; - double x = std::sqrt(hi + lo) / ratio; - while (hi > lo) { - const double n = estimate(x, x * ratio); - if (n > config.params.test_nops) - hi = x - 1; - else - lo = x + 1; - x = (hi + lo) / 2; - } - - sliding.max_step_size = std::lrint(x); - if (sliding.max_step_size < count_top_lower) - sliding.max_step_size = count_top_lower; - sliding.max_window_size = std::lrint(x * ratio); - if (sliding.max_window_size < window_top_lower) - sliding.max_window_size = window_top_lower; - - while (estimate(sliding.max_step_size, sliding.max_window_size) > - config.params.test_nops * 2.0) { - if (ratio * sliding.max_step_size > sliding.max_window_size) { - if (sliding.max_step_size < count_top_lower) - break; - sliding.max_step_size = sliding.max_step_size * 7 / 8; - } else { - if (sliding.max_window_size < window_top_lower) - break; - sliding.max_window_size = sliding.max_window_size * 7 / 8; - } - } - - log_verbose("come up window_max %u from `batch_read`", - sliding.max_window_size); - log_verbose("come up step_max %u from `batch_write`", sliding.max_step_size); - return inherited::setup(); -} - -bool testcase_ttl::run() { - int err = db_open__begin__table_create_open_clean(dbi); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("ttl: bailout-prepare due '%s'", mdbx_strerror(err)); - return false; - } - - uint64_t seed = - prng64_map2_white(config.params.keygen.seed) + config.actor_id; - keyvalue_maker.setup(config.params, config.actor_id, 0 /* thread_number */); - key = keygen::alloc(config.params.keylen_max); - data = keygen::alloc(config.params.datalen_max); - const unsigned insert_flags = (config.params.table_flags & MDBX_DUPSORT) - ? MDBX_NODUPDATA - : MDBX_NODUPDATA | MDBX_NOOVERWRITE; - - std::deque<std::pair<uint64_t, unsigned>> fifo; - uint64_t serial = 0; - bool rc = false; - unsigned clear_wholetable_passed = 0; - unsigned clear_stepbystep_passed = 0; - unsigned dbfull_passed = 0; - unsigned loops = 0; - bool keyspace_overflow = false; - while (true) { - const uint64_t salt = prng64_white(seed) /* mdbx_txn_id(txn_guard.get()) */; - - const unsigned window_width = - (!should_continue() || flipcoin_x4()) ? 0 : edge2window(salt); - unsigned head_count = edge2count(salt); - log_debug("ttl: step #%" PRIu64 " (serial %" PRIu64 - ", window %u, count %u) salt %" PRIu64, - nops_completed, serial, window_width, head_count, salt); - - if (window_width || flipcoin()) { - clear_stepbystep_passed += window_width == 0; - while (fifo.size() > window_width) { - uint64_t tail_serial = fifo.back().first; - const unsigned tail_count = fifo.back().second; - log_trace("ttl: pop-tail (serial %" PRIu64 ", count %u)", tail_serial, - tail_count); - fifo.pop_back(); - for (unsigned n = 0; n < tail_count; ++n) { - log_trace("ttl: remove-tail %" PRIu64, tail_serial); - generate_pair(tail_serial); - err = remove(key, data); - if (unlikely(err != MDBX_SUCCESS)) { - if (err == MDBX_MAP_FULL && config.params.ignore_dbfull) { - log_notice("ttl: tail-bailout due '%s'", mdbx_strerror(err)); - goto bailout; - } - failure_perror("mdbx_del(tail)", err); - } - if (unlikely(!keyvalue_maker.increment(tail_serial, 1))) - failure("ttl: unexpected key-space overflow on the tail"); - } - report(tail_count); - } - } else { - log_trace("ttl: purge state"); - db_table_clear(dbi); - fifo.clear(); - clear_wholetable_passed += 1; - report(1); - } - - err = breakable_restart(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("ttl: bailout at commit due '%s'", mdbx_strerror(err)); - break; - } - if (!speculum_verify()) { - log_notice("ttl: bailout after tail-trim"); - return false; - } - - if (!keyspace_overflow && (should_continue() || !clear_wholetable_passed || - !clear_stepbystep_passed)) { - unsigned underutilization_x256 = - txn_underutilization_x256(txn_guard.get()); - if (dbfull_passed > underutilization_x256) { - log_notice("ttl: skip head-grow to avoid one more dbfull (was %u, " - "underutilization %.2f%%)", - dbfull_passed, underutilization_x256 / 2.560); - continue; - } - fifo.push_front(std::make_pair(serial, head_count)); - retry: - for (unsigned n = 0; n < head_count; ++n) { - log_trace("ttl: insert-head %" PRIu64, serial); - generate_pair(serial); - err = insert(key, data, insert_flags); - if (unlikely(err != MDBX_SUCCESS)) { - if ((err == MDBX_TXN_FULL || err == MDBX_MAP_FULL) && - config.params.ignore_dbfull) { - log_notice("ttl: head-insert skip due '%s'", mdbx_strerror(err)); - txn_restart(true, false); - serial = fifo.front().first; - fifo.front().second = head_count = n; - dbfull_passed += 1; - goto retry; - } - failure_perror("mdbx_put(head)", err); - } - - if (unlikely(!keyvalue_maker.increment(serial, 1))) { - log_notice("ttl: unexpected key-space overflow"); - keyspace_overflow = true; - txn_restart(true, false); - serial = fifo.front().first; - fifo.front().second = head_count = n; - goto retry; - } - } - err = breakable_restart(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("ttl: head-commit skip due '%s'", mdbx_strerror(err)); - serial = fifo.front().first; - fifo.pop_front(); - } - if (!speculum_verify()) { - log_notice("ttl: bailout after head-grow"); - return false; - } - loops += 1; - } else if (fifo.empty()) { - log_notice("ttl: done %u whole loops, %" PRIu64 " ops, %" PRIu64 " items", - loops, nops_completed, serial); - rc = true; - break; - } else { - log_notice("ttl: done, wait for empty, skip head-grow"); - } - } - -bailout: - txn_end(true); - if (dbi) { - if (config.params.drop_table && !mode_readonly()) { - txn_begin(false); - db_table_drop(dbi); - err = breakable_commit(); - if (unlikely(err != MDBX_SUCCESS)) { - log_notice("ttl: bailout-clean due '%s'", mdbx_strerror(err)); - return false; - } - } else - db_table_close(dbi); - } - return rc; -} diff --git a/libs/libmdbx/src/test/utils.cc b/libs/libmdbx/src/test/utils.cc deleted file mode 100644 index 051671ff87..0000000000 --- a/libs/libmdbx/src/test/utils.cc +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright 2017-2020 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" -#include <float.h> -#if defined(HAVE_IEEE754_H) || __has_include(<ieee754.h>) -#include <ieee754.h> -#endif -#if defined(__APPLE__) || defined(__MACH__) -#include <mach/mach_time.h> -#endif /* defined(__APPLE__) || defined(__MACH__) */ - -std::string format(const char *fmt, ...) { - va_list ap, ones; - va_start(ap, fmt); - va_copy(ones, ap); -#ifdef _MSC_VER - int needed = _vscprintf(fmt, ap); -#else - int needed = vsnprintf(nullptr, 0, fmt, ap); -#endif - assert(needed >= 0); - va_end(ap); - std::string result; - result.reserve((size_t)needed + 1); - result.resize((size_t)needed, '\0'); - int actual = vsnprintf((char *)result.data(), result.capacity(), fmt, ones); - assert(actual == needed); - (void)actual; - va_end(ones); - return result; -} - -std::string data2hex(const void *ptr, size_t bytes, simple_checksum &checksum) { - std::string result; - if (bytes > 0) { - const uint8_t *data = (const uint8_t *)ptr; - checksum.push(data, bytes); - result.reserve(bytes * 2); - const uint8_t *const end = data + bytes; - do { - char h = *data >> 4; - char l = *data & 15; - result.push_back((l < 10) ? l + '0' : l - 10 + 'a'); - result.push_back((h < 10) ? h + '0' : h - 10 + 'a'); - } while (++data < end); - } - assert(result.size() == bytes * 2); - return result; -} - -bool hex2data(const char *hex_begin, const char *hex_end, void *ptr, - size_t bytes, simple_checksum &checksum) { - if (bytes * 2 != (size_t)(hex_end - hex_begin)) - return false; - - uint8_t *data = (uint8_t *)ptr; - for (const char *hex = hex_begin; hex != hex_end; hex += 2, ++data) { - unsigned l = hex[0], h = hex[1]; - - if (l >= '0' && l <= '9') - l = l - '0'; - else if (l >= 'A' && l <= 'F') - l = l - 'A' + 10; - else if (l >= 'a' && l <= 'f') - l = l - 'a' + 10; - else - return false; - - if (h >= '0' && h <= '9') - h = h - '0'; - else if (h >= 'A' && h <= 'F') - h = h - 'A' + 10; - else if (h >= 'a' && h <= 'f') - h = h - 'a' + 10; - else - return false; - - uint32_t c = l + (h << 4); - checksum.push(c); - *data = (uint8_t)c; - } - return true; -} - -bool is_samedata(const MDBX_val *a, const MDBX_val *b) { - return a->iov_len == b->iov_len && - memcmp(a->iov_base, b->iov_base, a->iov_len) == 0; -} - -//----------------------------------------------------------------------------- - -/* TODO: replace my 'libmera' from t1ha. */ -uint64_t entropy_ticks(void) { -#if defined(EMSCRIPTEN) - return (uint64_t)emscripten_get_now(); -#endif /* EMSCRIPTEN */ - -#if defined(__APPLE__) || defined(__MACH__) - return mach_absolute_time(); -#endif /* defined(__APPLE__) || defined(__MACH__) */ - -#if defined(__sun__) || defined(__sun) - return gethrtime(); -#endif /* __sun__ */ - -#if defined(__GNUC__) || defined(__clang__) - -#if defined(__ia64__) - uint64_t ticks; - __asm __volatile("mov %0=ar.itc" : "=r"(ticks)); - return ticks; -#elif defined(__hppa__) - uint64_t ticks; - __asm __volatile("mfctl 16, %0" : "=r"(ticks)); - return ticks; -#elif defined(__s390__) - uint64_t ticks; - __asm __volatile("stck 0(%0)" : : "a"(&(ticks)) : "memory", "cc"); - return ticks; -#elif defined(__alpha__) - uint64_t ticks; - __asm __volatile("rpcc %0" : "=r"(ticks)); - return ticks; -#elif defined(__sparc__) || defined(__sparc) || defined(__sparc64__) || \ - defined(__sparc64) || defined(__sparc_v8plus__) || \ - defined(__sparc_v8plus) || defined(__sparc_v8plusa__) || \ - defined(__sparc_v8plusa) || defined(__sparc_v9__) || defined(__sparc_v9) - - union { - uint64_t u64; - struct { -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - uint32_t h, l; -#else - uint32_t l, h; -#endif - } u32; - } cycles; - -#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || \ - defined(__sparc_v9__) || defined(__sparc_v8plus) || \ - defined(__sparc_v8plusa) || defined(__sparc_v9) - -#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul || \ - defined(__sparc64__) || defined(__sparc64) - __asm __volatile("rd %%tick, %0" : "=r"(cycles.u64)); -#else - __asm __volatile("rd %%tick, %1; srlx %1, 32, %0" - : "=r"(cycles.u32.h), "=r"(cycles.u32.l)); -#endif /* __sparc64__ */ - -#else - __asm __volatile(".byte 0x83, 0x41, 0x00, 0x00; mov %%g1, %0" - : "=r"(cycles.u64) - : - : "%g1"); -#endif /* __sparc8plus__ || __sparc_v9__ */ - return cycles.u64; - -#elif (defined(__powerpc64__) || defined(__ppc64__) || defined(__ppc64) || \ - defined(__powerpc64)) - uint64_t ticks; - __asm __volatile("mfspr %0, 268" : "=r"(ticks)); - return ticks; -#elif (defined(__powerpc__) || defined(__ppc__) || defined(__powerpc) || \ - defined(__ppc)) -#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul - uint64_t ticks; - __asm __volatile("mftb %0" : "=r"(ticks)); - *now = ticks; -#else - uint64_t ticks; - uint32_t low, high_before, high_after; - __asm __volatile("mftbu %0; mftb %1; mftbu %2" - : "=r"(high_before), "=r"(low), "=r"(high_after)); - ticks = (uint64_t)high_after << 32; - ticks |= low & /* zeroes if high part has changed */ - ~(high_before - high_after); -#endif -#elif (defined(__aarch64__) || (defined(__ARM_ARCH) && __ARM_ARCH > 7)) && \ - !defined(MDBX_SAFE4QEMU) - uint64_t virtual_timer; - __asm __volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer)); - return virtual_timer; -#elif (defined(__ARM_ARCH) && __ARM_ARCH > 5 && __ARM_ARCH < 8) || \ - defined(_M_ARM) - static uint32_t pmcntenset = 0x00425B00; - if (unlikely(pmcntenset == 0x00425B00)) { - uint32_t pmuseren; -#ifdef _M_ARM - pmuseren = _MoveFromCoprocessor(15, 0, 9, 14, 0); -#else - __asm("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); -#endif - if (1 & pmuseren /* Is it allowed for user mode code? */) { -#ifdef _M_ARM - pmcntenset = _MoveFromCoprocessor(15, 0, 9, 12, 1); -#else - __asm("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); -#endif - } else - pmcntenset = 0; - } - if (pmcntenset & 0x80000000ul /* Is it counting? */) { -#ifdef _M_ARM - return __rdpmccntr64(); -#else - uint32_t pmccntr; - __asm __volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); - return pmccntr; -#endif - } -#elif defined(__mips__) || defined(__mips) || defined(_R4000) - unsigned count; - __asm __volatile("rdhwr %0, $2" : "=r"(count)); - return count; -#endif /* arch selector */ -#endif /* __GNUC__ || __clang__ */ - -#if defined(__e2k__) || defined(__ia32__) - return __rdtsc(); -#elif defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) - LARGE_INTEGER PerformanceCount; - if (QueryPerformanceCounter(&PerformanceCount)) - return PerformanceCount.QuadPart; - return GetTickCount64(); -#else - struct timespec ts; -#if defined(CLOCK_MONOTONIC_COARSE) - clockid_t clk_id = CLOCK_MONOTONIC_COARSE; -#elif defined(CLOCK_MONOTONIC_RAW) - clockid_t clk_id = CLOCK_MONOTONIC_RAW; -#else - clockid_t clk_id = CLOCK_MONOTONIC; -#endif - int rc = clock_gettime(clk_id, &ts); - if (unlikely(rc)) - failure_perror("clock_gettime()", rc); - - return (((uint64_t)ts.tv_sec) << 32) + ts.tv_nsec; -#endif -} - -//----------------------------------------------------------------------------- - -uint64_t prng64_white(uint64_t &state) { - state = prng64_map2_careless(state); - return bleach64(state); -} - -uint32_t prng32(uint64_t &state) { - return (uint32_t)(prng64_careless(state) >> 32); -} - -void prng_fill(uint64_t &state, void *ptr, size_t bytes) { - uint32_t u32 = prng32(state); - - while (bytes >= 4) { - memcpy(ptr, &u32, 4); - ptr = (uint32_t *)ptr + 1; - bytes -= 4; - u32 = prng32(state); - } - - switch (bytes & 3) { - case 3: - memcpy(ptr, &u32, 3); - break; - case 2: - memcpy(ptr, &u32, 2); - break; - case 1: - memcpy(ptr, &u32, 1); - break; - case 0: - break; - } -} - -static __thread uint64_t prng_state; - -void prng_seed(uint64_t seed) { prng_state = bleach64(seed); } - -uint32_t prng32(void) { return prng32(prng_state); } - -uint64_t prng64(void) { return prng64_white(prng_state); } - -void prng_fill(void *ptr, size_t bytes) { prng_fill(prng_state, ptr, bytes); } - -uint64_t entropy_white() { return bleach64(entropy_ticks()); } - -double double_from_lower(uint64_t salt) { -#ifdef IEEE754_DOUBLE_BIAS - ieee754_double r; - r.ieee.negative = 0; - r.ieee.exponent = IEEE754_DOUBLE_BIAS; - r.ieee.mantissa0 = (unsigned)(salt >> 32); - r.ieee.mantissa1 = (unsigned)salt; - return r.d; -#else - const uint64_t top = (UINT64_C(1) << DBL_MANT_DIG) - 1; - const double scale = 1.0 / (double)top; - return (salt & top) * scale; -#endif -} - -double double_from_upper(uint64_t salt) { -#ifdef IEEE754_DOUBLE_BIAS - ieee754_double r; - r.ieee.negative = 0; - r.ieee.exponent = IEEE754_DOUBLE_BIAS; - salt >>= 64 - DBL_MANT_DIG; - r.ieee.mantissa0 = (unsigned)(salt >> 32); - r.ieee.mantissa1 = (unsigned)salt; - return r.d; -#else - const uint64_t top = (UINT64_C(1) << DBL_MANT_DIG) - 1; - const double scale = 1.0 / (double)top; - return (salt >> (64 - DBL_MANT_DIG)) * scale; -#endif -} - -bool flipcoin() { return bleach32((uint32_t)entropy_ticks()) & 1; } -bool flipcoin_x2() { return (bleach32((uint32_t)entropy_ticks()) & 3) == 0; } -bool flipcoin_x3() { return (bleach32((uint32_t)entropy_ticks()) & 7) == 0; } -bool flipcoin_x4() { return (bleach32((uint32_t)entropy_ticks()) & 15) == 0; } - -bool jitter(unsigned probability_percent) { - const uint32_t top = UINT32_MAX - UINT32_MAX % 100; - uint32_t dice, edge = (top) / 100 * probability_percent; - do - dice = bleach32((uint32_t)entropy_ticks()); - while (dice >= top); - return dice < edge; -} - -void jitter_delay(bool extra) { - unsigned dice = entropy_white() & 3; - if (dice == 0) { - log_trace("== jitter.no-delay"); - } else { - log_trace(">> jitter.delay: dice %u", dice); - do { - cpu_relax(); - memory_barrier(); - cpu_relax(); - if (dice > 1) { - osal_yield(); - cpu_relax(); - if (dice > 2) { - unsigned us = entropy_white() & - (extra ? 0xffff /* 656 ms */ : 0x3ff /* 1 ms */); - log_trace("== jitter.delay: %0.6f", us / 1000000.0); - osal_udelay(us); - } - } - } while (flipcoin()); - log_trace("<< jitter.delay: dice %u", dice); - } -} diff --git a/libs/libmdbx/src/test/utils.h b/libs/libmdbx/src/test/utils.h deleted file mode 100644 index 9e6d4627aa..0000000000 --- a/libs/libmdbx/src/test/utils.h +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright 2017-2020 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" - -#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || \ - !defined(__ORDER_BIG_ENDIAN__) -#error __BYTE_ORDER__ should be defined. -#endif - -#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ && \ - __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ -#error Unsupported byte order. -#endif - -#if __GNUC_PREREQ(4, 4) || defined(__clang__) -#ifndef bswap64 -#define bswap64(v) __builtin_bswap64(v) -#endif -#ifndef bswap32 -#define bswap32(v) __builtin_bswap32(v) -#endif -#if (__GNUC_PREREQ(4, 8) || __has_builtin(__builtin_bswap16)) && \ - !defined(bswap16) -#define bswap16(v) __builtin_bswap16(v) -#endif - -#elif defined(_MSC_VER) - -#if _MSC_FULL_VER < 190024215 -#pragma message( \ - "It is recommended to use Visual Studio 2015 (MSC 19.0) or newer.") -#endif - -#define bswap64(v) _byteswap_uint64(v) -#define bswap32(v) _byteswap_ulong(v) -#define bswap16(v) _byteswap_ushort(v) -#define rot64(v, s) _rotr64(v, s) -#define rot32(v, s) _rotr(v, s) - -#if defined(_M_ARM64) || defined(_M_X64) || defined(_M_IA64) -#pragma intrinsic(_umul128) -#define mul_64x64_128(a, b, ph) _umul128(a, b, ph) -#pragma intrinsic(__umulh) -#define mul_64x64_high(a, b) __umulh(a, b) -#endif - -#if defined(_M_IX86) -#pragma intrinsic(__emulu) -#define mul_32x32_64(a, b) __emulu(a, b) -#elif defined(_M_ARM) -#define mul_32x32_64(a, b) _arm_umull(a, b) -#endif - -#endif /* compiler */ - -#ifndef bswap64 -#ifdef __bswap_64 -#define bswap64(v) __bswap_64(v) -#else -static __inline uint64_t bswap64(uint64_t v) { - return v << 56 | v >> 56 | ((v << 40) & UINT64_C(0x00ff000000000000)) | - ((v << 24) & UINT64_C(0x0000ff0000000000)) | - ((v << 8) & UINT64_C(0x000000ff00000000)) | - ((v >> 8) & UINT64_C(0x00000000ff0000000)) | - ((v >> 24) & UINT64_C(0x0000000000ff0000)) | - ((v >> 40) & UINT64_C(0x000000000000ff00)); -} -#endif -#endif /* bswap64 */ - -#ifndef bswap32 -#ifdef __bswap_32 -#define bswap32(v) __bswap_32(v) -#else -static __inline uint32_t bswap32(uint32_t v) { - return v << 24 | v >> 24 | ((v << 8) & UINT32_C(0x00ff0000)) | - ((v >> 8) & UINT32_C(0x0000ff00)); -} -#endif -#endif /* bswap32 */ - -#ifndef bswap16 -#ifdef __bswap_16 -#define bswap16(v) __bswap_16(v) -#else -static __inline uint16_t bswap16(uint16_t v) { return v << 8 | v >> 8; } -#endif -#endif /* bswap16 */ - -#define is_byteorder_le() (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -#define is_byteorder_be() (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - -#ifndef htole16 -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define htobe16(v) bswap16(v) -#define htole16(v) (v) -#define be16toh(v) bswap16(v) -#define le16toh(v) (v) -#else -#define htobe16(v) (v) -#define htole16(v) bswap16(v) -#define be16toh(v) (v) -#define le16toh(v) bswap16(v) -#endif -#endif /* htole16 */ - -#ifndef htole32 -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define htobe32(v) bswap32(v) -#define htole32(v) (v) -#define be32toh(v) bswap32(v) -#define le32toh(v) (v) -#else -#define htobe32(v) (v) -#define htole32(v) bswap32(v) -#define be32toh(v) (v) -#define le32toh(v) bswap32(v) -#endif -#endif /* htole32 */ - -#ifndef htole64 -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define htobe64(v) bswap64(v) -#define htole64(v) (v) -#define be64toh(v) bswap64(v) -#define le64toh(v) (v) -#else -#define htobe64(v) (v) -#define htole64(v) bswap_64(v) -#define be64toh(v) (v) -#define le64toh(v) bswap_64(v) -#endif -#endif /* htole64 */ - -namespace unaligned { - -template <typename T> static __inline T load(const void *ptr) { -#if defined(_MSC_VER) && \ - (defined(_M_ARM64) || defined(_M_X64) || defined(_M_IA64)) - return *(const T __unaligned *)ptr; -#elif MDBX_UNALIGNED_OK - return *(const T *)ptr; -#else - T local; -#if defined(__GNUC__) || defined(__clang__) - __builtin_memcpy(&local, (const T *)ptr, sizeof(T)); -#else - memcpy(&local, (const T *)ptr, sizeof(T)); -#endif /* __GNUC__ || __clang__ */ - return local; -#endif /* MDBX_UNALIGNED_OK */ -} - -template <typename T> static __inline void store(void *ptr, const T &value) { -#if defined(_MSC_VER) && \ - (defined(_M_ARM64) || defined(_M_X64) || defined(_M_IA64)) - *((T __unaligned *)ptr) = value; -#elif MDBX_UNALIGNED_OK - *(volatile T *)ptr = value; -#else -#if defined(__GNUC__) || defined(__clang__) - __builtin_memcpy(ptr, &value, sizeof(T)); -#else - memcpy(ptr, &value, sizeof(T)); -#endif /* __GNUC__ || __clang__ */ -#endif /* MDBX_UNALIGNED_OK */ -} - -} /* namespace unaligned */ - -//----------------------------------------------------------------------------- - -#ifndef rot64 -static __inline uint64_t rot64(uint64_t v, unsigned s) { - return (v >> s) | (v << (64 - s)); -} -#endif /* rot64 */ - -static __inline bool is_power2(size_t x) { return (x & (x - 1)) == 0; } - -#undef roundup2 -static __inline size_t roundup2(size_t value, size_t granularity) { - assert(is_power2(granularity)); - return (value + granularity - 1) & ~(granularity - 1); -} - -//----------------------------------------------------------------------------- - -static __inline void memory_barrier(void) { -#if __has_extension(c_atomic) || __has_extension(cxx_atomic) - __c11_atomic_thread_fence(__ATOMIC_SEQ_CST); -#elif defined(__ATOMIC_SEQ_CST) - __atomic_thread_fence(__ATOMIC_SEQ_CST); -#elif defined(__clang__) || defined(__GNUC__) - __sync_synchronize(); -#elif defined(_MSC_VER) - MemoryBarrier(); -#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */ -#if defined(__ia64__) || defined(__ia64) || defined(_M_IA64) - __mf(); -#elif defined(__ia32__) - _mm_mfence(); -#else -#error "Unknown target for Intel Compiler, please report to us." -#endif -#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun) - __machine_rw_barrier(); -#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) && \ - (defined(HP_IA64) || defined(__ia64)) - _Asm_mf(); -#elif defined(_AIX) || defined(__ppc__) || defined(__powerpc__) || \ - defined(__ppc64__) || defined(__powerpc64__) - __lwsync(); -#else -#error "Could not guess the kind of compiler, please report to us." -#endif -} - -static __inline void cpu_relax() { -#if defined(__ia32__) - _mm_pause(); -#elif defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) || \ - defined(YieldProcessor) - YieldProcessor(); -#else -/* nope */ -#endif -} - -//----------------------------------------------------------------------------- - -struct simple_checksum { - uint64_t value{0}; - - simple_checksum() = default; - - void push(const uint32_t &data) { - value += data * UINT64_C(9386433910765580089) + 1; - value ^= value >> 41; - value *= UINT64_C(0xBD9CACC22C6E9571); - } - - void push(const uint64_t &data) { - push((uint32_t)data); - push((uint32_t)(data >> 32)); - } - - void push(const bool data) { - push(data ? UINT32_C(0x780E) : UINT32_C(0xFA18E)); - } - - void push(const void *ptr, size_t bytes) { - const uint8_t *data = (const uint8_t *)ptr; - for (size_t i = 0; i < bytes; ++i) - push((uint32_t)data[i]); - } - - void push(const double &data) { push(&data, sizeof(double)); } - void push(const char *cstr) { push(cstr, strlen(cstr)); } - void push(const std::string &str) { push(str.data(), str.size()); } - - void push(unsigned salt, const MDBX_val &val) { - push(unsigned(val.iov_len)); - push(salt); - push(val.iov_base, val.iov_len); - } - -#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) - void push(const HANDLE &handle) { push(&handle, sizeof(handle)); } -#endif /* _WINDOWS */ -}; - -std::string data2hex(const void *ptr, size_t bytes, simple_checksum &checksum); -bool hex2data(const char *hex_begin, const char *hex_end, void *ptr, - size_t bytes, simple_checksum &checksum); -bool is_samedata(const MDBX_val *a, const MDBX_val *b); -std::string format(const char *fmt, ...); - -uint64_t entropy_ticks(void); -uint64_t entropy_white(void); -static inline uint64_t bleach64(uint64_t v) { - // Tommy Ettinger, https://www.blogger.com/profile/04953541827437796598 - // http://mostlymangling.blogspot.com/2019/01/better-stronger-mixer-and-test-procedure.html - v ^= rot64(v, 25) ^ rot64(v, 50); - v *= UINT64_C(0xA24BAED4963EE407); - v ^= rot64(v, 24) ^ rot64(v, 49); - v *= UINT64_C(0x9FB21C651E98DF25); - return v ^ v >> 28; -} - -static inline uint32_t bleach32(uint32_t x) { - // https://github.com/skeeto/hash-prospector - // exact bias: 0.17353355999581582 - x ^= x >> 16; - x *= UINT32_C(0x7feb352d); - x ^= 0x3027C563 ^ (x >> 15); - x *= UINT32_C(0x846ca68b); - x ^= x >> 16; - return x; -} - -static inline uint64_t prng64_map1_careless(uint64_t state) { - return state * UINT64_C(6364136223846793005) + 1; -} - -static inline uint64_t prng64_map2_careless(uint64_t state) { - return (state + UINT64_C(1442695040888963407)) * - UINT64_C(6364136223846793005); -} - -static inline uint64_t prng64_map1_white(uint64_t state) { - return bleach64(prng64_map1_careless(state)); -} - -static inline uint64_t prng64_map2_white(uint64_t state) { - return bleach64(prng64_map2_careless(state)); -} - -static inline uint64_t prng64_careless(uint64_t &state) { - state = prng64_map1_careless(state); - return state; -} - -static inline double u64_to_double1(uint64_t v) { - union { - uint64_t u64; - double d; - } casting; - - casting.u64 = UINT64_C(0x3ff) << 52 | (v >> 12); - assert(casting.d >= 1.0 && casting.d < 2.0); - return casting.d - 1.0; -} - -uint64_t prng64_white(uint64_t &state); -uint32_t prng32(uint64_t &state); -void prng_fill(uint64_t &state, void *ptr, size_t bytes); - -void prng_seed(uint64_t seed); -uint32_t prng32(void); -uint64_t prng64(void); -void prng_fill(void *ptr, size_t bytes); - -bool flipcoin(); -bool flipcoin_x2(); -bool flipcoin_x3(); -bool flipcoin_x4(); -bool jitter(unsigned probability_percent); -void jitter_delay(bool extra = false); diff --git a/libs/libmdbx/src/test/valgrind_suppress.txt b/libs/libmdbx/src/test/valgrind_suppress.txt deleted file mode 100644 index e1e152051d..0000000000 --- a/libs/libmdbx/src/test/valgrind_suppress.txt +++ /dev/null @@ -1,540 +0,0 @@ -{ - msync-whole-mmap-1 - Memcheck:Param - msync(start) - fun:msync - ... - fun:mdbx_sync_locked -} -{ - msync-whole-mmap-2 - Memcheck:Param - msync(start) - fun:msync - ... - fun:mdbx_env_sync_internal -} - -# modern Valgrind don't support the `vector[...]` pattern -# for((i=0;i<64;++i)); do echo -e "{\n pwrite-page-flush-$i\n Memcheck:Param\n pwritev(vector[$i])\n fun:pwritev\n ...\n fun:mdbx_page_flush\n}"; done >> valgrind_suppress.txt - -{ - pwrite-page-flush - Memcheck:Param - pwritev(vector[...]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-0 - Memcheck:Param - pwritev(vector[0]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-1 - Memcheck:Param - pwritev(vector[1]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-2 - Memcheck:Param - pwritev(vector[2]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-3 - Memcheck:Param - pwritev(vector[3]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-4 - Memcheck:Param - pwritev(vector[4]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-5 - Memcheck:Param - pwritev(vector[5]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-6 - Memcheck:Param - pwritev(vector[6]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-7 - Memcheck:Param - pwritev(vector[7]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-8 - Memcheck:Param - pwritev(vector[8]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-9 - Memcheck:Param - pwritev(vector[9]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-10 - Memcheck:Param - pwritev(vector[10]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-11 - Memcheck:Param - pwritev(vector[11]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-12 - Memcheck:Param - pwritev(vector[12]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-13 - Memcheck:Param - pwritev(vector[13]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-14 - Memcheck:Param - pwritev(vector[14]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-15 - Memcheck:Param - pwritev(vector[15]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-16 - Memcheck:Param - pwritev(vector[16]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-17 - Memcheck:Param - pwritev(vector[17]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-18 - Memcheck:Param - pwritev(vector[18]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-19 - Memcheck:Param - pwritev(vector[19]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-20 - Memcheck:Param - pwritev(vector[20]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-21 - Memcheck:Param - pwritev(vector[21]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-22 - Memcheck:Param - pwritev(vector[22]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-23 - Memcheck:Param - pwritev(vector[23]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-24 - Memcheck:Param - pwritev(vector[24]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-25 - Memcheck:Param - pwritev(vector[25]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-26 - Memcheck:Param - pwritev(vector[26]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-27 - Memcheck:Param - pwritev(vector[27]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-28 - Memcheck:Param - pwritev(vector[28]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-29 - Memcheck:Param - pwritev(vector[29]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-30 - Memcheck:Param - pwritev(vector[30]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-31 - Memcheck:Param - pwritev(vector[31]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-32 - Memcheck:Param - pwritev(vector[32]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-33 - Memcheck:Param - pwritev(vector[33]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-34 - Memcheck:Param - pwritev(vector[34]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-35 - Memcheck:Param - pwritev(vector[35]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-36 - Memcheck:Param - pwritev(vector[36]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-37 - Memcheck:Param - pwritev(vector[37]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-38 - Memcheck:Param - pwritev(vector[38]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-39 - Memcheck:Param - pwritev(vector[39]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-40 - Memcheck:Param - pwritev(vector[40]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-41 - Memcheck:Param - pwritev(vector[41]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-42 - Memcheck:Param - pwritev(vector[42]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-43 - Memcheck:Param - pwritev(vector[43]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-44 - Memcheck:Param - pwritev(vector[44]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-45 - Memcheck:Param - pwritev(vector[45]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-46 - Memcheck:Param - pwritev(vector[46]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-47 - Memcheck:Param - pwritev(vector[47]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-48 - Memcheck:Param - pwritev(vector[48]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-49 - Memcheck:Param - pwritev(vector[49]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-50 - Memcheck:Param - pwritev(vector[50]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-51 - Memcheck:Param - pwritev(vector[51]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-52 - Memcheck:Param - pwritev(vector[52]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-53 - Memcheck:Param - pwritev(vector[53]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-54 - Memcheck:Param - pwritev(vector[54]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-55 - Memcheck:Param - pwritev(vector[55]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-56 - Memcheck:Param - pwritev(vector[56]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-57 - Memcheck:Param - pwritev(vector[57]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-58 - Memcheck:Param - pwritev(vector[58]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-59 - Memcheck:Param - pwritev(vector[59]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-60 - Memcheck:Param - pwritev(vector[60]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-61 - Memcheck:Param - pwritev(vector[61]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-62 - Memcheck:Param - pwritev(vector[62]) - fun:pwritev - ... - fun:mdbx_page_flush -} -{ - pwrite-page-flush-63 - Memcheck:Param - pwritev(vector[63]) - fun:pwritev - ... - fun:mdbx_page_flush -} |