diff options
| author | George Hazan <ghazan@miranda.im> | 2018-09-17 21:21:41 +0300 | 
|---|---|---|
| committer | George Hazan <ghazan@miranda.im> | 2018-09-17 21:21:49 +0300 | 
| commit | d6edbc9108a3ea183774c84993f679e824ad8a6f (patch) | |
| tree | 8c00b848a3e72b502493648d7eaaa05f68addd87 /libs/libmdbx/src | |
| parent | dcc57d5f94f77ed22127cbe3ac2babcf2dd6d4e3 (diff) | |
libmdbx: another important bugfix
Diffstat (limited to 'libs/libmdbx/src')
| -rw-r--r-- | libs/libmdbx/src/CMakeLists.txt | 193 | ||||
| -rw-r--r-- | libs/libmdbx/src/TODO.md | 89 | ||||
| -rw-r--r-- | libs/libmdbx/src/build.sh | 18 | ||||
| -rw-r--r-- | libs/libmdbx/src/mdbx.h | 2 | ||||
| -rw-r--r-- | libs/libmdbx/src/package.sh | 25 | ||||
| -rw-r--r-- | libs/libmdbx/src/src/mdbx.c | 225 | ||||
| -rw-r--r-- | libs/libmdbx/src/test/gc.sh | 30 | ||||
| -rw-r--r-- | libs/libmdbx/src/test/hill.cc | 7 | ||||
| -rw-r--r-- | libs/libmdbx/src/test/jitter.cc | 6 | ||||
| -rw-r--r-- | libs/libmdbx/src/test/keygen.cc | 4 | ||||
| -rw-r--r-- | libs/libmdbx/src/test/keygen.h | 3 | ||||
| -rw-r--r-- | libs/libmdbx/src/test/main.cc | 8 | ||||
| -rw-r--r-- | libs/libmdbx/src/test/osal-unix.cc | 14 | ||||
| -rw-r--r-- | libs/libmdbx/src/test/test.cc | 10 | ||||
| -rw-r--r-- | libs/libmdbx/src/test/test.h | 2 | ||||
| -rw-r--r-- | libs/libmdbx/src/test/utils.cc | 5 | ||||
| -rw-r--r-- | libs/libmdbx/src/test/utils.h | 2 | 
17 files changed, 162 insertions, 481 deletions
diff --git a/libs/libmdbx/src/CMakeLists.txt b/libs/libmdbx/src/CMakeLists.txt deleted file mode 100644 index b664075556..0000000000 --- a/libs/libmdbx/src/CMakeLists.txt +++ /dev/null @@ -1,193 +0,0 @@ -cmake_minimum_required(VERSION 2.8.7) -set(TARGET mdbx) -project(${TARGET}) - -message(WARNING " -*************************************************************** -  MDBX is under active development, database format and API -  aren't stable at least until 2018Q3. New version won't be -  backwards compatible. Main focus of the rework is to provide -  clear and robust API and new features. -*************************************************************** -") - -set(MDBX_VERSION_MAJOR 0) -set(MDBX_VERSION_MINOR 1) -set(MDBX_VERSION_RELEASE 3) -set(MDBX_VERSION_REVISION 1) - -set(MDBX_VERSION_STRING ${MDBX_VERSION_MAJOR}.${MDBX_VERSION_MINOR}.${MDBX_VERSION_RELEASE}) - -enable_language(C) -enable_language(CXX) - -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED on) - -add_definitions(-DNDEBUG=1 -DMDBX_DEBUG=0 -DLIBMDBX_EXPORTS=1 -D_GNU_SOURCE=1) - -find_package(Threads REQUIRED) - -get_directory_property(hasParent PARENT_DIRECTORY) -if(hasParent) -  set(STANDALONE_BUILD 0) -else() -  set(STANDALONE_BUILD 1) -  enable_testing() - -  if (CMAKE_C_COMPILER_ID MATCHES GNU) -    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2") -    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3") -    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") -    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") -    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra") -    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections") -    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") -    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") -    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11") -    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") -  endif() - -  if (CMAKE_CXX_COMPILER_ID MATCHES GNU) -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpointer-arith") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-sign-compare") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat-security") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wwrite-strings") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmax-errors=20") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wunused-function -Wunused-variable -Wunused-value -Wmissing-declarations") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-field-initializers") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-qual") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-strict-aliasing") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -finline-functions-called-once") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-packed-bitfield-compat") - -    set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3") -    set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g3") -  endif() - -  if (COVERAGE) -    if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") -      message(FATAL_ERROR "Coverage requires -DCMAKE_BUILD_TYPE=Debug Current value=${CMAKE_BUILD_TYPE}") -    endif() - -    message(STATUS "Setting coverage compiler flags") -    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb3 -O0 --coverage -fprofile-arcs -ftest-coverage") -    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}     -g -ggdb3 -O0 --coverage -fprofile-arcs -ftest-coverage") -    add_definitions(-DCOVERAGE_TEST) -  endif() - -  if (NOT TRAVIS) -    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fsanitize=leak -fstack-protector-strong -static-libasan") -  endif() -endif() - -set(${TARGET}_SRC -  mdbx.h -  src/bits.h -  src/defs.h -  src/lck-posix.c -  src/mdbx.c -  src/osal.c -  src/osal.h -  src/version.c -  ) - -add_library(${TARGET}_STATIC STATIC -  ${${TARGET}_SRC} -  ) - -add_library(${TARGET} ALIAS ${TARGET}_STATIC) - -add_library(${TARGET}_SHARED SHARED -  ${${TARGET}_SRC} -  ) - -set_target_properties(${TARGET}_SHARED PROPERTIES -  VERSION ${MDBX_VERSION_STRING} -  SOVERSION ${MDBX_VERSION_MAJOR} -  OUTPUT_NAME ${TARGET} -  CLEAN_DIRECT_OUTPUT 1 -  ) - -set_target_properties(${TARGET}_STATIC PROPERTIES -  VERSION ${MDBX_VERSION_STRING} -  SOVERSION ${MDBX_VERSION_MAJOR} -  OUTPUT_NAME ${TARGET} -  CLEAN_DIRECT_OUTPUT 1 -  ) - -target_include_directories(${TARGET}_STATIC PUBLIC -  ${CMAKE_CURRENT_SOURCE_DIR}) -target_include_directories(${TARGET}_SHARED PUBLIC -  ${CMAKE_CURRENT_SOURCE_DIR}) - -target_link_libraries(${TARGET}_STATIC ${CMAKE_THREAD_LIBS_INIT}) -target_link_libraries(${TARGET}_SHARED ${CMAKE_THREAD_LIBS_INIT}) -if(UNIX AND NOT APPLE) -  target_link_libraries(${TARGET}_STATIC rt) -  target_link_libraries(${TARGET}_SHARED rt) -endif() - -install(TARGETS ${TARGET}_STATIC DESTINATION ${CMAKE_INSTALL_PREFIX}/lib64 COMPONENT mdbx) -install(TARGETS ${TARGET}_SHARED DESTINATION ${CMAKE_INSTALL_PREFIX}/lib64 COMPONENT mdbx) -install(FILES mdbx.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include COMPONENT mdbx-devel) - -add_subdirectory(src/tools) -add_subdirectory(test) -add_subdirectory(test/pcrf) -add_subdirectory(tutorial) - -############################################################################## - -set(CPACK_GENERATOR "RPM") -set(CPACK_RPM_COMPONENT_INSTALL ON) - -# Version -if (NOT "$ENV{BUILD_NUMBER}" STREQUAL "") -  set(CPACK_PACKAGE_RELEASE $ENV{BUILD_NUMBER}) -else() -  if (NOT "$ENV{CI_PIPELINE_ID}" STREQUAL "") -    set(CPACK_PACKAGE_RELEASE $ENV{CI_PIPELINE_ID}) -  else() -    set(CPACK_PACKAGE_RELEASE 1) -  endif() -endif() -set(CPACK_RPM_PACKAGE_RELEASE ${CPACK_PACKAGE_RELEASE}) - -set(CPACK_PACKAGE_VERSION ${MDBX_VERSION_STRING}) -set(CPACK_PACKAGE_VERSION_FULL ${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_RELEASE}) - -set(CPACK_RPM_mdbx-devel_PACKAGE_REQUIRES "mdbx = ${CPACK_PACKAGE_VERSION}") - -set(CPACK_RPM_SPEC_INSTALL_POST "/bin/true") -set(CPACK_RPM_mdbx_PACKAGE_NAME mdbx) -set(CPACK_RPM_mdbx-devel_PACKAGE_NAME mdbx-devel) -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The revised and extended descendant of Symas LMDB") - -set(CPACK_PACKAGE_VENDOR "???") -set(CPACK_PACKAGE_CONTACT "Vladimir Romanov") -set(CPACK_PACKAGE_RELOCATABLE false) -set(CPACK_RPM_PACKAGE_ARCHITECTURE "x86_64") -set(CPACK_RPM_PACKAGE_REQUIRES "") -set(CPACK_RPM_PACKAGE_GROUP "Applications/Database") - -set(CPACK_RPM_mdbx_FILE_NAME "${CPACK_RPM_mdbx_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION_FULL}.${CPACK_RPM_PACKAGE_ARCHITECTURE}.rpm") -set(CPACK_RPM_mdbx-devel_FILE_NAME "${CPACK_RPM_mdbx-devel_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION_FULL}.${CPACK_RPM_PACKAGE_ARCHITECTURE}.rpm") - -set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION -  /usr/local -  /usr/local/bin -  /usr/local/lib64 -  /usr/local/include -  /usr/local/man -  /usr/local/man/man1 -  ) - -include(CPack) diff --git a/libs/libmdbx/src/TODO.md b/libs/libmdbx/src/TODO.md deleted file mode 100644 index 810b18dc4a..0000000000 --- a/libs/libmdbx/src/TODO.md +++ /dev/null @@ -1,89 +0,0 @@ -Допеределки -=========== -- [ ] Перевод mdbx-tools на С++ и сборка для Windows. -- [ ] Переход на CMake, замена заглушек mdbx_version и mdbx_build. -- [ ] Актуализация README.md -- [ ] Переход на C++11, добавление #pramga detect_mismatch(). -- [ ] Убрать MDB_DEBUG (всегда: логирование важный ситуаций и ошибок, опционально: включение ассертов и трассировка). -- [ ] Заменить mdbx_debug на mdbx_trace, и почистить... -- [ ] Заметить максимум assert() на mdbx_assert(env, ...). - -Качество и CI -============= -- [ ] Добавить в CI linux сборки для 32-битных таргетов. - -Доработки API -============= -- [ ] Поправить/Добавить описание нового API. -- [ ] Добавить возможность "подбора" режима для mdbx_env_open(). -- [ ] Переименовать в API: env->db, db->tbl. - -Тесты -===== -- [ ] Тестирование поддержки lockless-режима. -- [x] Додумать имя и размещение тестовой БД по-умолчанию. -- [ ] Реализовать cleanup в тесте. -- [ ] usage для теста. -- [ ] Логирование в файл, плюс более полный progress bar. -- [ ] Опция игнорирования (пропуска части теста) при переполнении БД. -- [ ] Базовый бенчмарк. - -Развитие -======== -- [ ] Отслеживание времени жизни DBI-хендлов. -- [ ] Отрефакторить mdbx_freelist_save(). -- [ ] Хранить "свободный хвост" не связанный с freeDB в META. -- [x] Возврат выделенных страниц в unallocated tail-pool. -- [ ] Валидатор страниц БД по номеру транзакции: -      ~0 при переработке и номер транзакции при выделении, -      проверять что этот номер больше головы реклайминга и не-больше текущей транзакции. -- [ ] Размещение overflow-pages в отдельном mmap/файле с собственной геометрией. -- [ ] Зафиксировать формат БД. -- [ ] Валидатор страниц по CRC32, плюс контроль номер транзакии под модулю 2^32. -- [ ] Валидатор страниц по t1ha c контролем снимков/версий БД на основе Merkle Tree. -- [ ] Возможность хранения ключей внутри data (libfptu). -- [ ] Асинхронная фиксация (https://github.com/leo-yuriev/libmdbx/issues/5). -- [ ] (Пере)Выделять память под IDL-списки с учетом реального кол-ва страниц, т.е. max(MDB_IDL_UM_MAX/MDB_IDL_UM_MAX, npages). - ------------------------------------------------------------------------ - -Сделано -======= -- [x] разделение errno и GetLastError(). -- [x] CI посредством AppVeyor. -- [x] тест конкурентного доступа. -- [x] тест основного функционала (заменить текущий треш). -- [x] uint32/uint64 в структурах. -- [x] Завершить переименование. -- [x] Макросы версионности, сделать как в fpta (cmake?). -- [x] Попробовать убрать yield (или что там с местом?). -- [x] trinity для copy/compaction. -- [x] trinity для mdbx_chk и mdbx_stat. -- [x] проверки с mdbx_meta_eq. -- [x] Не проверять режим при открытии в readonly. -- [x] Поправить выбор tail в mdbx_chk. -- [x] Там-же проверять позицию реклайминга. -- [x] поправить проблему открытия после READ-ONLY. -- [x] static-assertы на размер/выравнивание lck, meta и т.п. -- [x] Зачистить size_t. -- [x] Добавить локи вокруг dbi. -- [x] Привести в порядок volatile. -- [x] контроль meta.mapsize. -- [x] переработка формата: заголовки страниц, meta, clk... -- [x] зачистка Doxygen и бесполезных комментариев. -- [x] Добавить поле типа контрольной суммы. -- [x] Добавить поле/флаг размера pgno_t. -- [x] Поменять сигнатуры. -- [x] Добавить мета-страницы в coredump, проверить lck. -- [x] Сделать список для txnid_t, кода sizeof(txnid_t) > sizeof(pgno_t) и вернуть размер pgno_t. -- [x] Избавиться от умножения на размер страницы (заменить на сдвиг). -- [x] Устранение всех предупреждений (в том числе под Windows). -- [x] Добавить 'mti_reader_finished_flag'. -- [x] Погасить все level4-warnings от MSVC, включить /WX. -- [x] Проверка посредством Coverity с гашением всех дефектов. -- [x] Полная матрица Windows-сборок (2013/2015/2017). -- [x] Дать возможность задавать размер страницы при создании БД. -- [x] Изменение mapsize через API с блокировкой и увеличением txn. -- [x] Контроль размера страницы полного размера и кол-ва страниц при создании и обновлении. -- [x] Инкрементальный mmap. -- [x] Инкрементальное приращение размера (колбэк стратегии?). diff --git a/libs/libmdbx/src/build.sh b/libs/libmdbx/src/build.sh deleted file mode 100644 index 5170882265..0000000000 --- a/libs/libmdbx/src/build.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -set -e -CONFIG=$1 - -if [[ -z "${CONFIG}" ]]; then -    CONFIG=Debug -fi -if [[ -r /opt/rh/devtoolset-6/enable ]]; then -    source /opt/rh/devtoolset-6/enable -fi -#rm -f -r build || true -mkdir -p cmake-build-${CONFIG} -pushd  cmake-build-${CONFIG} &> /dev/null -if [[ ! -r Makefile ]]; then -    cmake .. -DCMAKE_BUILD_TYPE=${CONFIG} -fi -make -j8 || exit 1 -popd &> /dev/null diff --git a/libs/libmdbx/src/mdbx.h b/libs/libmdbx/src/mdbx.h index 2d0eeba949..8720f34ae0 100644 --- a/libs/libmdbx/src/mdbx.h +++ b/libs/libmdbx/src/mdbx.h @@ -1251,6 +1251,8 @@ LIBMDBX_API int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, int del);   *  - MDBX_EINVAL   - an invalid parameter was specified. */  LIBMDBX_API int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,                           MDBX_val *data); +LIBMDBX_API int mdbx_get2(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, +                          MDBX_val *data);  /* Store items into a database.   * diff --git a/libs/libmdbx/src/package.sh b/libs/libmdbx/src/package.sh deleted file mode 100644 index d7f9ab297a..0000000000 --- a/libs/libmdbx/src/package.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -set -e - -CONFIG=$1 - -if [[ -z "${CONFIG}" ]]; then -    CONFIG=Debug -fi - -DIRNAME=`dirname ${BASH_SOURCE[0]}` -DIRNAME=`readlink --canonicalize ${DIRNAME}` - -if [[ -r /opt/rh/devtoolset-6/enable ]]; then -    source /opt/rh/devtoolset-6/enable -fi - -mkdir -p cmake-build-${CONFIG} -pushd  cmake-build-${CONFIG} &> /dev/null -if [[ ! -r Makefile ]]; then -    cmake .. -DCMAKE_BUILD_TYPE=${CONFIG} -fi -rm -f *.rpm -make -j8 package || exit 1 -rm -f *-Unspecified.rpm -popd &> /dev/null diff --git a/libs/libmdbx/src/src/mdbx.c b/libs/libmdbx/src/src/mdbx.c index 82e0959134..9cfeba8809 100644 --- a/libs/libmdbx/src/src/mdbx.c +++ b/libs/libmdbx/src/src/mdbx.c @@ -3680,6 +3680,25 @@ static int mdbx_update_gc(MDBX_txn *txn) {    if (unlikely(rc != MDBX_SUCCESS))      goto bailout; +  txnid_t reclaiming_head_id = env->me_last_reclaimed; +  if (unlikely(reclaiming_head_id == 0)) { +    reclaiming_head_id = mdbx_find_oldest(txn) - 1; +    MDBX_val key; +    rc = mdbx_cursor_get(&mc, &key, NULL, MDBX_FIRST); +    if (unlikely(rc != MDBX_SUCCESS)) { +      if (rc != MDBX_NOTFOUND) +        goto bailout; +    } else if (unlikely(key.iov_len != sizeof(txnid_t))) { +      rc = MDBX_CORRUPTED; +      goto bailout; +    } else { +      txnid_t first_pg; +      memcpy(&first_pg, key.iov_base, sizeof(txnid_t)); +      if (reclaiming_head_id >= first_pg) +        reclaiming_head_id = first_pg - 1; +    } +  } +  retry:    mdbx_trace(" >> restart");    mdbx_tassert(txn, mdbx_pnl_check(env->me_reclaimed_pglist, true)); @@ -3687,7 +3706,7 @@ retry:             filled_gc_slot = ~0u;    txnid_t cleaned_gc_id = 0, head_gc_id = env->me_last_reclaimed                                                ? env->me_last_reclaimed -                                              : ~(txnid_t)0; +                                              : reclaiming_head_id;    if (unlikely(/* paranoia */ ++loop > 42)) {      mdbx_error("too more loops %u, bailout", loop); @@ -3963,7 +3982,7 @@ retry:      if (0 >= (int)left)        break; -    const unsigned max_spread = 10; +    const unsigned prefer_max_scatter = 257;      txnid_t reservation_gc_id;      if (lifo) {        assert(txn->mt_lifo_reclaimed != NULL); @@ -3976,7 +3995,7 @@ retry:        }        if (head_gc_id > 1 && -          MDBX_PNL_SIZE(txn->mt_lifo_reclaimed) < max_spread && +          MDBX_PNL_SIZE(txn->mt_lifo_reclaimed) < prefer_max_scatter &&            left > ((unsigned)MDBX_PNL_SIZE(txn->mt_lifo_reclaimed) -                    reused_gc_slots) *                       env->me_maxgc_ov1page) { @@ -3995,7 +4014,7 @@ retry:          /* LY: freedb is empty, will look any free txn-id in high2low order. */          do {            --head_gc_id; -          assert(MDBX_PNL_LAST(txn->mt_lifo_reclaimed) > head_gc_id); +          mdbx_assert(env, MDBX_PNL_LAST(txn->mt_lifo_reclaimed) > head_gc_id);            rc = mdbx_txl_append(&txn->mt_lifo_reclaimed, head_gc_id);            if (unlikely(rc != MDBX_SUCCESS))              goto bailout; @@ -4005,7 +4024,7 @@ retry:                       " to lifo-reclaimed, cleaned-gc-slot = %u",                       dbg_prefix_mode, head_gc_id, cleaned_gc_slot);          } while (head_gc_id > 1 && -                 MDBX_PNL_SIZE(txn->mt_lifo_reclaimed) < max_spread && +                 MDBX_PNL_SIZE(txn->mt_lifo_reclaimed) < prefer_max_scatter &&                   left > ((unsigned)MDBX_PNL_SIZE(txn->mt_lifo_reclaimed) -                           reused_gc_slots) *                              env->me_maxgc_ov1page); @@ -4045,7 +4064,10 @@ retry:          if (chunk < env->me_maxgc_ov1page * 2)            chunk /= 2;          else { -          const unsigned threshold = env->me_maxgc_ov1page * avail_gs_slots; +          const unsigned threshold = +              env->me_maxgc_ov1page * ((avail_gs_slots < prefer_max_scatter) +                                           ? avail_gs_slots +                                           : prefer_max_scatter);            if (left < threshold)              chunk = env->me_maxgc_ov1page;            else { @@ -4071,7 +4093,7 @@ retry:              chunk = (avail >= tail) ? tail - span                                      : (avail_gs_slots > 3 && -                                       reused_gc_slots < max_spread - 3) +                                       reused_gc_slots < prefer_max_scatter - 3)                                            ? avail - span                                            : tail;            } @@ -4112,6 +4134,14 @@ retry:      settled += chunk;      mdbx_trace("%s.settled %u (+%u), continue", dbg_prefix_mode, settled,                 chunk); + +    if (txn->mt_lifo_reclaimed && +        unlikely(amount < MDBX_PNL_SIZE(env->me_reclaimed_pglist))) { +      mdbx_notice("** restart: reclaimed-list growth %u -> %u", amount, +                  (unsigned)MDBX_PNL_SIZE(env->me_reclaimed_pglist)); +      goto retry; +    } +      continue;    } @@ -7142,6 +7172,41 @@ int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) {    return mdbx_cursor_set(&cx.outer, key, data, MDBX_SET, &exact);  } +int mdbx_get2(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) { +  int exact = 0; +  DKBUF; + +  mdbx_debug("===> get db %u key [%s]", dbi, DKEY(key)); + +  if (unlikely(!key || !data || !txn)) +    return MDBX_EINVAL; + +  if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE)) +    return MDBX_EBADSIGN; + +  if (unlikely(txn->mt_owner != mdbx_thread_self())) +    return MDBX_THREAD_MISMATCH; + +  if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))) +    return MDBX_EINVAL; + +  if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED)) +    return MDBX_BAD_TXN; + +  MDBX_cursor_couple cx; +  int rc = mdbx_cursor_init(&cx.outer, txn, dbi); +  if (unlikely(rc != MDBX_SUCCESS)) +    return rc; + +  const int op = +      (txn->mt_dbs[dbi].md_flags & MDBX_DUPSORT) ? MDBX_GET_BOTH : MDBX_SET_KEY; +  rc = mdbx_cursor_set(&cx.outer, key, data, op, &exact); +  if (unlikely(rc != MDBX_SUCCESS)) +    return rc; + +  return exact ? MDBX_SUCCESS : MDBX_RESULT_TRUE; +} +  /* Find a sibling for a page.   * Replaces the page at the top of the cursor's stack with the specified   * sibling, if one exists. @@ -7739,11 +7804,6 @@ int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,        return MDBX_INCOMPATIBLE;    /* FALLTHRU */    case MDBX_SET: -#ifndef SLAPD_LMDB_LEGACY -    if (op == MDBX_SET && unlikely(data != NULL)) -      return MDBX_EINVAL; -#endif /* SLAPD_LMDB_LEGACY */ -  /* FALLTHRU */    case MDBX_SET_KEY:    case MDBX_SET_RANGE:      if (unlikely(key == NULL)) @@ -8931,131 +8991,6 @@ static int __must_check_result mdbx_node_add_leaf(MDBX_cursor *mc,    return MDBX_SUCCESS;  } -#if 0 -/* Add a node to the page pointed to by the cursor. - * Set MDBX_TXN_ERROR on failure. - * - * [in] mc    The cursor for this operation. - * [in] indx  The index on the page where the new node should be added. - * [in] key   The key for the new node. - * [in] data  The data for the new node, if any. - * [in] pgno  The page number, if adding a branch node. - * [in] flags Flags for the node. - * - * Returns 0 on success, non-zero on failure. Possible errors are: - * - * MDBX_ENOMEM    - failed to allocate overflow pages for the node. - * MDBX_PAGE_FULL  - there is insufficient room in the page. This error - *                  should never happen since all callers already calculate - *                  the page's free space before calling this function. */ -static int mdbx_node_add(MDBX_cursor *mc, unsigned indx, const MDBX_val *key, -                         MDBX_val *data, pgno_t pgno, unsigned flags) { -  unsigned i; -  size_t node_size = NODESIZE; -  intptr_t room; -  MDBX_node *node; -  MDBX_page *mp = mc->mc_pg[mc->mc_top]; -  MDBX_page *ofp = NULL; /* overflow page */ -  void *ndata; - -  mdbx_cassert(mc, mp->mp_upper >= mp->mp_lower); - -  DKBUF; -  mdbx_debug("add to %s %spage %" PRIaPGNO " index %i, data size %" PRIuPTR -             " key size %" PRIuPTR " [%s]", -             IS_LEAF(mp) ? "leaf" : "branch", IS_SUBP(mp) ? "sub-" : "", -             mp->mp_pgno, indx, data ? data->iov_len : 0, -             key ? key->iov_len : 0, DKEY(key)); - -  room = (intptr_t)SIZELEFT(mp) - (intptr_t)sizeof(indx_t); -  if (key != NULL) -    node_size += key->iov_len; -  if (IS_LEAF(mp)) { -    mdbx_cassert(mc, key && data); -    if (unlikely(F_ISSET(flags, F_BIGDATA))) { -      /* Data already on overflow page. */ -      node_size += sizeof(pgno_t); -    } else if (unlikely(node_size + data->iov_len > -                        mc->mc_txn->mt_env->me_nodemax)) { -      pgno_t ovpages = OVPAGES(mc->mc_txn->mt_env, data->iov_len); -      int rc; -      /* Put data on overflow page. */ -      mdbx_debug("data size is %" PRIuPTR ", node would be %" PRIuPTR -                 ", put data on overflow page", -                 data->iov_len, node_size + data->iov_len); -      node_size = EVEN(node_size + sizeof(pgno_t)); -      if ((intptr_t)node_size > room) -        goto full; -      if ((rc = mdbx_page_new(mc, P_OVERFLOW, ovpages, &ofp))) -        return rc; -      mdbx_debug("allocated overflow page %" PRIaPGNO, ofp->mp_pgno); -      flags |= F_BIGDATA; -      goto update; -    } else { -      node_size += data->iov_len; -    } -  } -  node_size = EVEN(node_size); -  if (unlikely((intptr_t)node_size > room)) -    goto full; - -update: -  /* Move higher pointers up one slot. */ -  for (i = NUMKEYS(mp); i > indx; i--) -    mp->mp_ptrs[i] = mp->mp_ptrs[i - 1]; - -  /* Adjust free space offsets. */ -  size_t ofs = mp->mp_upper - node_size; -  mdbx_cassert(mc, ofs >= mp->mp_lower + sizeof(indx_t)); -  mdbx_cassert(mc, ofs <= UINT16_MAX); -  mp->mp_ptrs[indx] = (uint16_t)ofs; -  mp->mp_upper = (uint16_t)ofs; -  mp->mp_lower += sizeof(indx_t); - -  /* Write the node data. */ -  node = NODEPTR(mp, indx); -  node->mn_ksize = (key == NULL) ? 0 : (uint16_t)key->iov_len; -  node->mn_flags = (uint16_t)flags; -  if (IS_LEAF(mp)) -    SETDSZ(node, data->iov_len); -  else -    SETPGNO(node, pgno); - -  if (key) -    memcpy(NODEKEY(node), key->iov_base, key->iov_len); - -  if (IS_LEAF(mp)) { -    ndata = NODEDATA(node); -    if (likely(ofp == NULL)) { -      if (unlikely(F_ISSET(flags, F_BIGDATA))) -        memcpy(ndata, data->iov_base, sizeof(pgno_t)); -      else if (F_ISSET(flags, MDBX_RESERVE)) -        data->iov_base = ndata; -      else if (likely(ndata != data->iov_base)) -        memcpy(ndata, data->iov_base, data->iov_len); -    } else { -      memcpy(ndata, &ofp->mp_pgno, sizeof(pgno_t)); -      ndata = PAGEDATA(ofp); -      if (F_ISSET(flags, MDBX_RESERVE)) -        data->iov_base = ndata; -      else if (likely(ndata != data->iov_base)) -        memcpy(ndata, data->iov_base, data->iov_len); -    } -  } - -  return MDBX_SUCCESS; - -full: -  mdbx_debug("not enough room in page %" PRIaPGNO ", got %u ptrs", mp->mp_pgno, -             NUMKEYS(mp)); -  mdbx_debug("upper-lower = %u - %u = %" PRIiPTR, mp->mp_upper, mp->mp_lower, -             room); -  mdbx_debug("node size = %" PRIuPTR, node_size); -  mc->mc_txn->mt_flags |= MDBX_TXN_ERROR; -  return MDBX_PAGE_FULL; -} -#endif -  /* Delete the specified node from a page.   * [in] mc Cursor pointing to the node to delete.   * [in] ksize The size of a node. Only used if the page is @@ -11751,6 +11686,20 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,    if (unlikely(!txn || !dbi || (user_flags & ~VALID_FLAGS) != 0))      return MDBX_EINVAL; +  switch (user_flags & +          (MDBX_INTEGERDUP | MDBX_DUPFIXED | MDBX_DUPSORT | MDBX_REVERSEDUP)) { +  default: +    return MDBX_EINVAL; +  case MDBX_DUPSORT: +  case MDBX_DUPSORT | MDBX_REVERSEDUP: +  case MDBX_DUPSORT | MDBX_DUPFIXED: +  case MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_REVERSEDUP: +  case MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERDUP: +  case MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_INTEGERDUP | MDBX_REVERSEDUP: +  case 0: +    break; +  } +    if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))      return MDBX_EBADSIGN; @@ -12983,7 +12932,7 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *new_data,      rc = mdbx_cursor_get(&cx.outer, &present_key, &present_data, MDBX_SET_KEY);      if (unlikely(rc != MDBX_SUCCESS)) {        old_data->iov_base = NULL; -      old_data->iov_len = rc; +      old_data->iov_len = 0;        if (rc != MDBX_NOTFOUND || (flags & MDBX_CURRENT))          goto bailout;      } else if (flags & MDBX_NOOVERWRITE) { diff --git a/libs/libmdbx/src/test/gc.sh b/libs/libmdbx/src/test/gc.sh index bddd92af24..0625518a4f 100644 --- a/libs/libmdbx/src/test/gc.sh +++ b/libs/libmdbx/src/test/gc.sh @@ -32,31 +32,31 @@ function probe {  caption="Failfast #1" probe \  	--pagesize=min --size=6G --table=+data.dups --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ -	--nops=99999 --batch.write=9 --mode=-writemap,-coalesce,+lifo --keygen.seed=248240655 --hill +	--nops=99999 --batch.write=9 --mode=-writemap,-coalesce,+lifo --keygen.seed=248240655 basic  caption="Failfast #2" probe \  	--pagesize=min --size=6G --table=-data.dups --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \ -	--nops=999999 --batch.write=999 --mode=+writemap,+coalesce,+lifo --keygen.seed=259083046 --hill +	--nops=999999 --batch.write=999 --mode=+writemap,+coalesce,+lifo --keygen.seed=259083046 basic  caption="Failfast #3" probe \  	--pagesize=min --size=6G --table=-data.dups --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \ -	--nops=999999 --batch.write=999 --mode=+writemap,+coalesce,+lifo --keygen.seed=522365681 --hill +	--nops=999999 --batch.write=999 --mode=+writemap,+coalesce,+lifo --keygen.seed=522365681 basic  caption="Failfast #4" probe \  	--pagesize=min --size=6G --table=-data.dups --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \ -	--nops=999999 --batch.write=9999 --mode=-writemap,+coalesce,+lifo --keygen.seed=866083781 --hill +	--nops=999999 --batch.write=9999 --mode=-writemap,+coalesce,+lifo --keygen.seed=866083781 basic  caption="Failfast #5" probe \  	--pagesize=min --size=6G --table=-data.dups --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \ -	--nops=999999 --batch.write=999 --mode=+writemap,-coalesce,+lifo --keygen.seed=246539192 --hill +	--nops=999999 --batch.write=999 --mode=+writemap,-coalesce,+lifo --keygen.seed=246539192 basic  caption="Failfast #6" probe \  	--pagesize=min --size=6G --table=-data.dups --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \ -	--nops=999999 --batch.write=999 --mode=+writemap,+coalesce,+lifo --keygen.seed=540406278 --hill +	--nops=999999 --batch.write=999 --mode=+writemap,+coalesce,+lifo --keygen.seed=540406278 basic  caption="Failfast #7" probe \  	--pagesize=min --size=6G --table=+data.dups --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ -	--nops=999999 --batch.write=999 --mode=-writemap,+coalesce,+lifo --keygen.seed=619798690 --hill +	--nops=999999 --batch.write=999 --mode=-writemap,+coalesce,+lifo --keygen.seed=619798690 basic  count=0  for nops in {2..7}; do @@ -65,14 +65,26 @@ for nops in {2..7}; do  		for ((rep=0; rep++ < loops; )); do  			for ((bits=2**${#options[@]}; --bits >= 0; )); do  				seed=$(date +%N) +				caption="Probe #$((++count)) int-key,w/o-dups, repeat ${rep} of ${loops}" probe \ +					--pagesize=min --size=6G --table=+key.integer,-data.dups --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \ +					--nops=$( rep9 $nops ) --batch.write=$( rep9 $wbatch ) --mode=$(bits2list options $bits) \ +					--keygen.seed=${seed} basic +				caption="Probe #$((++count)) int-key,with-dups, repeat ${rep} of ${loops}" probe \ +					--pagesize=min --size=6G --table=+key.integer,+data.dups --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ +					--nops=$( rep9 $nops ) --batch.write=$( rep9 $wbatch ) --mode=$(bits2list options $bits) \ +					--keygen.seed=${seed} basic +				caption="Probe #$((++count)) int-key,int-data, repeat ${rep} of ${loops}" probe \ +					--pagesize=min --size=6G --table=+key.integer,+data.integer --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \ +					--nops=$( rep9 $nops ) --batch.write=$( rep9 $wbatch ) --mode=$(bits2list options $bits) \ +					--keygen.seed=${seed} basic  				caption="Probe #$((++count)) w/o-dups, repeat ${rep} of ${loops}" probe \  					--pagesize=min --size=6G --table=-data.dups --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \  					--nops=$( rep9 $nops ) --batch.write=$( rep9 $wbatch ) --mode=$(bits2list options $bits) \ -					--keygen.seed=${seed} --hill +					--keygen.seed=${seed} basic  				caption="Probe #$((++count)) with-dups, repeat ${rep} of ${loops}" probe \  					--pagesize=min --size=6G --table=+data.dups --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \  					--nops=$( rep9 $nops ) --batch.write=$( rep9 $wbatch ) --mode=$(bits2list options $bits) \ -					--keygen.seed=${seed} --hill +					--keygen.seed=${seed} basic  			done  		done  	done diff --git a/libs/libmdbx/src/test/hill.cc b/libs/libmdbx/src/test/hill.cc index 0193c4f2f5..10cb308942 100644 --- a/libs/libmdbx/src/test/hill.cc +++ b/libs/libmdbx/src/test/hill.cc @@ -53,7 +53,7 @@ bool testcase_hill::run() {     */    /* TODO: работа в несколько потоков */ -  keyvalue_maker.setup(config.params, 0 /* thread_number */); +  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); @@ -114,6 +114,7 @@ bool testcase_hill::run() {      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);      rc = mdbx_replace(txn_guard.get(), dbi, &a_key->value, &a_data_0->value,                        &a_data_1->value, update_flags);      if (unlikely(rc != MDBX_SUCCESS)) @@ -126,6 +127,7 @@ bool testcase_hill::run() {      // удаляем вторую запись      log_trace("uphill: delete-b %" PRIu64, b_serial); +    checkdata("uphill: delete-b", dbi, b_key->value, b_data->value);      rc = mdbx_del(txn_guard.get(), dbi, &b_key->value, &b_data->value);      if (unlikely(rc != MDBX_SUCCESS))        failure_perror("mdbx_del(b)", rc); @@ -158,6 +160,7 @@ bool testcase_hill::run() {                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);      int rc = mdbx_replace(txn_guard.get(), dbi, &a_key->value, &a_data_1->value,                            &a_data_0->value, update_flags);      if (unlikely(rc != MDBX_SUCCESS)) @@ -184,6 +187,7 @@ bool testcase_hill::run() {      // удаляем первую запись      log_trace("downhill: delete-a (age %" PRIu64 ") %" PRIu64, age_shift,                a_serial); +    checkdata("downhill: delete-a", dbi, a_key->value, a_data_1->value);      rc = mdbx_del(txn_guard.get(), dbi, &a_key->value, &a_data_1->value);      if (unlikely(rc != MDBX_SUCCESS))        failure_perror("mdbx_del(a)", rc); @@ -195,6 +199,7 @@ bool testcase_hill::run() {      // удаляем вторую запись      log_trace("downhill: delete-b %" PRIu64, b_serial); +    checkdata("downhill: delete-b", dbi, b_key->value, b_data->value);      rc = mdbx_del(txn_guard.get(), dbi, &b_key->value, &b_data->value);      if (unlikely(rc != MDBX_SUCCESS))        failure_perror("mdbx_del(b)", rc); diff --git a/libs/libmdbx/src/test/jitter.cc b/libs/libmdbx/src/test/jitter.cc index e7faf2a3f9..2551400443 100644 --- a/libs/libmdbx/src/test/jitter.cc +++ b/libs/libmdbx/src/test/jitter.cc @@ -58,7 +58,11 @@ bool testcase_jitter::run() {      jitter_delay();      db_close(); -    report(1); + +    /* 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 index 0b68194dc1..c7a706065f 100644 --- a/libs/libmdbx/src/test/keygen.cc +++ b/libs/libmdbx/src/test/keygen.cc @@ -142,7 +142,7 @@ void __hot maker::pair(serial_t serial, const buffer &key, buffer &value,    }  } -void maker::setup(const config::actor_params_pod &actor, +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); @@ -161,7 +161,7 @@ void maker::setup(const config::actor_params_pod &actor,    assert(thread_number < 2);    (void)thread_number;    mapping = actor.keygen; -  salt = actor.keygen.seed * UINT64_C(14653293970879851569); +  salt = (actor.keygen.seed + actor_id) * UINT64_C(14653293970879851569);    // FIXME: TODO    base = 0; diff --git a/libs/libmdbx/src/test/keygen.h b/libs/libmdbx/src/test/keygen.h index 449165ae9a..bbd97b29d1 100644 --- a/libs/libmdbx/src/test/keygen.h +++ b/libs/libmdbx/src/test/keygen.h @@ -119,7 +119,8 @@ public:    void pair(serial_t serial, const buffer &key, buffer &value,              serial_t value_age); -  void setup(const config::actor_params_pod &actor, unsigned thread_number); +  void setup(const config::actor_params_pod &actor, unsigned actor_id, +             unsigned thread_number);    bool increment(serial_t &serial, int delta);  }; diff --git a/libs/libmdbx/src/test/main.cc b/libs/libmdbx/src/test/main.cc index 7493ab75c3..3384311b3b 100644 --- a/libs/libmdbx/src/test/main.cc +++ b/libs/libmdbx/src/test/main.cc @@ -154,8 +154,14 @@ int main(int argc, char *const argv[]) {                               config::mode_bits))        continue;      if (config::parse_option(argc, argv, narg, "table", params.table_flags, -                             config::table_bits)) +                             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,                               mdbx_limits_pgsize_min(), diff --git a/libs/libmdbx/src/test/osal-unix.cc b/libs/libmdbx/src/test/osal-unix.cc index 8132e267ef..6661ae42c8 100644 --- a/libs/libmdbx/src/test/osal-unix.cc +++ b/libs/libmdbx/src/test/osal-unix.cc @@ -182,6 +182,9 @@ void osal_killall_actors(void) {  }  int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) { +  struct timespec ts; +  ts.tv_nsec = 0; +  ts.tv_sec = timeout;  retry:    int status, options = WNOHANG;  #ifdef WUNTRACED @@ -209,9 +212,16 @@ retry:    }    if (pid == 0) { -    if (timeout && sleep(timeout)) +    /* child still running */ +    if (ts.tv_sec == 0 && ts.tv_nsec == 0) +      ts.tv_nsec = 1; +    if (nanosleep(&ts, &ts) == 0) { +      /* timeout and no signal fomr child */ +      pid = 0; +      return 0; +    } +    if (errno == EINTR)        goto retry; -    return 0;    }    switch (errno) { diff --git a/libs/libmdbx/src/test/test.cc b/libs/libmdbx/src/test/test.cc index c28bbd221e..b9663c2a09 100644 --- a/libs/libmdbx/src/test/test.cc +++ b/libs/libmdbx/src/test/test.cc @@ -410,6 +410,16 @@ void testcase::db_table_close(MDBX_dbi handle) {    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_get2(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) { diff --git a/libs/libmdbx/src/test/test.h b/libs/libmdbx/src/test/test.h index ef1c4caa47..4b10a40fef 100644 --- a/libs/libmdbx/src/test/test.h +++ b/libs/libmdbx/src/test/test.h @@ -112,6 +112,8 @@ protected:    void fetch_canary();    void update_canary(uint64_t increment);    void kick_progress(bool active) const; +  void checkdata(const char *step, MDBX_dbi handle, MDBX_val key2check, +                 MDBX_val expected_valued);    MDBX_dbi db_table_open(bool create);    void db_table_drop(MDBX_dbi handle); diff --git a/libs/libmdbx/src/test/utils.cc b/libs/libmdbx/src/test/utils.cc index 53a750e314..5a5290f057 100644 --- a/libs/libmdbx/src/test/utils.cc +++ b/libs/libmdbx/src/test/utils.cc @@ -91,6 +91,11 @@ bool hex2data(const char *hex_begin, const char *hex_end, void *ptr,    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. */ diff --git a/libs/libmdbx/src/test/utils.h b/libs/libmdbx/src/test/utils.h index 5d62909fd5..42d497e86e 100644 --- a/libs/libmdbx/src/test/utils.h +++ b/libs/libmdbx/src/test/utils.h @@ -317,7 +317,7 @@ struct simple_checksum {  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);  | 
