mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-21 18:58:21 +08:00
mdbx: merge branch master
into stable
.
This commit is contained in:
commit
93429d3a23
@ -512,23 +512,25 @@ else()
|
|||||||
mark_as_advanced(MDBX_USE_OFDLOCKS)
|
mark_as_advanced(MDBX_USE_OFDLOCKS)
|
||||||
set(MDBX_AVOID_MSYNC_DEFAULT OFF)
|
set(MDBX_AVOID_MSYNC_DEFAULT OFF)
|
||||||
endif()
|
endif()
|
||||||
option(MDBX_AVOID_MSYNC "Controls dirty pages tracking, spilling and persisting in MDBX_WRITEMAP mode" ${MDBX_AVOID_MSYNC_DEFAULT})
|
add_mdbx_option(MDBX_AVOID_MSYNC "Controls dirty pages tracking, spilling and persisting in MDBX_WRITEMAP mode" ${MDBX_AVOID_MSYNC_DEFAULT})
|
||||||
add_mdbx_option(MDBX_LOCKING "Locking method (Windows=-1, SysV=5, POSIX=1988, POSIX=2001, POSIX=2008, Futexes=1995)" AUTO)
|
add_mdbx_option(MDBX_LOCKING "Locking method (Windows=-1, SysV=5, POSIX=1988, POSIX=2001, POSIX=2008, Futexes=1995)" AUTO)
|
||||||
mark_as_advanced(MDBX_LOCKING)
|
mark_as_advanced(MDBX_LOCKING)
|
||||||
add_mdbx_option(MDBX_TRUST_RTC "Does a system have battery-backed Real-Time Clock or just a fake" AUTO)
|
add_mdbx_option(MDBX_TRUST_RTC "Does a system have battery-backed Real-Time Clock or just a fake" AUTO)
|
||||||
mark_as_advanced(MDBX_TRUST_RTC)
|
mark_as_advanced(MDBX_TRUST_RTC)
|
||||||
option(MDBX_FORCE_ASSERTIONS "Force enable assertion checking" OFF)
|
add_mdbx_option(MDBX_FORCE_ASSERTIONS "Force enable assertion checking" OFF)
|
||||||
option(MDBX_DISABLE_VALIDATION "Disable some checks to reduce an overhead and detection probability of database corruption to a values closer to the LMDB" OFF)
|
add_mdbx_option(MDBX_DISABLE_VALIDATION "Disable some checks to reduce an overhead and detection probability of database corruption to a values closer to the LMDB" OFF)
|
||||||
option(MDBX_ENABLE_REFUND "Zerocost auto-compactification during write-transactions" ON)
|
mark_as_advanced(MDBX_DISABLE_VALIDATION)
|
||||||
option(MDBX_ENABLE_MADVISE "Using POSIX' madvise() and/or similar hints" ON)
|
add_mdbx_option(MDBX_ENABLE_REFUND "Zerocost auto-compactification during write-transactions" ON)
|
||||||
|
add_mdbx_option(MDBX_ENABLE_MADVISE "Using POSIX' madvise() and/or similar hints" ON)
|
||||||
if (CMAKE_TARGET_BITNESS GREATER 32)
|
if (CMAKE_TARGET_BITNESS GREATER 32)
|
||||||
set(MDBX_BIGFOOT_DEFAULT ON)
|
set(MDBX_BIGFOOT_DEFAULT ON)
|
||||||
else()
|
else()
|
||||||
set(MDBX_BIGFOOT_DEFAULT OFF)
|
set(MDBX_BIGFOOT_DEFAULT OFF)
|
||||||
endif()
|
endif()
|
||||||
option(MDBX_ENABLE_BIGFOOT "Chunking long list of retired pages during huge transactions commit to avoid use sequences of pages" ${MDBX_BIGFOOT_DEFAULT})
|
add_mdbx_option(MDBX_ENABLE_BIGFOOT "Chunking long list of retired pages during huge transactions commit to avoid use sequences of pages" ${MDBX_BIGFOOT_DEFAULT})
|
||||||
option(MDBX_ENABLE_PGOP_STAT "Gathering statistics for page operations" ON)
|
add_mdbx_option(MDBX_ENABLE_PGOP_STAT "Gathering statistics for page operations" ON)
|
||||||
option(MDBX_ENABLE_PROFGC "Profiling of GC search and updates" OFF)
|
add_mdbx_option(MDBX_ENABLE_PROFGC "Profiling of GC search and updates" OFF)
|
||||||
|
mark_as_advanced(MDBX_ENABLE_PROFGC)
|
||||||
|
|
||||||
if(NOT MDBX_AMALGAMATED_SOURCE)
|
if(NOT MDBX_AMALGAMATED_SOURCE)
|
||||||
if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG")
|
if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG")
|
||||||
|
81
ChangeLog.md
81
ChangeLog.md
@ -1,10 +1,87 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
---------
|
=========
|
||||||
|
|
||||||
English version [by Google](https://gitflic-ru.translate.goog/project/erthink/libmdbx/blob?file=ChangeLog.md&_x_tr_sl=ru&_x_tr_tl=en)
|
English version [by Google](https://gitflic-ru.translate.goog/project/erthink/libmdbx/blob?file=ChangeLog.md&_x_tr_sl=ru&_x_tr_tl=en)
|
||||||
and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md).
|
and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md).
|
||||||
|
|
||||||
|
|
||||||
|
## v0.12.8 (сопровождение и подготовка к релизу)
|
||||||
|
|
||||||
|
Поддержка стабильной ветки.
|
||||||
|
|
||||||
|
Мелочи:
|
||||||
|
|
||||||
|
- Удаление устаревших `mdbx_set_compare()` и `mdbx_set_dupsort()`.
|
||||||
|
- Корректировка определения `MDBX_LAST_ADDED_ERRCODE`.
|
||||||
|
- Добавление в C++ API забытого исключения `mdbx::duplicated_lck_file`.
|
||||||
|
- Обновление патча для старых версий buildroot.
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
## v0.12.8 "Владимир Уткин" от 2023-10-17
|
||||||
|
|
||||||
|
Стабилизирующий выпуск с исправлением обнаруженных ошибок и устранением недочетов,
|
||||||
|
в день 100-летия со дня рождения выдающегося советского и российского ученого и конструктора [Влади́мира Фёдоровича У́ткина](https://ru.wikipedia.org/wiki/Уткин,_Владимир_Фёдорович).
|
||||||
|
|
||||||
|
```
|
||||||
|
git diff' stat: 24 commits, 18 files changed, 624 insertions(+), 94 deletions(-)
|
||||||
|
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||||
|
```
|
||||||
|
|
||||||
|
Благодарности:
|
||||||
|
|
||||||
|
- [Alain Picard](https://github.com/castortech) за сообщение о проблеме
|
||||||
|
с обработкой `MDBX_MULTIPLE` и помощь в тестировании.
|
||||||
|
|
||||||
|
Исправления и доработки:
|
||||||
|
|
||||||
|
- Устранение регресса/ошибки в пути обработки `put(MDBX_MULTIPLE)` при пакетном/оптовом
|
||||||
|
помещении в БД множественных значений одного ключа (aka multi-value или dupsort).
|
||||||
|
Проявление проблемы зависит от компилятора и опций оптимизации/кодогенерации, но с большой вероятностью возвращется
|
||||||
|
ошибка `MDBX_BAD_VALSIZE` (`-30781`), а в отладочных сборках срабатывает проверка `cASSERT(mc, !"Invalid key-size")`.
|
||||||
|
Сценарии приводящие к другим проявлениям на данный момент не известны.
|
||||||
|
|
||||||
|
- Реализована перезапись в `mdbx_put(MDBX_CURRENT)` всех текущих мульти-значений ключа
|
||||||
|
при отсутствии флага `MDBX_NOOVERWRITE`. Ранее в такой ситуации возвращалась ошибка `MDBX_EMULTIVAL`.
|
||||||
|
В текущем понимании новое поведение более удобно и не создаёт проблем совместимости с ранее написанным кодом.
|
||||||
|
|
||||||
|
- Добавлена возможность использовать `mdbx_cursor_get(MDBX_GET_MULTIPLE)` без предварительной установки
|
||||||
|
курсора, совмещая операцию пакетного получения данных с позиционированием курсора на передаваемый ключ.
|
||||||
|
|
||||||
|
- Микрооптимизация и рефакторинг `cursor_put_nochecklen()` в продолжение исправления
|
||||||
|
регресса/ошибки в пути обработки `put(MDBX_MULTIPLE)`.
|
||||||
|
|
||||||
|
- Уточнение формулировок в описании API, в том числе пояснений о `SIGSEGV`
|
||||||
|
и недопустимости прямого изменения данных.
|
||||||
|
|
||||||
|
Мелочи:
|
||||||
|
|
||||||
|
- Исправление несущественных предупреждений при `MDBX_ENABLE_PROFGC=ON`.
|
||||||
|
- Добавление `slice::as_pod<typename>()` в C++ API.
|
||||||
|
- Добавление перегрузки `txn::put_multiple()` и контроля POD в C++ API.
|
||||||
|
- Добавление smoke-теста для `put(MDBX_MULTIPLE)`.
|
||||||
|
- Добавление дополнительных smoke-тестов в область видимости ctest.
|
||||||
|
- Устранение жалоб Valgrind на инвариантное чтение неинициализированной памяти
|
||||||
|
и утечки памяти в одном из тестов.
|
||||||
|
- Костыль для глушения/игнорирования `EDEADLK` в ряде сценариев при
|
||||||
|
использовании Valgrind или ASAN. В частности, это устраняет
|
||||||
|
ложно-негативный результат проверки БД посредством `mdbx_chk -wc`,
|
||||||
|
т.е. проверку БД в кооперативном (не эксклюзивном) режиме чтения-записи
|
||||||
|
в сборках с поддержкой Valgrind или включеным ASAN. Для более подробной
|
||||||
|
информации см. [соответствующий коммит](https://gitflic.ru/project/erthink/libmdbx/commit/1aead6869a7eff1a85e400ab3eeecb4c8b904fe6).
|
||||||
|
- Доработка `mdbx_dump_val()` используемой для логирования и отладки.
|
||||||
|
- Устранение предупреждений Valgrind при логировании в отладочных сборках.
|
||||||
|
- Доработка использования `filesystem` для старых компиляторов.
|
||||||
|
- Сокращение излишнего вызова `osal_thread_self()`.
|
||||||
|
- Вывод информации о большинстве mdbx-опций при сборке посредством CMake.
|
||||||
|
- Добавление определений макросов для Doxygen.
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
## v0.12.7 "Артек" от 2023-06-16
|
## v0.12.7 "Артек" от 2023-06-16
|
||||||
|
|
||||||
Стабилизирующий выпуск с исправлением обнаруженных ошибок и устранением
|
Стабилизирующий выпуск с исправлением обнаруженных ошибок и устранением
|
||||||
@ -317,7 +394,7 @@ Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
|||||||
|
|
||||||
- Добавлен явный выбор `tls_model("local-dynamic")` для обхода проблемы
|
- Добавлен явный выбор `tls_model("local-dynamic")` для обхода проблемы
|
||||||
`relocation R_X86_64_TPOFF32 against FOO cannot be used with -shared`
|
`relocation R_X86_64_TPOFF32 against FOO cannot be used with -shared`
|
||||||
из-за ошибки в CLANG приводящей к использованию неверного режима `ls_model`.
|
из-за ошибки в CLANG приводящей к использованию неверного режима `tls_model`.
|
||||||
|
|
||||||
- Изменение тактики слияния страниц при удалении.
|
- Изменение тактики слияния страниц при удалении.
|
||||||
Теперь слияние выполняется преимущественно с уже измененной/грязной страницей.
|
Теперь слияние выполняется преимущественно с уже измененной/грязной страницей.
|
||||||
|
@ -2224,14 +2224,24 @@ INCLUDE_FILE_PATTERNS =
|
|||||||
# recursively expanded use the := operator instead of the = operator.
|
# recursively expanded use the := operator instead of the = operator.
|
||||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||||
|
|
||||||
PREDEFINED = DOXYGEN MDBX_DECLARE_EXCEPTION \
|
|
||||||
MDBX_NOTHROW_PURE_FUNCTION MDBX_PURE_FUNCTION \
|
PREDEFINED = DOXYGEN \
|
||||||
MDBX_NOTHROW_CONST_FUNCTION \
|
MDBX_CXX20_CONCEPT(CONCEPT,NAME)="CONCEPT NAME" \
|
||||||
MDBX_CXX01_CONSTEXPR MDBX_CXX01_CONSTEXPR_VAR \
|
MDBX_STD_FILESYSTEM_PATH=::mdbx::filesystem::path \
|
||||||
MDBX_CXX11_CONSTEXPR MDBX_CXX11_CONSTEXPR_VAR \
|
MDBX_U128_TYPE=uint128_t MDBX_I128_TYPE=int128_t \
|
||||||
MDBX_CXX14_CONSTEXPR MDBX_CXX14_CONSTEXPR_VAR \
|
MDBX_DECLARE_EXCEPTION(NAME)="struct LIBMDBX_API_TYPE NAME : public exception{NAME(const ::mdbx::error &); virtual ~NAME() noexcept; }" \
|
||||||
MDBX_CXX17_CONSTEXPR MDBX_CXX20_CONSTEXPR \
|
MDBX_PURE_FUNCTION=[[gnu::pure]] \
|
||||||
MDBX_CXX17_NOEXCEPT
|
MDBX_NOTHROW_PURE_FUNCTION="[[gnu::pure, gnu::nothrow]]" \
|
||||||
|
MDBX_CONST_FUNCTION=[[gnu::const]] \
|
||||||
|
MDBX_NOTHROW_CONST_FUNCTION="[[gnu::const, gnu::nothrow]]" \
|
||||||
|
MDBX_CXX01_CONSTEXPR=constexpr MDBX_CXX01_CONSTEXPR_VAR=constexpr \
|
||||||
|
MDBX_CXX11_CONSTEXPR=constexpr MDBX_CXX11_CONSTEXPR_VAR=constexpr \
|
||||||
|
MDBX_CXX14_CONSTEXPR=constexpr MDBX_CXX14_CONSTEXPR_VAR=constexpr \
|
||||||
|
MDBX_CXX17_CONSTEXPR=constexpr MDBX_CXX20_CONSTEXPR=constexpr \
|
||||||
|
MDBX_CXX17_NOEXCEPT=noexcept MDBX_IF_CONSTEXPR=constexpr \
|
||||||
|
MDBX_CXX20_LIKELY=[[likely]] MDBX_CXX20_UNLIKELY=[[unlikely]] \
|
||||||
|
MDBX_MAYBE_UNUSED=[[maybe_unused]] \
|
||||||
|
MDBX_DEPRECATED=[[deprecated]]
|
||||||
|
|
||||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||||
# tag can be used to specify a list of macro names that should be expanded. The
|
# tag can be used to specify a list of macro names that should be expanded. The
|
||||||
|
88
mdbx.h
88
mdbx.h
@ -1876,7 +1876,8 @@ enum MDBX_error_t {
|
|||||||
MDBX_BAD_RSLOT = -30783,
|
MDBX_BAD_RSLOT = -30783,
|
||||||
|
|
||||||
/** Transaction is not valid for requested operation,
|
/** Transaction is not valid for requested operation,
|
||||||
* e.g. had errored and be must aborted, has a child, or is invalid */
|
* e.g. had errored and be must aborted, has a child/nested transaction,
|
||||||
|
* or is invalid */
|
||||||
MDBX_BAD_TXN = -30782,
|
MDBX_BAD_TXN = -30782,
|
||||||
|
|
||||||
/** Invalid size or alignment of key or data for target database,
|
/** Invalid size or alignment of key or data for target database,
|
||||||
@ -1936,7 +1937,7 @@ enum MDBX_error_t {
|
|||||||
MDBX_DUPLICATED_CLK = -30413,
|
MDBX_DUPLICATED_CLK = -30413,
|
||||||
|
|
||||||
/* The last of MDBX-added error codes */
|
/* The last of MDBX-added error codes */
|
||||||
MDBX_LAST_ADDED_ERRCODE = MDBX_TXN_OVERLAPPING,
|
MDBX_LAST_ADDED_ERRCODE = MDBX_DUPLICATED_CLK,
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
MDBX_ENODATA = ERROR_HANDLE_EOF,
|
MDBX_ENODATA = ERROR_HANDLE_EOF,
|
||||||
@ -2699,11 +2700,12 @@ MDBX_DEPRECATED LIBMDBX_INLINE_API(int, mdbx_env_info,
|
|||||||
* success. The \ref MDBX_RESULT_TRUE means no data pending for flush
|
* success. The \ref MDBX_RESULT_TRUE means no data pending for flush
|
||||||
* to disk, and 0 otherwise. Some possible errors are:
|
* to disk, and 0 otherwise. Some possible errors are:
|
||||||
*
|
*
|
||||||
* \retval MDBX_EACCES the environment is read-only.
|
* \retval MDBX_EACCES The environment is read-only.
|
||||||
* \retval MDBX_BUSY the environment is used by other thread
|
* \retval MDBX_BUSY The environment is used by other thread
|
||||||
* and `nonblock=true`.
|
* and `nonblock=true`.
|
||||||
* \retval MDBX_EINVAL an invalid parameter was specified.
|
* \retval MDBX_EINVAL An invalid parameter was specified.
|
||||||
* \retval MDBX_EIO an error occurred during synchronization. */
|
* \retval MDBX_EIO An error occurred during the flushing/writing data
|
||||||
|
* to a storage medium/disk. */
|
||||||
LIBMDBX_API int mdbx_env_sync_ex(MDBX_env *env, bool force, bool nonblock);
|
LIBMDBX_API int mdbx_env_sync_ex(MDBX_env *env, bool force, bool nonblock);
|
||||||
|
|
||||||
/** \brief The shortcut to calling \ref mdbx_env_sync_ex() with
|
/** \brief The shortcut to calling \ref mdbx_env_sync_ex() with
|
||||||
@ -2846,9 +2848,9 @@ LIBMDBX_INLINE_API(int, mdbx_env_get_syncperiod,
|
|||||||
*
|
*
|
||||||
* Only a single thread may call this function. All transactions, databases,
|
* Only a single thread may call this function. All transactions, databases,
|
||||||
* and cursors must already be closed before calling this function. Attempts
|
* and cursors must already be closed before calling this function. Attempts
|
||||||
* to use any such handles after calling this function will cause a `SIGSEGV`.
|
* to use any such handles after calling this function is UB and would cause
|
||||||
* The environment handle will be freed and must not be used again after this
|
* a `SIGSEGV`. The environment handle will be freed and must not be used again
|
||||||
* call.
|
* after this call.
|
||||||
*
|
*
|
||||||
* \param [in] env An environment handle returned by
|
* \param [in] env An environment handle returned by
|
||||||
* \ref mdbx_env_create().
|
* \ref mdbx_env_create().
|
||||||
@ -2878,7 +2880,8 @@ LIBMDBX_INLINE_API(int, mdbx_env_get_syncperiod,
|
|||||||
* is expected, i.e. \ref MDBX_env instance was freed in
|
* is expected, i.e. \ref MDBX_env instance was freed in
|
||||||
* proper manner.
|
* proper manner.
|
||||||
*
|
*
|
||||||
* \retval MDBX_EIO An error occurred during synchronization. */
|
* \retval MDBX_EIO An error occurred during the flushing/writing data
|
||||||
|
* to a storage medium/disk. */
|
||||||
LIBMDBX_API int mdbx_env_close_ex(MDBX_env *env, bool dont_sync);
|
LIBMDBX_API int mdbx_env_close_ex(MDBX_env *env, bool dont_sync);
|
||||||
|
|
||||||
/** \brief The shortcut to calling \ref mdbx_env_close_ex() with
|
/** \brief The shortcut to calling \ref mdbx_env_close_ex() with
|
||||||
@ -3918,7 +3921,8 @@ LIBMDBX_API int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency);
|
|||||||
* by current thread.
|
* by current thread.
|
||||||
* \retval MDBX_EINVAL Transaction handle is NULL.
|
* \retval MDBX_EINVAL Transaction handle is NULL.
|
||||||
* \retval MDBX_ENOSPC No more disk space.
|
* \retval MDBX_ENOSPC No more disk space.
|
||||||
* \retval MDBX_EIO A system-level I/O error occurred.
|
* \retval MDBX_EIO An error occurred during the flushing/writing
|
||||||
|
* data to a storage medium/disk.
|
||||||
* \retval MDBX_ENOMEM Out of memory. */
|
* \retval MDBX_ENOMEM Out of memory. */
|
||||||
LIBMDBX_INLINE_API(int, mdbx_txn_commit, (MDBX_txn * txn)) {
|
LIBMDBX_INLINE_API(int, mdbx_txn_commit, (MDBX_txn * txn)) {
|
||||||
return mdbx_txn_commit_ex(txn, NULL);
|
return mdbx_txn_commit_ex(txn, NULL);
|
||||||
@ -4084,9 +4088,9 @@ LIBMDBX_API int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary);
|
|||||||
* \see mdbx_get_datacmp \see mdbx_dcmp()
|
* \see mdbx_get_datacmp \see mdbx_dcmp()
|
||||||
*
|
*
|
||||||
* \anchor avoid_custom_comparators
|
* \anchor avoid_custom_comparators
|
||||||
* It is recommend not using custom comparison functions, but instead
|
* \deprecated It is recommend not using custom comparison functions, but
|
||||||
* converting the keys to one of the forms that are suitable for built-in
|
* instead converting the keys to one of the forms that are suitable for
|
||||||
* comparators (for instance take look to the \ref value2key).
|
* built-in comparators (for instance take look to the \ref value2key).
|
||||||
* The reasons to not using custom comparators are:
|
* The reasons to not using custom comparators are:
|
||||||
* - The order of records could not be validated without your code.
|
* - The order of records could not be validated without your code.
|
||||||
* So `mdbx_chk` utility will reports "wrong order" errors
|
* So `mdbx_chk` utility will reports "wrong order" errors
|
||||||
@ -4316,7 +4320,7 @@ LIBMDBX_API int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi,
|
|||||||
enum MDBX_dbi_state_t {
|
enum MDBX_dbi_state_t {
|
||||||
/** DB was written in this txn */
|
/** DB was written in this txn */
|
||||||
MDBX_DBI_DIRTY = 0x01,
|
MDBX_DBI_DIRTY = 0x01,
|
||||||
/** Named-DB record is older than txnID */
|
/** Cached Named-DB record is older than txnID */
|
||||||
MDBX_DBI_STALE = 0x02,
|
MDBX_DBI_STALE = 0x02,
|
||||||
/** Named-DB handle opened in this txn */
|
/** Named-DB handle opened in this txn */
|
||||||
MDBX_DBI_FRESH = 0x04,
|
MDBX_DBI_FRESH = 0x04,
|
||||||
@ -4398,9 +4402,14 @@ LIBMDBX_API int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, bool del);
|
|||||||
* items requires the use of \ref mdbx_cursor_get().
|
* items requires the use of \ref mdbx_cursor_get().
|
||||||
*
|
*
|
||||||
* \note The memory pointed to by the returned values is owned by the
|
* \note The memory pointed to by the returned values is owned by the
|
||||||
* database. The caller need not dispose of the memory, and may not
|
* database. The caller MUST not dispose of the memory, and MUST not modify it
|
||||||
* modify it in any way. For values returned in a read-only transaction
|
* in any way regardless in a read-only nor read-write transactions!
|
||||||
* any modification attempts will cause a `SIGSEGV`.
|
* For case a database opened without the \ref MDBX_WRITEMAP modification
|
||||||
|
* attempts likely will cause a `SIGSEGV`. However, when a database opened with
|
||||||
|
* the \ref MDBX_WRITEMAP or in case values returned inside read-write
|
||||||
|
* transaction are located on a "dirty" (modified and pending to commit) pages,
|
||||||
|
* such modification will silently accepted and likely will lead to DB and/or
|
||||||
|
* data corruption.
|
||||||
*
|
*
|
||||||
* \note Values returned from the database are valid only until a
|
* \note Values returned from the database are valid only until a
|
||||||
* subsequent update operation, or the end of the transaction.
|
* subsequent update operation, or the end of the transaction.
|
||||||
@ -4650,7 +4659,7 @@ LIBMDBX_API int mdbx_replace_ex(MDBX_txn *txn, MDBX_dbi dbi,
|
|||||||
LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
||||||
const MDBX_val *data);
|
const MDBX_val *data);
|
||||||
|
|
||||||
/** \brief Create a cursor handle but not bind it to transaction nor DBI handle.
|
/** \brief Create a cursor handle but not bind it to transaction nor DBI-handle.
|
||||||
* \ingroup c_cursors
|
* \ingroup c_cursors
|
||||||
*
|
*
|
||||||
* A cursor cannot be used when its database handle is closed. Nor when its
|
* A cursor cannot be used when its database handle is closed. Nor when its
|
||||||
@ -4674,7 +4683,7 @@ LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
|||||||
* \returns Created cursor handle or NULL in case out of memory. */
|
* \returns Created cursor handle or NULL in case out of memory. */
|
||||||
LIBMDBX_API MDBX_cursor *mdbx_cursor_create(void *context);
|
LIBMDBX_API MDBX_cursor *mdbx_cursor_create(void *context);
|
||||||
|
|
||||||
/** \brief Set application information associated with the \ref MDBX_cursor.
|
/** \brief Set application information associated with the cursor.
|
||||||
* \ingroup c_cursors
|
* \ingroup c_cursors
|
||||||
* \see mdbx_cursor_get_userctx()
|
* \see mdbx_cursor_get_userctx()
|
||||||
*
|
*
|
||||||
@ -4697,11 +4706,11 @@ LIBMDBX_API int mdbx_cursor_set_userctx(MDBX_cursor *cursor, void *ctx);
|
|||||||
MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *
|
MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *
|
||||||
mdbx_cursor_get_userctx(const MDBX_cursor *cursor);
|
mdbx_cursor_get_userctx(const MDBX_cursor *cursor);
|
||||||
|
|
||||||
/** \brief Bind cursor to specified transaction and DBI handle.
|
/** \brief Bind cursor to specified transaction and DBI-handle.
|
||||||
* \ingroup c_cursors
|
* \ingroup c_cursors
|
||||||
*
|
*
|
||||||
* Using of the `mdbx_cursor_bind()` is equivalent to calling
|
* Using of the `mdbx_cursor_bind()` is equivalent to calling
|
||||||
* \ref mdbx_cursor_renew() but with specifying an arbitrary dbi handle.
|
* \ref mdbx_cursor_renew() but with specifying an arbitrary DBI-handle.
|
||||||
*
|
*
|
||||||
* A cursor may be associated with a new transaction, and referencing a new or
|
* A cursor may be associated with a new transaction, and referencing a new or
|
||||||
* the same database handle as it was created with. This may be done whether the
|
* the same database handle as it was created with. This may be done whether the
|
||||||
@ -4715,7 +4724,7 @@ mdbx_cursor_get_userctx(const MDBX_cursor *cursor);
|
|||||||
*
|
*
|
||||||
* \param [in] txn A transaction handle returned by \ref mdbx_txn_begin().
|
* \param [in] txn A transaction handle returned by \ref mdbx_txn_begin().
|
||||||
* \param [in] dbi A database handle returned by \ref mdbx_dbi_open().
|
* \param [in] dbi A database handle returned by \ref mdbx_dbi_open().
|
||||||
* \param [out] cursor A cursor handle returned by \ref mdbx_cursor_create().
|
* \param [in] cursor A cursor handle returned by \ref mdbx_cursor_create().
|
||||||
*
|
*
|
||||||
* \returns A non-zero error value on failure and 0 on success,
|
* \returns A non-zero error value on failure and 0 on success,
|
||||||
* some possible errors are:
|
* some possible errors are:
|
||||||
@ -4774,15 +4783,14 @@ LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi,
|
|||||||
* or \ref mdbx_cursor_create(). */
|
* or \ref mdbx_cursor_create(). */
|
||||||
LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor);
|
LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor);
|
||||||
|
|
||||||
/** \brief Renew a cursor handle.
|
/** \brief Renew a cursor handle for use within the given transaction.
|
||||||
* \ingroup c_cursors
|
* \ingroup c_cursors
|
||||||
*
|
*
|
||||||
* The cursor may be associated with a new transaction, and referencing a new or
|
* A cursor may be associated with a new transaction whether the previous
|
||||||
* the same database handle as it was created with. This may be done whether the
|
* transaction is running or finished.
|
||||||
* previous transaction is live or dead.
|
|
||||||
*
|
*
|
||||||
* Using of the `mdbx_cursor_renew()` is equivalent to calling
|
* Using of the `mdbx_cursor_renew()` is equivalent to calling
|
||||||
* \ref mdbx_cursor_bind() with the DBI handle that previously
|
* \ref mdbx_cursor_bind() with the DBI-handle that previously
|
||||||
* the cursor was used with.
|
* the cursor was used with.
|
||||||
*
|
*
|
||||||
* \note In contrast to LMDB, the MDBX allow any cursor to be re-used by using
|
* \note In contrast to LMDB, the MDBX allow any cursor to be re-used by using
|
||||||
@ -4796,7 +4804,9 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor);
|
|||||||
* some possible errors are:
|
* some possible errors are:
|
||||||
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned
|
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned
|
||||||
* by current thread.
|
* by current thread.
|
||||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
* \retval MDBX_EINVAL An invalid parameter was specified.
|
||||||
|
* \retval MDBX_BAD_DBI The cursor was not bound to a DBI-handle
|
||||||
|
* or such a handle became invalid. */
|
||||||
LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor);
|
LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor);
|
||||||
|
|
||||||
/** \brief Return the cursor's transaction handle.
|
/** \brief Return the cursor's transaction handle.
|
||||||
@ -4834,6 +4844,16 @@ LIBMDBX_API int mdbx_cursor_copy(const MDBX_cursor *src, MDBX_cursor *dest);
|
|||||||
* to which data refers.
|
* to which data refers.
|
||||||
* \see mdbx_get()
|
* \see mdbx_get()
|
||||||
*
|
*
|
||||||
|
* \note The memory pointed to by the returned values is owned by the
|
||||||
|
* database. The caller MUST not dispose of the memory, and MUST not modify it
|
||||||
|
* in any way regardless in a read-only nor read-write transactions!
|
||||||
|
* For case a database opened without the \ref MDBX_WRITEMAP modification
|
||||||
|
* attempts likely will cause a `SIGSEGV`. However, when a database opened with
|
||||||
|
* the \ref MDBX_WRITEMAP or in case values returned inside read-write
|
||||||
|
* transaction are located on a "dirty" (modified and pending to commit) pages,
|
||||||
|
* such modification will silently accepted and likely will lead to DB and/or
|
||||||
|
* data corruption.
|
||||||
|
*
|
||||||
* \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open().
|
* \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open().
|
||||||
* \param [in,out] key The key for a retrieved item.
|
* \param [in,out] key The key for a retrieved item.
|
||||||
* \param [in,out] data The data of a retrieved item.
|
* \param [in,out] data The data of a retrieved item.
|
||||||
@ -4860,6 +4880,16 @@ LIBMDBX_API int mdbx_cursor_get(MDBX_cursor *cursor, MDBX_val *key,
|
|||||||
* array to which `pairs` refers.
|
* array to which `pairs` refers.
|
||||||
* \see mdbx_cursor_get()
|
* \see mdbx_cursor_get()
|
||||||
*
|
*
|
||||||
|
* \note The memory pointed to by the returned values is owned by the
|
||||||
|
* database. The caller MUST not dispose of the memory, and MUST not modify it
|
||||||
|
* in any way regardless in a read-only nor read-write transactions!
|
||||||
|
* For case a database opened without the \ref MDBX_WRITEMAP modification
|
||||||
|
* attempts likely will cause a `SIGSEGV`. However, when a database opened with
|
||||||
|
* the \ref MDBX_WRITEMAP or in case values returned inside read-write
|
||||||
|
* transaction are located on a "dirty" (modified and pending to commit) pages,
|
||||||
|
* such modification will silently accepted and likely will lead to DB and/or
|
||||||
|
* data corruption.
|
||||||
|
*
|
||||||
* \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open().
|
* \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open().
|
||||||
* \param [out] count The number of key and value item returned, on success
|
* \param [out] count The number of key and value item returned, on success
|
||||||
* it always be the even because the key-value
|
* it always be the even because the key-value
|
||||||
|
63
mdbx.h++
63
mdbx.h++
@ -80,7 +80,8 @@
|
|||||||
|
|
||||||
#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L
|
#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#elif __has_include(<experimental/filesystem>)
|
#elif defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L && \
|
||||||
|
__has_include(<experimental/filesystem>)
|
||||||
#include <experimental/filesystem>
|
#include <experimental/filesystem>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -368,6 +369,7 @@ using string = ::std::basic_string<char, ::std::char_traits<char>, ALLOCATOR>;
|
|||||||
using filehandle = ::mdbx_filehandle_t;
|
using filehandle = ::mdbx_filehandle_t;
|
||||||
#if defined(DOXYGEN) || \
|
#if defined(DOXYGEN) || \
|
||||||
(defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \
|
(defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \
|
||||||
|
defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L && \
|
||||||
(!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || \
|
(!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || \
|
||||||
__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) && \
|
__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) && \
|
||||||
(!defined(__IPHONE_OS_VERSION_MIN_REQUIRED) || \
|
(!defined(__IPHONE_OS_VERSION_MIN_REQUIRED) || \
|
||||||
@ -394,6 +396,16 @@ using path = ::std::wstring;
|
|||||||
using path = ::std::string;
|
using path = ::std::string;
|
||||||
#endif /* mdbx::path */
|
#endif /* mdbx::path */
|
||||||
|
|
||||||
|
#if defined(__SIZEOF_INT128__) || \
|
||||||
|
(defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128)
|
||||||
|
#ifndef MDBX_U128_TYPE
|
||||||
|
#define MDBX_U128_TYPE __uint128_t
|
||||||
|
#endif /* MDBX_U128_TYPE */
|
||||||
|
#ifndef MDBX_I128_TYPE
|
||||||
|
#define MDBX_I128_TYPE __int128_t
|
||||||
|
#endif /* MDBX_I128_TYPE */
|
||||||
|
#endif /* __SIZEOF_INT128__ || _INTEGRAL_MAX_BITS >= 128 */
|
||||||
|
|
||||||
#if __cplusplus >= 201103L || defined(DOXYGEN)
|
#if __cplusplus >= 201103L || defined(DOXYGEN)
|
||||||
/// \brief Duration in 1/65536 units of second.
|
/// \brief Duration in 1/65536 units of second.
|
||||||
using duration = ::std::chrono::duration<unsigned, ::std::ratio<1, 65536>>;
|
using duration = ::std::chrono::duration<unsigned, ::std::ratio<1, 65536>>;
|
||||||
@ -546,12 +558,14 @@ MDBX_DECLARE_EXCEPTION(something_busy);
|
|||||||
MDBX_DECLARE_EXCEPTION(thread_mismatch);
|
MDBX_DECLARE_EXCEPTION(thread_mismatch);
|
||||||
MDBX_DECLARE_EXCEPTION(transaction_full);
|
MDBX_DECLARE_EXCEPTION(transaction_full);
|
||||||
MDBX_DECLARE_EXCEPTION(transaction_overlapping);
|
MDBX_DECLARE_EXCEPTION(transaction_overlapping);
|
||||||
|
MDBX_DECLARE_EXCEPTION(duplicated_lck_file);
|
||||||
#undef MDBX_DECLARE_EXCEPTION
|
#undef MDBX_DECLARE_EXCEPTION
|
||||||
|
|
||||||
[[noreturn]] LIBMDBX_API void throw_too_small_target_buffer();
|
[[noreturn]] LIBMDBX_API void throw_too_small_target_buffer();
|
||||||
[[noreturn]] LIBMDBX_API void throw_max_length_exceeded();
|
[[noreturn]] LIBMDBX_API void throw_max_length_exceeded();
|
||||||
[[noreturn]] LIBMDBX_API void throw_out_range();
|
[[noreturn]] LIBMDBX_API void throw_out_range();
|
||||||
[[noreturn]] LIBMDBX_API void throw_allocators_mismatch();
|
[[noreturn]] LIBMDBX_API void throw_allocators_mismatch();
|
||||||
|
[[noreturn]] LIBMDBX_API void throw_bad_value_size();
|
||||||
static MDBX_CXX14_CONSTEXPR size_t check_length(size_t bytes);
|
static MDBX_CXX14_CONSTEXPR size_t check_length(size_t bytes);
|
||||||
static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom,
|
static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom,
|
||||||
size_t payload);
|
size_t payload);
|
||||||
@ -1029,6 +1043,35 @@ struct LIBMDBX_API_TYPE slice : public ::MDBX_val {
|
|||||||
return slice(size_t(-1));
|
return slice(size_t(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename POD> MDBX_CXX14_CONSTEXPR POD as_pod() const {
|
||||||
|
static_assert(::std::is_standard_layout<POD>::value &&
|
||||||
|
!::std::is_pointer<POD>::value,
|
||||||
|
"Must be a standard layout type!");
|
||||||
|
if (MDBX_LIKELY(size() == sizeof(POD)))
|
||||||
|
MDBX_CXX20_LIKELY {
|
||||||
|
POD r;
|
||||||
|
memcpy(&r, data(), sizeof(r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
throw_bad_value_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MDBX_U128_TYPE
|
||||||
|
MDBX_U128_TYPE as_uint128() const;
|
||||||
|
#endif /* MDBX_U128_TYPE */
|
||||||
|
uint64_t as_uint64() const;
|
||||||
|
uint32_t as_uint32() const;
|
||||||
|
uint16_t as_uint16() const;
|
||||||
|
uint8_t as_uint8() const;
|
||||||
|
|
||||||
|
#ifdef MDBX_I128_TYPE
|
||||||
|
MDBX_I128_TYPE as_int128() const;
|
||||||
|
#endif /* MDBX_I128_TYPE */
|
||||||
|
int64_t as_int64() const;
|
||||||
|
int32_t as_int32() const;
|
||||||
|
int16_t as_int16() const;
|
||||||
|
int8_t as_int8() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MDBX_CXX11_CONSTEXPR slice(size_t invalid_length) noexcept
|
MDBX_CXX11_CONSTEXPR slice(size_t invalid_length) noexcept
|
||||||
: ::MDBX_val({nullptr, invalid_length}) {}
|
: ::MDBX_val({nullptr, invalid_length}) {}
|
||||||
@ -2292,6 +2335,10 @@ public:
|
|||||||
return buffer(::mdbx::slice::wrap(pod), make_reference, allocator);
|
return buffer(::mdbx::slice::wrap(pod), make_reference, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename POD> MDBX_CXX14_CONSTEXPR POD as_pod() const {
|
||||||
|
return slice_.as_pod<POD>();
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Reserves storage space.
|
/// \brief Reserves storage space.
|
||||||
void reserve(size_t wanna_headroom, size_t wanna_tailroom) {
|
void reserve(size_t wanna_headroom, size_t wanna_tailroom) {
|
||||||
wanna_headroom = ::std::min(::std::max(headroom(), wanna_headroom),
|
wanna_headroom = ::std::min(::std::max(headroom(), wanna_headroom),
|
||||||
@ -3975,10 +4022,20 @@ public:
|
|||||||
size_t values_count, put_mode mode,
|
size_t values_count, put_mode mode,
|
||||||
bool allow_partial = false);
|
bool allow_partial = false);
|
||||||
template <typename VALUE>
|
template <typename VALUE>
|
||||||
|
size_t put_multiple(map_handle map, const slice &key,
|
||||||
|
const VALUE *values_array, size_t values_count,
|
||||||
|
put_mode mode, bool allow_partial = false) {
|
||||||
|
static_assert(::std::is_standard_layout<VALUE>::value &&
|
||||||
|
!::std::is_pointer<VALUE>::value &&
|
||||||
|
!::std::is_array<VALUE>::value,
|
||||||
|
"Must be a standard layout type!");
|
||||||
|
return put_multiple(map, key, sizeof(VALUE), values_array, values_count,
|
||||||
|
mode, allow_partial);
|
||||||
|
}
|
||||||
|
template <typename VALUE>
|
||||||
void put_multiple(map_handle map, const slice &key,
|
void put_multiple(map_handle map, const slice &key,
|
||||||
const ::std::vector<VALUE> &vector, put_mode mode) {
|
const ::std::vector<VALUE> &vector, put_mode mode) {
|
||||||
put_multiple(map, key, sizeof(VALUE), vector.data(), vector.size(), mode,
|
put_multiple(map, key, vector.data(), vector.size(), mode);
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ptrdiff_t estimate(map_handle map, pair from, pair to) const;
|
inline ptrdiff_t estimate(map_handle map, pair from, pair to) const;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
From 790cbdc02c2597650964a564e05fbb5af503adc9 Mon Sep 17 00:00:00 2001
|
From 3efdf07a80f750c23de126ac80e78fb0545a1b63 Mon Sep 17 00:00:00 2001
|
||||||
From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?=
|
From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?=
|
||||||
=?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= <leo@yuriev.ru>
|
=?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= <leo@yuriev.ru>
|
||||||
Date: Wed, 19 Apr 2023 13:34:37 +0300
|
Date: Mon, 23 Oct 2023 18:07:13 +0300
|
||||||
Subject: [PATCH] package/libmdbx: new package (library/database).
|
Subject: [PATCH] package/libmdbx: new package (library/database).
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
Content-Type: text/plain; charset=UTF-8
|
Content-Type: text/plain; charset=UTF-8
|
||||||
@ -15,8 +15,9 @@ This patch adds libmdbx:
|
|||||||
in terms of reliability, features and performance.
|
in terms of reliability, features and performance.
|
||||||
- https://gitflic.ru/project/erthink/libmdbx
|
- https://gitflic.ru/project/erthink/libmdbx
|
||||||
|
|
||||||
The v0.12.5 "Dynamo" is stable release of frontward _libmdbx_ branch with new superior features
|
The v0.12.8 "Vladimir Utkin" is stable release of frontward _libmdbx_
|
||||||
on the day of 100 anniversary of USSR' «Dynamo» sports and fitness society.
|
branch with new superior features on the day of 100 anniversary of the birth
|
||||||
|
of the outstanding Soviet and Russian scientist and engineer Vladimir Fedorovich Utkin.
|
||||||
|
|
||||||
The complete ChangeLog: https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md
|
The complete ChangeLog: https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md
|
||||||
|
|
||||||
@ -111,18 +112,18 @@ index 0000000000..a9a4ac45c5
|
|||||||
+ !BR2_TOOLCHAIN_GCC_AT_LEAST_4_4
|
+ !BR2_TOOLCHAIN_GCC_AT_LEAST_4_4
|
||||||
diff --git a/package/libmdbx/libmdbx.hash b/package/libmdbx/libmdbx.hash
|
diff --git a/package/libmdbx/libmdbx.hash b/package/libmdbx/libmdbx.hash
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000..7a5b19952e
|
index 0000000000..82cf28d6a9
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/package/libmdbx/libmdbx.hash
|
+++ b/package/libmdbx/libmdbx.hash
|
||||||
@@ -0,0 +1,5 @@
|
@@ -0,0 +1,5 @@
|
||||||
+# Hashes from: https://libmdbx.dqdkfa.ru/release/SHA256SUMS
|
+# Hashes from: https://libmdbx.dqdkfa.ru/release/SHA256SUMS
|
||||||
+sha256 9c3abaaf9079a9518bb7155734817a2e286fffea46f7cc0825dfbd1cf9174075 libmdbx-amalgamated-0.12.5.tar.xz
|
+sha256 c78c56c53708bbfc519bf53ebf520d1f09d30ee6427a4bedf713316696e671d0 libmdbx-amalgamated-0.12.8.tar.xz
|
||||||
+
|
+
|
||||||
+# Locally calculated
|
+# Locally calculated
|
||||||
+sha256 310fe25c858a9515fc8c8d7d1f24a67c9496f84a91e0a0e41ea9975b1371e569 LICENSE
|
+sha256 310fe25c858a9515fc8c8d7d1f24a67c9496f84a91e0a0e41ea9975b1371e569 LICENSE
|
||||||
diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk
|
diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000..9a196eda60
|
index 0000000000..d198fe5b22
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/package/libmdbx/libmdbx.mk
|
+++ b/package/libmdbx/libmdbx.mk
|
||||||
@@ -0,0 +1,42 @@
|
@@ -0,0 +1,42 @@
|
||||||
@ -132,7 +133,7 @@ index 0000000000..9a196eda60
|
|||||||
+#
|
+#
|
||||||
+################################################################################
|
+################################################################################
|
||||||
+
|
+
|
||||||
+LIBMDBX_VERSION = 0.12.5
|
+LIBMDBX_VERSION = 0.12.8
|
||||||
+LIBMDBX_SOURCE = libmdbx-amalgamated-$(LIBMDBX_VERSION).tar.xz
|
+LIBMDBX_SOURCE = libmdbx-amalgamated-$(LIBMDBX_VERSION).tar.xz
|
||||||
+LIBMDBX_SITE = https://libmdbx.dqdkfa.ru/release
|
+LIBMDBX_SITE = https://libmdbx.dqdkfa.ru/release
|
||||||
+LIBMDBX_SUPPORTS_IN_SOURCE_BUILD = NO
|
+LIBMDBX_SUPPORTS_IN_SOURCE_BUILD = NO
|
||||||
@ -169,5 +170,5 @@ index 0000000000..9a196eda60
|
|||||||
+
|
+
|
||||||
+$(eval $(cmake-package))
|
+$(eval $(cmake-package))
|
||||||
--
|
--
|
||||||
2.34.1
|
2.42.0
|
||||||
|
|
||||||
|
135
src/core.c
135
src/core.c
@ -3634,18 +3634,15 @@ const char *mdbx_dump_val(const MDBX_val *key, char *const buf,
|
|||||||
char *const detent = buf + bufsize - 2;
|
char *const detent = buf + bufsize - 2;
|
||||||
char *ptr = buf;
|
char *ptr = buf;
|
||||||
*ptr++ = '<';
|
*ptr++ = '<';
|
||||||
for (size_t i = 0; i < key->iov_len; i++) {
|
for (size_t i = 0; i < key->iov_len && ptr < detent; i++) {
|
||||||
const ptrdiff_t left = detent - ptr;
|
const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
assert(left > 0);
|
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||||
int len = snprintf(ptr, left, "%02x", data[i]);
|
*ptr++ = hex[data[i] >> 4];
|
||||||
if (len < 0 || len >= left)
|
*ptr++ = hex[data[i] & 15];
|
||||||
break;
|
|
||||||
ptr += len;
|
|
||||||
}
|
|
||||||
if (ptr < detent) {
|
|
||||||
ptr[0] = '>';
|
|
||||||
ptr[1] = '\0';
|
|
||||||
}
|
}
|
||||||
|
if (ptr < detent)
|
||||||
|
*ptr++ = '>';
|
||||||
|
*ptr = '\0';
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
@ -7244,7 +7241,7 @@ bailout:
|
|||||||
#if MDBX_ENABLE_PROFGC
|
#if MDBX_ENABLE_PROFGC
|
||||||
size_t majflt_after;
|
size_t majflt_after;
|
||||||
prof->xtime_cpu += osal_cputime(&majflt_after) - cputime_before;
|
prof->xtime_cpu += osal_cputime(&majflt_after) - cputime_before;
|
||||||
prof->majflt += majflt_after - majflt_before;
|
prof->majflt += (uint32_t)(majflt_after - majflt_before);
|
||||||
#endif /* MDBX_ENABLE_PROFGC */
|
#endif /* MDBX_ENABLE_PROFGC */
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -9131,7 +9128,7 @@ static int txn_renew(MDBX_txn *txn, const unsigned flags) {
|
|||||||
}
|
}
|
||||||
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
|
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
|
||||||
txn_valgrind(env, txn);
|
txn_valgrind(env, txn);
|
||||||
#endif
|
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
|
||||||
txn->mt_owner = tid;
|
txn->mt_owner = tid;
|
||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -9199,7 +9196,7 @@ int mdbx_txn_renew(MDBX_txn *txn) {
|
|||||||
|
|
||||||
rc = txn_renew(txn, MDBX_TXN_RDONLY);
|
rc = txn_renew(txn, MDBX_TXN_RDONLY);
|
||||||
if (rc == MDBX_SUCCESS) {
|
if (rc == MDBX_SUCCESS) {
|
||||||
txn->mt_owner = osal_thread_self();
|
tASSERT(txn, txn->mt_owner == osal_thread_self());
|
||||||
DEBUG("renew txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO
|
DEBUG("renew txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO
|
||||||
"/%" PRIaPGNO,
|
"/%" PRIaPGNO,
|
||||||
txn->mt_txnid, (txn->mt_flags & MDBX_TXN_RDONLY) ? 'r' : 'w',
|
txn->mt_txnid, (txn->mt_flags & MDBX_TXN_RDONLY) ? 'r' : 'w',
|
||||||
@ -9813,8 +9810,10 @@ static int txn_end(MDBX_txn *txn, const unsigned mode) {
|
|||||||
txn->mt_txnid == slot->mr_txnid.weak &&
|
txn->mt_txnid == slot->mr_txnid.weak &&
|
||||||
slot->mr_txnid.weak >= env->me_lck->mti_oldest_reader.weak);
|
slot->mr_txnid.weak >= env->me_lck->mti_oldest_reader.weak);
|
||||||
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
|
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
|
||||||
|
atomic_add32(&env->me_ignore_EDEADLK, 1);
|
||||||
txn_valgrind(env, nullptr);
|
txn_valgrind(env, nullptr);
|
||||||
#endif
|
atomic_sub32(&env->me_ignore_EDEADLK, 1);
|
||||||
|
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
|
||||||
atomic_store32(&slot->mr_snapshot_pages_used, 0, mo_Relaxed);
|
atomic_store32(&slot->mr_snapshot_pages_used, 0, mo_Relaxed);
|
||||||
safe64_reset(&slot->mr_txnid, false);
|
safe64_reset(&slot->mr_txnid, false);
|
||||||
atomic_store32(&env->me_lck->mti_readers_refresh_flag, true,
|
atomic_store32(&env->me_lck->mti_readers_refresh_flag, true,
|
||||||
@ -9843,7 +9842,7 @@ static int txn_end(MDBX_txn *txn, const unsigned mode) {
|
|||||||
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
|
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
|
||||||
if (txn == env->me_txn0)
|
if (txn == env->me_txn0)
|
||||||
txn_valgrind(env, nullptr);
|
txn_valgrind(env, nullptr);
|
||||||
#endif
|
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
|
||||||
|
|
||||||
txn->mt_flags = MDBX_TXN_FINISHED;
|
txn->mt_flags = MDBX_TXN_FINISHED;
|
||||||
txn->mt_owner = 0;
|
txn->mt_owner = 0;
|
||||||
@ -10258,6 +10257,14 @@ static int gcu_prepare_backlog(MDBX_txn *txn, gcu_context_t *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static __inline void gcu_clean_reserved(MDBX_env *env, MDBX_val pnl) {
|
static __inline void gcu_clean_reserved(MDBX_env *env, MDBX_val pnl) {
|
||||||
|
#if MDBX_DEBUG && (defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__))
|
||||||
|
/* Для предотвращения предупреждения Valgrind из mdbx_dump_val()
|
||||||
|
* вызванное через макрос DVAL_DEBUG() на выходе
|
||||||
|
* из cursor_set(MDBX_SET_KEY), которая вызывается ниже внутри update_gc() в
|
||||||
|
* цикле очистки и цикле заполнения зарезервированных элементов. */
|
||||||
|
memset(pnl.iov_base, 0xBB, pnl.iov_len);
|
||||||
|
#endif /* MDBX_DEBUG && (MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__) */
|
||||||
|
|
||||||
/* PNL is initially empty, zero out at least the length */
|
/* PNL is initially empty, zero out at least the length */
|
||||||
memset(pnl.iov_base, 0, sizeof(pgno_t));
|
memset(pnl.iov_base, 0, sizeof(pgno_t));
|
||||||
if ((env->me_flags & (MDBX_WRITEMAP | MDBX_NOMEMINIT)) == 0)
|
if ((env->me_flags & (MDBX_WRITEMAP | MDBX_NOMEMINIT)) == 0)
|
||||||
@ -10573,6 +10580,15 @@ retry:
|
|||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
goto bailout;
|
goto bailout;
|
||||||
|
|
||||||
|
#if MDBX_DEBUG && (defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__))
|
||||||
|
/* Для предотвращения предупреждения Valgrind из mdbx_dump_val()
|
||||||
|
* вызванное через макрос DVAL_DEBUG() на выходе
|
||||||
|
* из cursor_set(MDBX_SET_KEY), которая вызывается как выше в цикле
|
||||||
|
* очистки, так и ниже в цикле заполнения зарезервированных элементов.
|
||||||
|
*/
|
||||||
|
memset(data.iov_base, 0xBB, data.iov_len);
|
||||||
|
#endif /* MDBX_DEBUG && (MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__) */
|
||||||
|
|
||||||
if (retired_pages_before == MDBX_PNL_GETSIZE(txn->tw.retired_pages)) {
|
if (retired_pages_before == MDBX_PNL_GETSIZE(txn->tw.retired_pages)) {
|
||||||
const size_t at = (ctx->lifo == MDBX_PNL_ASCENDING)
|
const size_t at = (ctx->lifo == MDBX_PNL_ASCENDING)
|
||||||
? left - chunk
|
? left - chunk
|
||||||
@ -10610,6 +10626,16 @@ retry:
|
|||||||
rc = cursor_put_nochecklen(&ctx->cursor, &key, &data, MDBX_RESERVE);
|
rc = cursor_put_nochecklen(&ctx->cursor, &key, &data, MDBX_RESERVE);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
goto bailout;
|
goto bailout;
|
||||||
|
|
||||||
|
#if MDBX_DEBUG && (defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__))
|
||||||
|
/* Для предотвращения предупреждения Valgrind из mdbx_dump_val()
|
||||||
|
* вызванное через макрос DVAL_DEBUG() на выходе
|
||||||
|
* из cursor_set(MDBX_SET_KEY), которая вызывается как выше в цикле
|
||||||
|
* очистки, так и ниже в цикле заполнения зарезервированных элементов.
|
||||||
|
*/
|
||||||
|
memset(data.iov_base, 0xBB, data.iov_len);
|
||||||
|
#endif /* MDBX_DEBUG && (MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__) */
|
||||||
|
|
||||||
/* Retry if tw.retired_pages[] grew during the Put() */
|
/* Retry if tw.retired_pages[] grew during the Put() */
|
||||||
} while (data.iov_len < MDBX_PNL_SIZEOF(txn->tw.retired_pages));
|
} while (data.iov_len < MDBX_PNL_SIZEOF(txn->tw.retired_pages));
|
||||||
|
|
||||||
@ -11094,7 +11120,7 @@ bailout:
|
|||||||
|
|
||||||
MDBX_PNL_SETSIZE(txn->tw.relist, 0);
|
MDBX_PNL_SETSIZE(txn->tw.relist, 0);
|
||||||
#if MDBX_ENABLE_PROFGC
|
#if MDBX_ENABLE_PROFGC
|
||||||
env->me_lck->mti_pgop_stat.gc_prof.wloops += ctx->loop;
|
env->me_lck->mti_pgop_stat.gc_prof.wloops += (uint32_t)ctx->loop;
|
||||||
#endif /* MDBX_ENABLE_PROFGC */
|
#endif /* MDBX_ENABLE_PROFGC */
|
||||||
TRACE("<<< %zu loops, rc = %d", ctx->loop, rc);
|
TRACE("<<< %zu loops, rc = %d", ctx->loop, rc);
|
||||||
return rc;
|
return rc;
|
||||||
@ -11929,6 +11955,7 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) {
|
|||||||
(size_t)(commit_txnid - txn->mt_txnid));
|
(size_t)(commit_txnid - txn->mt_txnid));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
meta.unsafe_sign = MDBX_DATASIGN_NONE;
|
||||||
meta_set_txnid(env, &meta, commit_txnid);
|
meta_set_txnid(env, &meta, commit_txnid);
|
||||||
|
|
||||||
rc = sync_locked(env, env->me_flags | txn->mt_flags | MDBX_SHRINK_ALLOWED,
|
rc = sync_locked(env, env->me_flags | txn->mt_flags | MDBX_SHRINK_ALLOWED,
|
||||||
@ -15291,7 +15318,7 @@ bailout:
|
|||||||
} else {
|
} else {
|
||||||
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
|
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
|
||||||
txn_valgrind(env, nullptr);
|
txn_valgrind(env, nullptr);
|
||||||
#endif
|
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
|
||||||
}
|
}
|
||||||
osal_free(env_pathname.buffer_for_free);
|
osal_free(env_pathname.buffer_for_free);
|
||||||
return rc;
|
return rc;
|
||||||
@ -16852,11 +16879,13 @@ static __hot int cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MDBX_GET_MULTIPLE:
|
case MDBX_GET_MULTIPLE:
|
||||||
if (unlikely(data == NULL || !(mc->mc_flags & C_INITIALIZED)))
|
if (unlikely(!data))
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
if (unlikely(!(mc->mc_db->md_flags & MDBX_DUPFIXED)))
|
if (unlikely((mc->mc_db->md_flags & MDBX_DUPFIXED) == 0))
|
||||||
return MDBX_INCOMPATIBLE;
|
return MDBX_INCOMPATIBLE;
|
||||||
rc = MDBX_SUCCESS;
|
rc = (mc->mc_flags & C_INITIALIZED)
|
||||||
|
? MDBX_SUCCESS
|
||||||
|
: cursor_set(mc, key, data, MDBX_SET).err;
|
||||||
if ((mc->mc_xcursor->mx_cursor.mc_flags & (C_INITIALIZED | C_EOF)) !=
|
if ((mc->mc_xcursor->mx_cursor.mc_flags & (C_INITIALIZED | C_EOF)) !=
|
||||||
C_INITIALIZED)
|
C_INITIALIZED)
|
||||||
break;
|
break;
|
||||||
@ -17215,9 +17244,6 @@ static __hot int cursor_touch(MDBX_cursor *const mc, const MDBX_val *key,
|
|||||||
|
|
||||||
static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
|
static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
|
||||||
MDBX_val *data, unsigned flags) {
|
MDBX_val *data, unsigned flags) {
|
||||||
MDBX_page *sub_root = nullptr;
|
|
||||||
MDBX_val xdata, *rdata, dkey, olddata;
|
|
||||||
MDBX_db nested_dupdb;
|
|
||||||
int err;
|
int err;
|
||||||
DKBUF_DEBUG;
|
DKBUF_DEBUG;
|
||||||
MDBX_env *const env = mc->mc_txn->mt_env;
|
MDBX_env *const env = mc->mc_txn->mt_env;
|
||||||
@ -17225,7 +17251,6 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
|
|||||||
DDBI(mc), DKEY_DEBUG(key), key->iov_len,
|
DDBI(mc), DKEY_DEBUG(key), key->iov_len,
|
||||||
DVAL_DEBUG((flags & MDBX_RESERVE) ? nullptr : data), data->iov_len);
|
DVAL_DEBUG((flags & MDBX_RESERVE) ? nullptr : data), data->iov_len);
|
||||||
|
|
||||||
int dupdata_flag = 0;
|
|
||||||
if ((flags & MDBX_CURRENT) != 0 && (mc->mc_flags & C_SUB) == 0) {
|
if ((flags & MDBX_CURRENT) != 0 && (mc->mc_flags & C_SUB) == 0) {
|
||||||
if (unlikely(flags & (MDBX_APPEND | MDBX_NOOVERWRITE)))
|
if (unlikely(flags & (MDBX_APPEND | MDBX_NOOVERWRITE)))
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
@ -17284,10 +17309,11 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
|
|||||||
rc = MDBX_NO_ROOT;
|
rc = MDBX_NO_ROOT;
|
||||||
} else if ((flags & MDBX_CURRENT) == 0) {
|
} else if ((flags & MDBX_CURRENT) == 0) {
|
||||||
bool exact = false;
|
bool exact = false;
|
||||||
|
MDBX_val lastkey, olddata;
|
||||||
if ((flags & MDBX_APPEND) && mc->mc_db->md_entries > 0) {
|
if ((flags & MDBX_APPEND) && mc->mc_db->md_entries > 0) {
|
||||||
rc = cursor_last(mc, &dkey, &olddata);
|
rc = cursor_last(mc, &lastkey, &olddata);
|
||||||
if (likely(rc == MDBX_SUCCESS)) {
|
if (likely(rc == MDBX_SUCCESS)) {
|
||||||
const int cmp = mc->mc_dbx->md_cmp(key, &dkey);
|
const int cmp = mc->mc_dbx->md_cmp(key, &lastkey);
|
||||||
if (likely(cmp > 0)) {
|
if (likely(cmp > 0)) {
|
||||||
mc->mc_ki[mc->mc_top]++; /* step forward for appending */
|
mc->mc_ki[mc->mc_top]++; /* step forward for appending */
|
||||||
rc = MDBX_NOTFOUND;
|
rc = MDBX_NOTFOUND;
|
||||||
@ -17352,7 +17378,7 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
mc->mc_flags &= ~C_DEL;
|
mc->mc_flags &= ~C_DEL;
|
||||||
rdata = data;
|
MDBX_val xdata, *rdata = data;
|
||||||
size_t mcount = 0, dcount = 0;
|
size_t mcount = 0, dcount = 0;
|
||||||
if (unlikely(flags & MDBX_MULTIPLE)) {
|
if (unlikely(flags & MDBX_MULTIPLE)) {
|
||||||
dcount = data[1].iov_len;
|
dcount = data[1].iov_len;
|
||||||
@ -17397,11 +17423,15 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
|
|||||||
mc->mc_flags |= C_INITIALIZED;
|
mc->mc_flags |= C_INITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool insert_key, insert_data, do_sub = false;
|
MDBX_val dkey, olddata;
|
||||||
insert_key = insert_data = (rc != MDBX_SUCCESS);
|
MDBX_db nested_dupdb;
|
||||||
|
MDBX_page *sub_root = nullptr;
|
||||||
|
bool insert_key, insert_data;
|
||||||
uint16_t fp_flags = P_LEAF;
|
uint16_t fp_flags = P_LEAF;
|
||||||
MDBX_page *fp = env->me_pbuf;
|
MDBX_page *fp = env->me_pbuf;
|
||||||
fp->mp_txnid = mc->mc_txn->mt_front;
|
fp->mp_txnid = mc->mc_txn->mt_front;
|
||||||
|
insert_key = insert_data = (rc != MDBX_SUCCESS);
|
||||||
|
dkey.iov_base = nullptr;
|
||||||
if (insert_key) {
|
if (insert_key) {
|
||||||
/* The key does not exist */
|
/* The key does not exist */
|
||||||
DEBUG("inserting key at index %i", mc->mc_ki[mc->mc_top]);
|
DEBUG("inserting key at index %i", mc->mc_ki[mc->mc_top]);
|
||||||
@ -17576,7 +17606,6 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
|
|||||||
/* Back up original data item */
|
/* Back up original data item */
|
||||||
memcpy(dkey.iov_base = fp + 1, olddata.iov_base,
|
memcpy(dkey.iov_base = fp + 1, olddata.iov_base,
|
||||||
dkey.iov_len = olddata.iov_len);
|
dkey.iov_len = olddata.iov_len);
|
||||||
dupdata_flag = 1;
|
|
||||||
|
|
||||||
/* Make sub-page header for the dup items, with dummy body */
|
/* Make sub-page header for the dup items, with dummy body */
|
||||||
fp->mp_flags = P_LEAF | P_SUBP;
|
fp->mp_flags = P_LEAF | P_SUBP;
|
||||||
@ -17680,11 +17709,10 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rdata = &xdata;
|
|
||||||
flags |= F_DUPDATA;
|
|
||||||
do_sub = true;
|
|
||||||
if (!insert_key)
|
if (!insert_key)
|
||||||
node_del(mc, 0);
|
node_del(mc, 0);
|
||||||
|
rdata = &xdata;
|
||||||
|
flags |= F_DUPDATA;
|
||||||
goto new_sub;
|
goto new_sub;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17769,8 +17797,8 @@ new_sub:;
|
|||||||
* storing the user data in the keys field, so there are strict
|
* storing the user data in the keys field, so there are strict
|
||||||
* size limits on dupdata. The actual data fields of the child
|
* size limits on dupdata. The actual data fields of the child
|
||||||
* DB are all zero size. */
|
* DB are all zero size. */
|
||||||
if (do_sub) {
|
if (flags & F_DUPDATA) {
|
||||||
int xflags;
|
unsigned xflags;
|
||||||
size_t ecount;
|
size_t ecount;
|
||||||
put_sub:
|
put_sub:
|
||||||
xdata.iov_len = 0;
|
xdata.iov_len = 0;
|
||||||
@ -17791,13 +17819,11 @@ new_sub:;
|
|||||||
if (sub_root)
|
if (sub_root)
|
||||||
mc->mc_xcursor->mx_cursor.mc_pg[0] = sub_root;
|
mc->mc_xcursor->mx_cursor.mc_pg[0] = sub_root;
|
||||||
/* converted, write the original data first */
|
/* converted, write the original data first */
|
||||||
if (dupdata_flag) {
|
if (dkey.iov_base) {
|
||||||
rc = cursor_put_nochecklen(&mc->mc_xcursor->mx_cursor, &dkey, &xdata,
|
rc = cursor_put_nochecklen(&mc->mc_xcursor->mx_cursor, &dkey, &xdata,
|
||||||
xflags);
|
xflags);
|
||||||
if (unlikely(rc))
|
if (unlikely(rc))
|
||||||
goto bad_sub;
|
goto bad_sub;
|
||||||
/* we've done our job */
|
|
||||||
dkey.iov_len = 0;
|
|
||||||
}
|
}
|
||||||
if (!(node_flags(node) & F_SUBDATA) || sub_root) {
|
if (!(node_flags(node) & F_SUBDATA) || sub_root) {
|
||||||
/* Adjust other cursors pointing to mp */
|
/* Adjust other cursors pointing to mp */
|
||||||
@ -17814,7 +17840,7 @@ new_sub:;
|
|||||||
continue;
|
continue;
|
||||||
if (m2->mc_pg[i] == mp) {
|
if (m2->mc_pg[i] == mp) {
|
||||||
if (m2->mc_ki[i] == mc->mc_ki[i]) {
|
if (m2->mc_ki[i] == mc->mc_ki[i]) {
|
||||||
err = cursor_xinit2(m2, mx, dupdata_flag);
|
err = cursor_xinit2(m2, mx, dkey.iov_base != nullptr);
|
||||||
if (unlikely(err != MDBX_SUCCESS))
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
return err;
|
return err;
|
||||||
} else if (!insert_key && m2->mc_ki[i] < nkeys) {
|
} else if (!insert_key && m2->mc_ki[i] < nkeys) {
|
||||||
@ -17858,6 +17884,7 @@ new_sub:;
|
|||||||
if (mcount < dcount) {
|
if (mcount < dcount) {
|
||||||
data[0].iov_base = ptr_disp(data[0].iov_base, data[0].iov_len);
|
data[0].iov_base = ptr_disp(data[0].iov_base, data[0].iov_len);
|
||||||
insert_key = insert_data = false;
|
insert_key = insert_data = false;
|
||||||
|
dkey.iov_base = nullptr;
|
||||||
goto more;
|
goto more;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -21112,6 +21139,10 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data,
|
|||||||
tASSERT(txn, XCURSOR_INITED(&cx.outer) &&
|
tASSERT(txn, XCURSOR_INITED(&cx.outer) &&
|
||||||
cx.outer.mc_xcursor->mx_db.md_entries > 1);
|
cx.outer.mc_xcursor->mx_db.md_entries > 1);
|
||||||
rc = MDBX_EMULTIVAL;
|
rc = MDBX_EMULTIVAL;
|
||||||
|
if ((flags & MDBX_NOOVERWRITE) == 0) {
|
||||||
|
flags -= MDBX_CURRENT;
|
||||||
|
rc = cursor_del(&cx.outer, MDBX_ALLDUPS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23035,30 +23066,6 @@ bailout:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mdbx_set_compare(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
|
|
||||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR);
|
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID)))
|
|
||||||
return MDBX_BAD_DBI;
|
|
||||||
|
|
||||||
txn->mt_dbxs[dbi].md_cmp = cmp;
|
|
||||||
return MDBX_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mdbx_set_dupsort(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
|
|
||||||
int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_ERROR);
|
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
if (unlikely(!check_dbi(txn, dbi, DBI_USRVALID)))
|
|
||||||
return MDBX_BAD_DBI;
|
|
||||||
|
|
||||||
txn->mt_dbxs[dbi].md_dcmp = cmp;
|
|
||||||
return MDBX_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
__cold int mdbx_reader_list(const MDBX_env *env, MDBX_reader_list_func *func,
|
__cold int mdbx_reader_list(const MDBX_env *env, MDBX_reader_list_func *func,
|
||||||
void *ctx) {
|
void *ctx) {
|
||||||
int rc = check_env(env, true);
|
int rc = check_env(env, true);
|
||||||
|
@ -1482,6 +1482,7 @@ struct MDBX_env {
|
|||||||
int me_valgrind_handle;
|
int me_valgrind_handle;
|
||||||
#endif
|
#endif
|
||||||
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
|
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
|
||||||
|
MDBX_atomic_uint32_t me_ignore_EDEADLK;
|
||||||
pgno_t me_poison_edge;
|
pgno_t me_poison_edge;
|
||||||
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
|
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
|
||||||
|
|
||||||
|
@ -822,6 +822,11 @@ __cold static int mdbx_ipclock_failed(MDBX_env *env, osal_ipclock_t *ipc,
|
|||||||
#error "FIXME"
|
#error "FIXME"
|
||||||
#endif /* MDBX_LOCKING */
|
#endif /* MDBX_LOCKING */
|
||||||
|
|
||||||
|
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
|
||||||
|
if (rc == EDEADLK && atomic_load32(&env->me_ignore_EDEADLK, mo_Relaxed) > 0)
|
||||||
|
return rc;
|
||||||
|
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
|
||||||
|
|
||||||
ERROR("mutex (un)lock failed, %s", mdbx_strerror(err));
|
ERROR("mutex (un)lock failed, %s", mdbx_strerror(err));
|
||||||
if (rc != EDEADLK)
|
if (rc != EDEADLK)
|
||||||
env->me_flags |= MDBX_FATAL_ERROR;
|
env->me_flags |= MDBX_FATAL_ERROR;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||||
.TH MDBX_CHK 1 "2023-06-16" "MDBX 0.12.7"
|
.TH MDBX_CHK 1 "2023-10-17" "MDBX 0.12.8"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
mdbx_chk \- MDBX checking tool
|
mdbx_chk \- MDBX checking tool
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
||||||
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||||
.TH MDBX_COPY 1 "2023-06-16" "MDBX 0.12.7"
|
.TH MDBX_COPY 1 "2023-10-17" "MDBX 0.12.8"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
mdbx_copy \- MDBX environment copy tool
|
mdbx_copy \- MDBX environment copy tool
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
.\" Copyright 2021-2023 Leonid Yuriev <leo@yuriev.ru>.
|
.\" Copyright 2021-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||||
.\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved.
|
.\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved.
|
||||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||||
.TH MDBX_DROP 1 "2023-06-16" "MDBX 0.12.7"
|
.TH MDBX_DROP 1 "2023-10-17" "MDBX 0.12.8"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
mdbx_drop \- MDBX database delete tool
|
mdbx_drop \- MDBX database delete tool
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
||||||
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||||
.TH MDBX_DUMP 1 "2023-06-16" "MDBX 0.12.7"
|
.TH MDBX_DUMP 1 "2023-10-17" "MDBX 0.12.8"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
mdbx_dump \- MDBX environment export tool
|
mdbx_dump \- MDBX environment export tool
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
||||||
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||||
.TH MDBX_LOAD 1 "2023-06-16" "MDBX 0.12.7"
|
.TH MDBX_LOAD 1 "2023-10-17" "MDBX 0.12.8"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
mdbx_load \- MDBX environment import tool
|
mdbx_load \- MDBX environment import tool
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
||||||
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||||
.TH MDBX_STAT 1 "2023-06-16" "MDBX 0.12.7"
|
.TH MDBX_STAT 1 "2023-10-17" "MDBX 0.12.8"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
mdbx_stat \- MDBX environment status tool
|
mdbx_stat \- MDBX environment status tool
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
110
src/mdbx.c++
110
src/mdbx.c++
@ -233,6 +233,10 @@ namespace mdbx {
|
|||||||
"into an incompatible memory allocation scheme.");
|
"into an incompatible memory allocation scheme.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[noreturn]] __cold void throw_bad_value_size() {
|
||||||
|
throw bad_value_size(MDBX_BAD_VALSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
__cold exception::exception(const ::mdbx::error &error) noexcept
|
__cold exception::exception(const ::mdbx::error &error) noexcept
|
||||||
: base(error.what()), error_(error) {}
|
: base(error.what()), error_(error) {}
|
||||||
|
|
||||||
@ -281,7 +285,7 @@ DEFINE_EXCEPTION(something_busy)
|
|||||||
DEFINE_EXCEPTION(thread_mismatch)
|
DEFINE_EXCEPTION(thread_mismatch)
|
||||||
DEFINE_EXCEPTION(transaction_full)
|
DEFINE_EXCEPTION(transaction_full)
|
||||||
DEFINE_EXCEPTION(transaction_overlapping)
|
DEFINE_EXCEPTION(transaction_overlapping)
|
||||||
|
DEFINE_EXCEPTION(duplicated_lck_file)
|
||||||
#undef DEFINE_EXCEPTION
|
#undef DEFINE_EXCEPTION
|
||||||
|
|
||||||
__cold const char *error::what() const noexcept {
|
__cold const char *error::what() const noexcept {
|
||||||
@ -367,6 +371,7 @@ __cold void error::throw_exception() const {
|
|||||||
CASE_EXCEPTION(thread_mismatch, MDBX_THREAD_MISMATCH);
|
CASE_EXCEPTION(thread_mismatch, MDBX_THREAD_MISMATCH);
|
||||||
CASE_EXCEPTION(transaction_full, MDBX_TXN_FULL);
|
CASE_EXCEPTION(transaction_full, MDBX_TXN_FULL);
|
||||||
CASE_EXCEPTION(transaction_overlapping, MDBX_TXN_OVERLAPPING);
|
CASE_EXCEPTION(transaction_overlapping, MDBX_TXN_OVERLAPPING);
|
||||||
|
CASE_EXCEPTION(duplicated_lck_file, MDBX_DUPLICATED_CLK);
|
||||||
#undef CASE_EXCEPTION
|
#undef CASE_EXCEPTION
|
||||||
default:
|
default:
|
||||||
if (is_mdbx_error())
|
if (is_mdbx_error())
|
||||||
@ -483,6 +488,109 @@ bool slice::is_printable(bool disable_utf8) const noexcept {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MDBX_U128_TYPE
|
||||||
|
MDBX_U128_TYPE slice::as_uint128() const {
|
||||||
|
static_assert(sizeof(MDBX_U128_TYPE) == 16, "WTF?");
|
||||||
|
if (size() == 16) {
|
||||||
|
MDBX_U128_TYPE r;
|
||||||
|
memcpy(&r, data(), sizeof(r));
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
return as_uint64();
|
||||||
|
}
|
||||||
|
#endif /* MDBX_U128_TYPE */
|
||||||
|
|
||||||
|
uint64_t slice::as_uint64() const {
|
||||||
|
static_assert(sizeof(uint64_t) == 8, "WTF?");
|
||||||
|
if (size() == 8) {
|
||||||
|
uint64_t r;
|
||||||
|
memcpy(&r, data(), sizeof(r));
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
return as_uint32();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t slice::as_uint32() const {
|
||||||
|
static_assert(sizeof(uint32_t) == 4, "WTF?");
|
||||||
|
if (size() == 4) {
|
||||||
|
uint32_t r;
|
||||||
|
memcpy(&r, data(), sizeof(r));
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
return as_uint16();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t slice::as_uint16() const {
|
||||||
|
static_assert(sizeof(uint16_t) == 2, "WTF?");
|
||||||
|
if (size() == 2) {
|
||||||
|
uint16_t r;
|
||||||
|
memcpy(&r, data(), sizeof(r));
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
return as_uint8();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t slice::as_uint8() const {
|
||||||
|
static_assert(sizeof(uint8_t) == 1, "WTF?");
|
||||||
|
if (size() == 1)
|
||||||
|
return *static_cast<const uint8_t *>(data());
|
||||||
|
else if (size() == 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
MDBX_CXX20_UNLIKELY throw_bad_value_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MDBX_I128_TYPE
|
||||||
|
MDBX_I128_TYPE slice::as_int128() const {
|
||||||
|
static_assert(sizeof(MDBX_I128_TYPE) == 16, "WTF?");
|
||||||
|
if (size() == 16) {
|
||||||
|
MDBX_I128_TYPE r;
|
||||||
|
memcpy(&r, data(), sizeof(r));
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
return as_int64();
|
||||||
|
}
|
||||||
|
#endif /* MDBX_I128_TYPE */
|
||||||
|
|
||||||
|
int64_t slice::as_int64() const {
|
||||||
|
static_assert(sizeof(int64_t) == 8, "WTF?");
|
||||||
|
if (size() == 8) {
|
||||||
|
uint64_t r;
|
||||||
|
memcpy(&r, data(), sizeof(r));
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
return as_int32();
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slice::as_int32() const {
|
||||||
|
static_assert(sizeof(int32_t) == 4, "WTF?");
|
||||||
|
if (size() == 4) {
|
||||||
|
int32_t r;
|
||||||
|
memcpy(&r, data(), sizeof(r));
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
return as_int16();
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t slice::as_int16() const {
|
||||||
|
static_assert(sizeof(int16_t) == 2, "WTF?");
|
||||||
|
if (size() == 2) {
|
||||||
|
int16_t r;
|
||||||
|
memcpy(&r, data(), sizeof(r));
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
return as_int8();
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t slice::as_int8() const {
|
||||||
|
if (size() == 1)
|
||||||
|
return *static_cast<const int8_t *>(data());
|
||||||
|
else if (size() == 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
MDBX_CXX20_UNLIKELY throw_bad_value_size();
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
|
char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
|
||||||
|
@ -80,6 +80,13 @@ if(UNIX AND NOT SUBPROJECT)
|
|||||||
set_target_properties(test_extra_maindb_ordinal PROPERTIES
|
set_target_properties(test_extra_maindb_ordinal PROPERTIES
|
||||||
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
||||||
endif()
|
endif()
|
||||||
|
add_executable(test_extra_dupfixed_multiple extra/dupfixed_multiple.c++)
|
||||||
|
target_include_directories(test_extra_dupfixed_multiple PRIVATE "${PROJECT_SOURCE_DIR}")
|
||||||
|
target_link_libraries(test_extra_dupfixed_multiple ${TOOL_MDBX_LIB})
|
||||||
|
if(MDBX_CXX_STANDARD)
|
||||||
|
set_target_properties(test_extra_dupfixed_multiple PROPERTIES
|
||||||
|
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -159,4 +166,12 @@ else()
|
|||||||
REQUIRED_FILES uniq_nested.db-copy)
|
REQUIRED_FILES uniq_nested.db-copy)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNIX AND NOT SUBPROJECT)
|
||||||
|
add_test(NAME extra_upsert_alldups COMMAND test_extra_upsert_alldups)
|
||||||
|
if(MDBX_BUILD_CXX)
|
||||||
|
add_test(NAME extra_maindb_ordinal COMMAND test_extra_maindb_ordinal)
|
||||||
|
add_test(NAME extra_dupfixed_multiple COMMAND test_extra_dupfixed_multiple)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
210
test/extra/dupfixed_multiple.c++
Normal file
210
test/extra/dupfixed_multiple.c++
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
#include "mdbx.h++"
|
||||||
|
#include <array>
|
||||||
|
#include <iostream>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
unlink("." MDBX_DATANAME);
|
||||||
|
unlink("." MDBX_LOCKNAME);
|
||||||
|
|
||||||
|
mdbx::env_managed env(".", mdbx::env_managed::create_parameters(),
|
||||||
|
mdbx::env::operate_parameters());
|
||||||
|
|
||||||
|
using buffer =
|
||||||
|
mdbx::buffer<mdbx::default_allocator, mdbx::default_capacity_policy>;
|
||||||
|
auto txn = env.start_write();
|
||||||
|
auto map = txn.create_map(nullptr, mdbx::key_mode::ordinal,
|
||||||
|
mdbx::value_mode::multi_ordinal);
|
||||||
|
|
||||||
|
txn.insert(map, buffer::key_from_u64(21), buffer::key_from_u64(18));
|
||||||
|
txn.insert(map, buffer::key_from_u64(7), buffer::key_from_u64(19));
|
||||||
|
txn.insert(map, buffer::key_from_u64(22), buffer::key_from_u64(17));
|
||||||
|
txn.insert(map, buffer::key_from_u64(26), buffer::key_from_u64(13));
|
||||||
|
txn.insert(map, buffer::key_from_u64(24), buffer::key_from_u64(15));
|
||||||
|
txn.insert(map, buffer::key_from_u64(23), buffer::key_from_u64(16));
|
||||||
|
txn.insert(map, buffer::key_from_u64(25), buffer::key_from_u64(14));
|
||||||
|
txn.insert(map, buffer::key_from_u64(27), buffer::key_from_u64(12));
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
txn = env.start_read();
|
||||||
|
auto cursor = txn.open_cursor(map);
|
||||||
|
if (cursor.to_first().value.as_uint64() != 19 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 18 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 17 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 16 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 15 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 14 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 13 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 12 || cursor.to_next(false).done ||
|
||||||
|
!cursor.eof()) {
|
||||||
|
std::cerr << "Fail\n";
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
txn.abort();
|
||||||
|
|
||||||
|
const uint64_t array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 42, 17, 99, 0, 33, 333};
|
||||||
|
txn = env.start_write();
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(13), array + 3, 4, mdbx::upsert);
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(10), array + 0, 1, mdbx::upsert);
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(12), array + 2, 3, mdbx::upsert);
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(15), array + 5, 6, mdbx::upsert);
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(14), array + 4, 5, mdbx::upsert);
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(11), array + 1, 2, mdbx::upsert);
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(16), array + 6, 7, mdbx::upsert);
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
txn = env.start_read();
|
||||||
|
cursor = txn.open_cursor(map);
|
||||||
|
if (/* key = 7 */ cursor.to_first().value.as_uint64() != 19 ||
|
||||||
|
|
||||||
|
/* key = 10: 1 элемент */
|
||||||
|
cursor.to_next().value.as_uint64() != 1 ||
|
||||||
|
|
||||||
|
/* key = 11: 2 элемента, пропуск 1 */
|
||||||
|
cursor.to_next().value.as_uint64() != 2 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 3 ||
|
||||||
|
|
||||||
|
/* key = 12: 3 элемента, пропуск 2 */
|
||||||
|
cursor.to_next().value.as_uint64() != 3 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 4 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 5 ||
|
||||||
|
|
||||||
|
/* key = 13: 4 элемента, пропуск 3 */
|
||||||
|
cursor.to_next().value.as_uint64() != 4 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 5 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 6 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 7 ||
|
||||||
|
|
||||||
|
/* key = 14: 5 элементов, пропуск 4 */
|
||||||
|
cursor.to_next().value.as_uint64() != 5 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 6 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 7 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 8 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 9 ||
|
||||||
|
|
||||||
|
/* key = 15: 6 элементов, пропуск 5 */
|
||||||
|
cursor.to_next().value.as_uint64() != 6 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 7 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 8 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 9 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 17 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 42 ||
|
||||||
|
|
||||||
|
/* key = 16: 7 элементов, пропуск 6 */
|
||||||
|
cursor.to_next().value.as_uint64() != 0 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 7 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 8 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 9 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 17 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 42 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 99 ||
|
||||||
|
|
||||||
|
/* key = 21 */ cursor.to_next().value.as_uint64() != 18 ||
|
||||||
|
/* key = 22 */ cursor.to_next().value.as_uint64() != 17 ||
|
||||||
|
/* key = 23 */ cursor.to_next().value.as_uint64() != 16 ||
|
||||||
|
/* key = 24 */ cursor.to_next().value.as_uint64() != 15 ||
|
||||||
|
/* key = 25 */ cursor.to_next().value.as_uint64() != 14 ||
|
||||||
|
/* key = 26 */ cursor.to_next().value.as_uint64() != 13 ||
|
||||||
|
/* key = 27 */ cursor.to_next().value.as_uint64() != 12 ||
|
||||||
|
cursor.to_next(false).done || !cursor.eof()) {
|
||||||
|
std::cerr << "Fail\n";
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
txn.abort();
|
||||||
|
|
||||||
|
txn = env.start_write();
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(7), array + 3, 4, mdbx::update);
|
||||||
|
txn.upsert(map, buffer::key_from_u64(10), buffer::key_from_u64(14));
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(11), array + 4, 5, mdbx::upsert);
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(12), array + 0, 1, mdbx::update);
|
||||||
|
txn.update(map, buffer::key_from_u64(13), buffer::key_from_u64(18));
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(14), array + 2, 3, mdbx::update);
|
||||||
|
txn.update(map, buffer::key_from_u64(15), buffer::key_from_u64(13));
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(16), array + 6, 9, mdbx::update);
|
||||||
|
txn.update(map, buffer::key_from_u64(21), buffer::key_from_u64(17));
|
||||||
|
txn.update(map, buffer::key_from_u64(22), buffer::key_from_u64(15));
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(23), array + 1, 2, mdbx::update);
|
||||||
|
txn.update(map, buffer::key_from_u64(24), buffer::key_from_u64(16));
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(25), array + 5, 6, mdbx::update);
|
||||||
|
txn.upsert(map, buffer::key_from_u64(26), buffer::key_from_u64(12));
|
||||||
|
txn.put_multiple(map, buffer::key_from_u64(27), array + 12, 3, mdbx::update);
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
txn = env.start_read();
|
||||||
|
cursor = txn.open_cursor(map);
|
||||||
|
if (/* key = 7 */
|
||||||
|
cursor.to_first().value.as_uint64() != 4 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 5 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 6 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 7 ||
|
||||||
|
|
||||||
|
/* key = 10: 1 элемент */
|
||||||
|
cursor.to_next().value.as_uint64() != 1 ||
|
||||||
|
/* +1 upsert */
|
||||||
|
cursor.to_next().value.as_uint64() != 14 ||
|
||||||
|
|
||||||
|
/* key = 11: 2 элемента, пропуск 1 */
|
||||||
|
cursor.to_next().value.as_uint64() != 2 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 3 ||
|
||||||
|
/* +5 элементов, пропуск 4 */
|
||||||
|
cursor.to_next().value.as_uint64() != 5 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 6 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 7 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 8 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 9 ||
|
||||||
|
|
||||||
|
/* key = 12: 1 элемент */
|
||||||
|
cursor.to_next().value.as_uint64() != 1 ||
|
||||||
|
/* key = 13 */ cursor.to_next().value.as_uint64() != 18 ||
|
||||||
|
|
||||||
|
/* key = 14: 3 элемента, пропуск 2 */
|
||||||
|
cursor.to_next().value.as_uint64() != 3 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 4 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 5 ||
|
||||||
|
|
||||||
|
/* key = 15 */ cursor.to_next().value.as_uint64() != 13 ||
|
||||||
|
|
||||||
|
/* key = 16: 9 элементов, пропуск 6 */
|
||||||
|
cursor.to_next().value.as_uint64() != 0 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 7 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 8 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 9 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 17 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 33 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 42 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 99 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 333 ||
|
||||||
|
|
||||||
|
/* key = 21 */ cursor.to_next().value.as_uint64() != 17 ||
|
||||||
|
/* key = 22 */ cursor.to_next().value.as_uint64() != 15 ||
|
||||||
|
/* key = 23: 2 элемента, пропуск 1 */
|
||||||
|
cursor.to_next().value.as_uint64() != 2 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 3 ||
|
||||||
|
/* key = 24 */ cursor.to_next().value.as_uint64() != 16 ||
|
||||||
|
/* key = 25: 6 элемента, пропуск 5 */
|
||||||
|
cursor.to_next().value.as_uint64() != 6 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 7 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 8 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 9 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 17 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 42 ||
|
||||||
|
|
||||||
|
/* key = 26, 1+1 upsert */
|
||||||
|
cursor.to_next().value.as_uint64() != 12 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 13 ||
|
||||||
|
|
||||||
|
/* key = 27: 3 элемента, пропуск 12 */
|
||||||
|
cursor.to_next().value.as_uint64() != 0 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 33 ||
|
||||||
|
cursor.to_next().value.as_uint64() != 333 ||
|
||||||
|
|
||||||
|
cursor.to_next(false).done || !cursor.eof()) {
|
||||||
|
std::cerr << "Fail\n";
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::cout << "OK\n";
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
@ -182,6 +182,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
errmsg = "failed to mdbx_txn_commit: %s\n";
|
errmsg = "failed to mdbx_txn_commit: %s\n";
|
||||||
goto Fail;
|
goto Fail;
|
||||||
}
|
}
|
||||||
|
mdbx_cursor_close(cur);
|
||||||
if ((rc = mdbx_env_close(env))) {
|
if ((rc = mdbx_env_close(env))) {
|
||||||
errmsg = "failed to mdbx_env_close: %s\n";
|
errmsg = "failed to mdbx_env_close: %s\n";
|
||||||
goto Fail;
|
goto Fail;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user