summaryrefslogtreecommitdiff
path: root/libs/libmdbx/src/test
diff options
context:
space:
mode:
authorLeonid Yuriev <leo@yuriev.ru>2020-10-08 02:02:18 +0300
committerGeorge Hazan <ghazan@miranda.im>2020-10-09 16:50:37 +0300
commita519d4617ed83a2167a693ae87934e56889fef05 (patch)
tree85c3aea76fe15268fc0891cf18c328913c6d4347 /libs/libmdbx/src/test
parentbc58e7ec8ef67c37b6d302eaa2e76deedec03106 (diff)
libmdbx: switch to original amalgamated source code (v0.9.1.18)
Amalgamated source code is the recommended form for embedding libmdbx in non-CMake build systems. This amalgamated version contains a minimum of files, is fully ready for use, and make impossible a number of errors. To upgrade or switch to a different version, just unpack to the `src` subdirectory a corresponding `libmdbx-amalgamated-X_Y_Z.zip` at the https://github.com/erthink/libmdbx/releases. For instance, the https://github.com/erthink/libmdbx/releases/download/v0.9.2/libmdbx-amalgamated-0_9_2.zip for the next release. -- Minimal changes have been made to the build configuration: 1. For use the standard `DllMain()` entry of libmdbx: - added the `MDBX_BUILD_SHARED_LIBRARY=1` option; - removed the `MDBX_CONFIG_MANUAL_TLS_CALLBACK` option; - deleted the `miranda.c` file containing only `DllMain()` with the `mdbx_dll_handle()` call, now this is done by the library itself. 2. Removed refs to extra files (that missing in the amalgamated source code): - for building `libmdbx.dll` only the `mdbx.h` and `mdbx.c` are used, but not `mdbx.c++` for a C++ API; - for building the `mdbx_chk`, `mdbx_load`, and `mdbx_dump` utilities only it own sources are used. -- Last libmdbx changes: - Fixed missing installation of `mdbx.h++`. - Fixed use of obsolete `__noreturn`. - Fixed use of `yield` instruction on ARM if unsupported. - Added pthread workaround for buggy toolchain/cmake/buildroot. - Fixed use of `pthread_yield()` for non-GLIBC. - Fixed use of `RegGetValueA()` on Windows 2000/XP. - Fixed use of `GetTickCount64()` on Windows 2000/XP. - Fixed opening DB on a network shares (in the exclusive mode). - Fixed copy&paste typos. - Fixed minor false-positive GCC warning.
Diffstat (limited to 'libs/libmdbx/src/test')
-rw-r--r--libs/libmdbx/src/test/CMakeLists.txt72
-rw-r--r--libs/libmdbx/src/test/append.cc164
-rw-r--r--libs/libmdbx/src/test/base.h118
-rw-r--r--libs/libmdbx/src/test/cases.cc98
-rw-r--r--libs/libmdbx/src/test/chrono.cc136
-rw-r--r--libs/libmdbx/src/test/chrono.h99
-rw-r--r--libs/libmdbx/src/test/config.cc603
-rw-r--r--libs/libmdbx/src/test/config.h337
-rw-r--r--libs/libmdbx/src/test/copy.cc26
-rw-r--r--libs/libmdbx/src/test/darwin/LICENSE24
-rw-r--r--libs/libmdbx/src/test/darwin/README.md8
-rw-r--r--libs/libmdbx/src/test/darwin/pthread_barrier.c110
-rw-r--r--libs/libmdbx/src/test/darwin/pthread_barrier.h83
-rw-r--r--libs/libmdbx/src/test/dead.cc35
-rw-r--r--libs/libmdbx/src/test/dump-load.sh40
-rw-r--r--libs/libmdbx/src/test/hill.cc450
-rw-r--r--libs/libmdbx/src/test/jitter.cc91
-rw-r--r--libs/libmdbx/src/test/keygen.cc352
-rw-r--r--libs/libmdbx/src/test/keygen.h136
-rw-r--r--libs/libmdbx/src/test/log.cc370
-rw-r--r--libs/libmdbx/src/test/log.h104
-rw-r--r--libs/libmdbx/src/test/long_stochastic.sh271
-rw-r--r--libs/libmdbx/src/test/main.cc639
-rw-r--r--libs/libmdbx/src/test/nested.cc286
-rw-r--r--libs/libmdbx/src/test/osal-unix.cc537
-rw-r--r--libs/libmdbx/src/test/osal-windows.cc459
-rw-r--r--libs/libmdbx/src/test/osal.h49
-rw-r--r--libs/libmdbx/src/test/pcrf/README.md2
-rw-r--r--libs/libmdbx/src/test/pcrf/pcrf_test.c413
-rw-r--r--libs/libmdbx/src/test/test.cc755
-rw-r--r--libs/libmdbx/src/test/test.h331
-rw-r--r--libs/libmdbx/src/test/try.cc20
-rw-r--r--libs/libmdbx/src/test/ttl.cc262
-rw-r--r--libs/libmdbx/src/test/utils.cc372
-rw-r--r--libs/libmdbx/src/test/utils.h362
-rw-r--r--libs/libmdbx/src/test/valgrind_suppress.txt540
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 &params) {
- 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 &params,
- 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 &params) {
- 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 = &current[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 &params,
- 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 *>(&params),
- 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 &params,
- 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 &params,
- 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 &params,
- 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 &params,
- result &out);
- static void mk_continue(const serial_t serial, const essentials &params,
- result &out);
- static void mk(const serial_t serial, const essentials &params, 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 &params,
- unsigned &last_space_id);
-void configure_actor(unsigned &last_space_id, const actor_testcase testcase,
- const char *space_id_cstr, const actor_params &params);
-void keycase_setup(const char *casename, actor_params &params);
-
-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
-}