mirror of
https://github.com/isar/libmdbx.git
synced 2025-12-17 05:22:21 +08:00
Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aea40fb79f | ||
|
|
0741c81cfd | ||
|
|
781b3f64d5 | ||
|
|
446d6c9421 | ||
|
|
fff3fbd866 | ||
|
|
3e850981c7 | ||
|
|
36a7e7ac24 | ||
|
|
2d7fe42327 | ||
|
|
2b88c6261f | ||
|
|
e515bd56e9 | ||
|
|
20160ae98f | ||
|
|
ea97fbae74 | ||
|
|
a0a4af7701 | ||
|
|
74f2bc813b | ||
|
|
1a18369015 | ||
|
|
e2f2fd8652 | ||
|
|
fb6be62046 | ||
|
|
f7e6bd770a | ||
|
|
ba5c74e54d | ||
|
|
049b71c148 | ||
|
|
185e43f3a8 | ||
|
|
990d4ea042 | ||
|
|
8d67d23224 | ||
|
|
4a7a2034c0 | ||
|
|
d963f3a971 | ||
|
|
fb15c8ca0b | ||
|
|
b6034e8045 | ||
|
|
ae01a8e891 | ||
|
|
1277fe965d | ||
|
|
7fc6a1b658 | ||
|
|
b1abcb8260 | ||
|
|
7cd3dbbccb | ||
|
|
352dd75ee8 | ||
|
|
cf1541e4d7 | ||
|
|
446dbc9d6c | ||
|
|
64a5ad8c04 | ||
|
|
0fd0d527d9 | ||
|
|
4bed5d1779 | ||
|
|
6e4473777e | ||
|
|
5abb6a9bbf | ||
|
|
c014685c01 | ||
|
|
476da5f8cf | ||
|
|
b905a6a391 | ||
|
|
d94f34b2c0 | ||
|
|
f5ce7322c4 | ||
|
|
ab5d290f11 | ||
|
|
7eb2f4130e | ||
|
|
ed8c7ead4e | ||
|
|
080875cd6d | ||
|
|
753cfd00eb | ||
|
|
311a6e5d10 | ||
|
|
e58b582639 | ||
|
|
e2ed55853d | ||
|
|
02c7cf2a9c | ||
|
|
83f19fc993 | ||
|
|
d440485156 | ||
|
|
25ec8e253f | ||
|
|
248208cf5d | ||
|
|
f02a0ffa21 | ||
|
|
2b0eae08f5 | ||
|
|
5d9740bbcf | ||
|
|
39f2bb142a | ||
|
|
e9b10db255 | ||
|
|
687622b8b1 | ||
|
|
fd8a99acff | ||
|
|
e21e91ad1f | ||
|
|
6027348651 | ||
|
|
1aead6869a | ||
|
|
45721d4064 | ||
|
|
6de15514df | ||
|
|
215bee9ab7 | ||
|
|
7d3f136a3a | ||
|
|
eb348ca34c | ||
|
|
cb48ee8f3d | ||
|
|
a387284458 | ||
|
|
e7ae8214fd | ||
|
|
e195f5bcf7 | ||
|
|
c256e8358c | ||
|
|
bc6d320bb2 | ||
|
|
7b12e7323f | ||
|
|
45aa39c68b | ||
|
|
d02bdcf2bd | ||
|
|
5561cec9c5 | ||
|
|
ff6674b377 | ||
|
|
ca6f04c52a | ||
|
|
db6cf469c9 | ||
|
|
d516e903d4 | ||
|
|
7aaae2ecd5 | ||
|
|
bf1c753be3 | ||
|
|
79edab2adf | ||
|
|
37792cc568 | ||
|
|
e8d2a5bd09 | ||
|
|
2c2612ba23 | ||
|
|
60b483025c | ||
|
|
2abf80a199 | ||
|
|
4fd21d2f7b |
@@ -1,5 +1,5 @@
|
||||
##
|
||||
## Copyright 2020-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
## Copyright 2020-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
## and other libmdbx authors: please see AUTHORS file.
|
||||
## All rights reserved.
|
||||
##
|
||||
@@ -512,23 +512,25 @@ else()
|
||||
mark_as_advanced(MDBX_USE_OFDLOCKS)
|
||||
set(MDBX_AVOID_MSYNC_DEFAULT OFF)
|
||||
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)
|
||||
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)
|
||||
mark_as_advanced(MDBX_TRUST_RTC)
|
||||
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)
|
||||
option(MDBX_ENABLE_REFUND "Zerocost auto-compactification during write-transactions" ON)
|
||||
option(MDBX_ENABLE_MADVISE "Using POSIX' madvise() and/or similar hints" ON)
|
||||
add_mdbx_option(MDBX_FORCE_ASSERTIONS "Force enable assertion checking" 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)
|
||||
mark_as_advanced(MDBX_DISABLE_VALIDATION)
|
||||
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)
|
||||
set(MDBX_BIGFOOT_DEFAULT ON)
|
||||
else()
|
||||
set(MDBX_BIGFOOT_DEFAULT OFF)
|
||||
endif()
|
||||
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)
|
||||
option(MDBX_ENABLE_PROFGC "Profiling of GC search and updates" OFF)
|
||||
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})
|
||||
add_mdbx_option(MDBX_ENABLE_PGOP_STAT "Gathering statistics for page operations" ON)
|
||||
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(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>.
|
||||
Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
Copyright 2015,2016 Peter-Service R&D LLC.
|
||||
All rights reserved.
|
||||
|
||||
295
ChangeLog.md
295
ChangeLog.md
@@ -1,9 +1,296 @@
|
||||
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)
|
||||
and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md).
|
||||
|
||||
## v0.12.10 "СЭМ" от 2024-03-12
|
||||
|
||||
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов
|
||||
в память Героя России гвардии майора Дмитрия Семёнова с позывным "СЭМ".
|
||||
|
||||
```
|
||||
git diff' stat: 19 commits, 57 files changed, 751 insertions(+), 331 deletions(-)
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
```
|
||||
|
||||
Благодарности:
|
||||
|
||||
- [Dvir H](https://t.me/Dvirsw) за [сообщение](https://t.me/libmdbx/5368)
|
||||
об ошибке `MDBX_CORRUPTED` в сценарии работы в режиме `MDBX_DUPFIXED` и нечетной длинной
|
||||
мульти-значений, с предоставлением точного минимального сценария воспроизведения.
|
||||
|
||||
Значимые исправления и доработки:
|
||||
|
||||
- Устранение унаследованной от LMDB ошибки приводящей к повреждению БД при использовании `MDBX_DUPFIXED`.
|
||||
Проблема была выявлена при расширении тестов сценариями с длинными мульти-значениями в режиме `MDBX_DUPFIXED`.
|
||||
Сообщений о проявлении этой ошибки в эксплуатационных/продуктовых средах не поступало.
|
||||
|
||||
На LEAF2-страниц, используемых для компактного хранения мульти-значений фиксированной длины,
|
||||
выполнялось резервирование места без учета возможности превышения размера страниц,
|
||||
с последующим переполнением, повреждением структуры БД и/или повреждением содержимого ОЗУ.
|
||||
|
||||
Вероятность проявления ошибки существенно увеличивалась с увеличением размера/длины
|
||||
мульти-значений/дубликатов и уменьшением размера страницы БД. Поэтому при использовании `MDBX_INTEGERDUP`
|
||||
вероятность проявления близка к нулю, а сценарий такого проявления найти не удалось.
|
||||
|
||||
В MDBX ошибка присутствовала с момента отделения проекта от LMDB,
|
||||
где эта ошибка присутствует более 11 лети, по настоящее время.
|
||||
|
||||
- Исправление ложной ошибки `MDBX_CORRUPTED (-30796)` в сценарии работы
|
||||
в режиме `MDBX_DUPFIXED` и нечетной длинной мульти-значений.
|
||||
|
||||
- Исправление недочета корректировки сопутствующих курсоров при разделении страницы
|
||||
по сценарию добавления пустой страницы слева.
|
||||
|
||||
- Доработка `rebalance()` ради уменьшения WAF. Новый функционал, включая
|
||||
контролируемую пользователем опцию `enum MDBX_option_t`, будет доступен
|
||||
в выпусках ветки `0.13.x`, а в этом выпуске доработка сводится к тактике
|
||||
не-вовленичения чистой страницы при нехватке запаса страниц в ходе обновления GC,
|
||||
за счет ухудшения баланса дерева страниц.
|
||||
|
||||
- Устранение упущения приводящего к нелогичной ситуации
|
||||
`me_dxb_mmap.curren > me_dxb_mmap.limit` при "дребезге" размера БД.
|
||||
В текущем понимании, последствий кроме срабатывания assert-проверки нет, а
|
||||
вероятность проявления близка к нулю.
|
||||
|
||||
- Исправление в функционале обхода дерева, используемого утилитой
|
||||
`mdbx_chk`, подсчета места затраченного на выравнивание на вложенной
|
||||
под-странице, в случае нечетного количества dupfixed-элементов нечетного
|
||||
размера.
|
||||
Сообщений о проявлении этой ошибки в эксплуатационных/продуктовых средах не поступало.
|
||||
|
||||
- Исправление assert-проверки внутри `check_txn()` для случая завершенных транзакций в режиме `MDBX_NO_TLS`.
|
||||
Последствий ошибки, кроме срабатывания assert-проверки в отладочных сборках, нет.
|
||||
|
||||
- Устранение ошибки при открытии БД на файловой системе только-для-чтения.
|
||||
|
||||
- Удалены излишне строгие проверки в утилите `mdbx_chk`, которые
|
||||
приводили к ложно-позитивным ошибкам при проверке БД после серии
|
||||
последних доработок. Подробности см в комментариях к коммитам [781b3f64d52b73cbaeb00a55811d1247c25624a8](https://gitflic.ru/project/erthink/libmdbx/commit/781b3f64d52b73cbaeb00a55811d1247c25624a8)
|
||||
и [0741c81cfd8dc0864fcf55e04192b2207c8f68f7](https://gitflic.ru/project/erthink/libmdbx/commit/0741c81cfd8dc0864fcf55e04192b2207c8f68f7).
|
||||
|
||||
Прочее:
|
||||
|
||||
- Расширение стохастического теста dupfixed-сценариями.
|
||||
- Корректировка условия в assert-проверке для `MDBX_TXN_DRAINED_GC`.
|
||||
- Добавление в jitter-сценарий простого теста сброса и перезапуска читающих транзакций.
|
||||
- Вынужденное продолжение очистки/рефакторинга унаследованных ребусов в `cursor_put_nochecklen()`.
|
||||
- Фиксация транзакции при ошибках теста для последующего анализа содержимого БД.
|
||||
- Сопутствующий рефакторинг `node_shrink()` для ясности исходного кода.
|
||||
- Приведение в соответствие протоколируемых имен тестов опциям командной строки.
|
||||
- Добавление cmoke-теста `extra/dupfixed_addodd`.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.12.9 "Ясень-4" от 2023-12-11
|
||||
|
||||
Стабилизирующий выпуск с исправлением обнаруженных ошибок и устранением недочетов.
|
||||
|
||||
```
|
||||
git diff' stat: 32 commits, 8 files changed, 667 insertions(+), 401 deletions(-)
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
```
|
||||
|
||||
Исправления и доработки:
|
||||
|
||||
- Ликвидация зависимости от ранее удаленной опции `MDBX_ENABLE_PREFAULT`, из-за
|
||||
чего опция `MDBX_ENABLE_MINCORE` не включалась автоматически, что приводило
|
||||
к не-активации соответствующего улучшения и не-достижению декларируемого уровня
|
||||
производительности в сценариях использования в режиме `MDBX_WRITEMAP`.
|
||||
|
||||
- Исправление авто-установки `MDBX_ENV_CHECKPID` при отключении использования
|
||||
функционала `madvise()` посредством опции сборки `MDBX_ENABLE_MADVISE=0`.
|
||||
Из-за чего при поддержке системой `madvise(MADV_DONTFORK)` не включался контроль pid.
|
||||
|
||||
- Добавлена проверка переданного ключа на `NULL` при обработке `MDBX_GET_MULTIPLE`.
|
||||
|
||||
- Добавлена проверка номеров корневых страниц в `coherency_check()`.
|
||||
|
||||
- Обеспечен `const` для начала и конца диапазона в аргументах `mdbx_estimate_range()`.
|
||||
|
||||
- Из разрабатываемой версии перенесены не-нарушающие совместимости доработки C++ API:
|
||||
|
||||
- добавлен тип `mdbx::cursor::estimation_result`, а поведение методов
|
||||
`cursor::estimate()` унифицировано с `cursor::move()`;
|
||||
- для предотвращения незаметного неверного использования API, для инициализации
|
||||
возвращаемых по ссылке срезов, вместо пустых срезов задействован `slice::invalid()`;
|
||||
- добавлены дополнительные C++ операторы преобразования к типам C API;
|
||||
- для совместимости со старыми стандартами C++ и старыми версиями STL перенесены
|
||||
в public классы `buffer::move_assign_alloc` и `buffer::copy_assign_alloc`;
|
||||
- добавлен тип `mdbx::default_buffer`;
|
||||
- для срезов и буферов добавлены методы `hex_decode()`, `base64_decode()`, `base58_decode()`;
|
||||
- добавлен тип `mdbx::comparator` и функций `mdbx::default_comparator()`;
|
||||
- добавлены статические методы `buffer::hex()`, `base64()`, `base58()`;
|
||||
- для транзакций и курсоров добавлены методы `get_/set_context`;
|
||||
- добавлен метод `cursor::clone()`;
|
||||
|
||||
- Поддержка base58 приведена в соответствии с черновиком RFC.
|
||||
|
||||
- Переработка/исправление `to_hex()` и `from_hex()`.
|
||||
|
||||
- Уменьшение `MDBX_opt_rp_augment_limit` по умолчанию до 1/3 от текущего количества страниц в БД.
|
||||
|
||||
Мелочи:
|
||||
|
||||
- Удаление устаревших `mdbx_set_compare()` и `mdbx_set_dupsort()`.
|
||||
- Корректировка определения `MDBX_LAST_ADDED_ERRCODE`.
|
||||
- Добавление в C++ API забытого исключения `mdbx::duplicated_lck_file`.
|
||||
- Обновление патча для старых версий buildroot.
|
||||
- Использование в API `const MDBX_txn` где это возможно.
|
||||
- Удаление устаревшего упоминания `MDBX_EAGAIN`.
|
||||
- Проверка pid процесса только в функциях API требующих активной среды/env.
|
||||
- Исправление опечаток в комментариях, в том числе в doxygen-описании.
|
||||
- В тестах для совместимости с проблемными версиями glibc и glibc++
|
||||
устранено использование `std::stoull()`.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
Стабилизирующий выпуск с исправлением обнаруженных ошибок и устранением
|
||||
недочетов, в день основания международного детского центра [«Арте́к»](https://ru.wikipedia.org/wiki/Артек).
|
||||
|
||||
```
|
||||
14 files changed, 222 insertions(+), 56 deletions(-)
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
```
|
||||
|
||||
Исправления и доработки:
|
||||
|
||||
- Исправление опечатки в имени переменной внутри `mdbx_env_turn_for_recovery()`,
|
||||
что приводило к неверному поведению в некоторых ситуациях.
|
||||
|
||||
С точки зрения пользователя, с учетом актуальных сценариев использования
|
||||
утилиты `mdbx_chk`, был только один специфический/редкий сценарий
|
||||
проявления ошибки/проблемы - когда выполнялась проверка и активация
|
||||
слабой/weak мета-страницы с НЕ-последней транзакцией после системной
|
||||
аварии машины, где БД использовалась в хрупком/небезопасном режиме.
|
||||
В сценарии, при успешной проверке целевой страницы и её последующей
|
||||
активации выводилось сообщение об ошибке, связанной со срабатыванием
|
||||
механизма контроля не-когерентности кэша файловой системы и отображенных
|
||||
в ОЗУ данных БД. При этом БД успешно восстанавливалось и не было
|
||||
каких-либо негативных последствия, кроме самого сообщения об ошибке.
|
||||
|
||||
Технически же ошибка проявлялась при "переключении" на мета-страницу,
|
||||
когда у хотя-бы одной из двух других мета-страниц номер транзакции был
|
||||
больше:
|
||||
|
||||
* Если содержимое других мета-страниц было корректным, а номера
|
||||
связанных транзакций были больше, то результирующий номер транзакции в
|
||||
целевой/активируемой мета-страницы устанавливается без учета этих
|
||||
мета-страниц и мог быть меньше-или-равным.
|
||||
|
||||
* В результате, если такие мета-страницы были в статусе слабых/weak, то
|
||||
при закрытии БД после переключения могла срабатывать защита от
|
||||
не-когерентности unified buffer/page cache, а в отладочных сборках могла
|
||||
срабатывать assert-проверка.
|
||||
|
||||
* Если же такие мета-страницы были в статусе сильных/steady, то
|
||||
переключение на новую мета-страницу могло не давать эффекта либо
|
||||
приводить к появлению двух мета-страниц с одинаковым номером транзакции,
|
||||
что является ошибочной ситуацией.
|
||||
|
||||
- Обходное решение проблем сборки посредством GCC с использование опций `-m32 -arch=i686 -Ofast`.
|
||||
Проблема обусловлена ошибкой GCC, из-за которой конструкция `__attribute__((__target__("sse2")))`
|
||||
не включает полноценное использование инструкций SSE и SSE2, если это не было сделано посредством
|
||||
опций командной строки, но была использована опция `-Ofast`. В результате сборка заканчивалась
|
||||
сообщением об ошибке:
|
||||
`error: inlining failed in call to 'always_inline' '_mm_movemask_ps': target specific option mismatch`
|
||||
|
||||
- Доработка режима "восстановления" БД и переключения на заданную мета-страницу:
|
||||
* Устранение обновления без необходимости мета-страницы с увеличением номера транзакции;
|
||||
* Устранение вывода (логирования) бессмысленного/лишнего предупреждения о пропуске обновления геометрии БД;
|
||||
* Более ожидаемое и безопасное поведение при проверке БД с указанием целевой мета-страницы в режиме чтения-записи.
|
||||
|
||||
Теперь при открытии БД посредством `mdbx_env_open_for_recovery()` не
|
||||
выполняется неявное изменение/обновление БД, в том числе при закрытии
|
||||
БД. Это позволяет обезопасить БД (снизить шанс её разрушения) если
|
||||
пользователь при попытке восстановления, либо просто в качестве
|
||||
эксперимента, задал утилите `mdbx_chk` неверную или опасную комбинацию
|
||||
параметров. При этом обычная проверка, как и явное переключение
|
||||
мета-страниц, работают по-прежнему.
|
||||
|
||||
Мелочи:
|
||||
|
||||
- Незначительное уточнение CMake-пробника для `std::filesystem`,
|
||||
проверяющего необходимость линковки с дополнительными библиотеками C++.
|
||||
- Устранение минорных предупреждений старых компиляторов в тестах.
|
||||
- Устранение причины ложно-позитивного предупреждения новых версий GCC в C++ API.
|
||||
- Исправление ссылки на репозиторий бенчмарка ioarena.
|
||||
- Добавление перекрестных ссылок в doxygen-документацию по C++ API.
|
||||
- Уточнение ограничений в разделе [Restrictions & Caveats](https://libmdbx.dqdkfa.ru/intro.html#restrictions).
|
||||
- Исправление ссылок на описание `mdbx_canary_put()`.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.12.6 "ЦСКА" от 2023-04-29
|
||||
|
||||
@@ -237,7 +524,7 @@ Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
|
||||
- Добавлен явный выбор `tls_model("local-dynamic")` для обхода проблемы
|
||||
`relocation R_X86_64_TPOFF32 against FOO cannot be used with -shared`
|
||||
из-за ошибки в CLANG приводящей к использованию неверного режима `ls_model`.
|
||||
из-за ошибки в CLANG приводящей к использованию неверного режима `tls_model`.
|
||||
|
||||
- Изменение тактики слияния страниц при удалении.
|
||||
Теперь слияние выполняется преимущественно с уже измененной/грязной страницей.
|
||||
@@ -354,7 +641,7 @@ Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
суммарный размер пары ключ-значение.
|
||||
|
||||
- Реализовано использование асинхронной (overlapped) записи в Windows,
|
||||
включая использования небуфферизированного ввода-вывода и `WriteGather()`.
|
||||
включая использования небуферизированного ввода-вывода и `WriteGather()`.
|
||||
Это позволяет сократить накладные расходы и частично обойти проблемы
|
||||
Windows с низкой производительностью ввода-вывода, включая большие
|
||||
задержки `FlushFileBuffers()`. Новый код также обеспечивает консолидацию
|
||||
@@ -483,7 +770,7 @@ New:
|
||||
- Added the `gcrtime_seconds16dot16` counter to the "Page Operation Statistics" that accumulates time spent for GC searching and reclaiming.
|
||||
- Copy-with-compactification now clears/zeroes unused gaps inside database pages.
|
||||
- The `C` and `C++` APIs has been extended and/or refined to simplify using `wchar_t` pathnames.
|
||||
On Windows the `mdbx_env_openW()`, ``mdbx_env_get_pathW()`()`, `mdbx_env_copyW()`, `mdbx_env_open_for_recoveryW()` are available for now,
|
||||
On Windows the `mdbx_env_openW()`, `mdbx_env_get_pathW()`, `mdbx_env_copyW()`, `mdbx_env_open_for_recoveryW()` are available for now,
|
||||
but the `mdbx_env_get_path()` has been replaced in favor of `mdbx_env_get_pathW()`.
|
||||
- Added explicit error message for Buildroot's Microblaze toolchain maintainers.
|
||||
- Added `MDBX_MANAGE_BUILD_FLAGS` build options for CMake.
|
||||
|
||||
@@ -277,7 +277,7 @@ the user's point of view.
|
||||
> and up to 30% faster when _libmdbx_ compiled with specific build options
|
||||
> which downgrades several runtime checks to be match with LMDB behaviour.
|
||||
>
|
||||
> These and other results could be easily reproduced with [ioArena](https://abf.io/erthink/ioarena.git) just by `make bench-quartet` command,
|
||||
> These and other results could be easily reproduced with [ioArena](https://abf.io/erthink/ioarena) just by `make bench-quartet` command,
|
||||
> including comparisons with [RockDB](https://en.wikipedia.org/wiki/RocksDB)
|
||||
> and [WiredTiger](https://en.wikipedia.org/wiki/WiredTiger).
|
||||
|
||||
@@ -659,7 +659,7 @@ Bindings
|
||||
Performance comparison
|
||||
======================
|
||||
|
||||
All benchmarks were done in 2015 by [IOArena](https://abf.io/erthink/ioarena.git)
|
||||
All benchmarks were done in 2015 by [IOArena](https://abf.io/erthink/ioarena)
|
||||
and multiple [scripts](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015)
|
||||
runs on Lenovo Carbon-2 laptop, i7-4600U 2.1 GHz (2 physical cores, 4 HyperThreading cores), 8 Gb RAM,
|
||||
SSD SAMSUNG MZNTD512HAGL-000L1 (DXT23L0Q) 512 Gb.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Copyright (c) 2012-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
## Copyright (c) 2012-2024 Leonid Yuriev <leo@yuriev.ru>.
|
||||
##
|
||||
## Licensed under the Apache License, Version 2.0 (the "License");
|
||||
## you may not use this file except in compliance with the License.
|
||||
@@ -1039,9 +1039,15 @@ macro(probe_libcxx_filesystem)
|
||||
#endif
|
||||
|
||||
int main(int argc, const char*argv[]) {
|
||||
fs::path probe(argv[0]);
|
||||
std::string str(argv[0]);
|
||||
fs::path probe(str);
|
||||
if (argc != 1) throw fs::filesystem_error(std::string("fake"), std::error_code());
|
||||
return fs::is_directory(probe.relative_path());
|
||||
int r = fs::is_directory(probe.relative_path());
|
||||
for (auto const& i : fs::directory_iterator(probe)) {
|
||||
++r;
|
||||
(void)i;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
]])
|
||||
set(LIBCXX_FILESYSTEM "")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Copyright (c) 2012-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
## Copyright (c) 2012-2024 Leonid Yuriev <leo@yuriev.ru>.
|
||||
##
|
||||
## Licensed under the Apache License, Version 2.0 (the "License");
|
||||
## you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Copyright (c) 2012-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
## Copyright (c) 2012-2024 Leonid Yuriev <leo@yuriev.ru>.
|
||||
##
|
||||
## Licensed under the Apache License, Version 2.0 (the "License");
|
||||
## you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -2224,14 +2224,24 @@ INCLUDE_FILE_PATTERNS =
|
||||
# recursively expanded use the := operator instead of the = operator.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
PREDEFINED = DOXYGEN MDBX_DECLARE_EXCEPTION \
|
||||
MDBX_NOTHROW_PURE_FUNCTION MDBX_PURE_FUNCTION \
|
||||
MDBX_NOTHROW_CONST_FUNCTION \
|
||||
MDBX_CXX01_CONSTEXPR MDBX_CXX01_CONSTEXPR_VAR \
|
||||
MDBX_CXX11_CONSTEXPR MDBX_CXX11_CONSTEXPR_VAR \
|
||||
MDBX_CXX14_CONSTEXPR MDBX_CXX14_CONSTEXPR_VAR \
|
||||
MDBX_CXX17_CONSTEXPR MDBX_CXX20_CONSTEXPR \
|
||||
MDBX_CXX17_NOEXCEPT
|
||||
|
||||
PREDEFINED = DOXYGEN \
|
||||
MDBX_CXX20_CONCEPT(CONCEPT,NAME)="CONCEPT NAME" \
|
||||
MDBX_STD_FILESYSTEM_PATH=::mdbx::filesystem::path \
|
||||
MDBX_U128_TYPE=uint128_t MDBX_I128_TYPE=int128_t \
|
||||
MDBX_DECLARE_EXCEPTION(NAME)="struct LIBMDBX_API_TYPE NAME : public exception{NAME(const ::mdbx::error &); virtual ~NAME() noexcept; }" \
|
||||
MDBX_PURE_FUNCTION=[[gnu::pure]] \
|
||||
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
|
||||
# tag can be used to specify a list of macro names that should be expanded. The
|
||||
|
||||
@@ -35,10 +35,11 @@ or debugging of a client application while retaining an active read
|
||||
transaction. LMDB this results in `MDB_MAP_FULL` error and subsequent write
|
||||
performance degradation.
|
||||
|
||||
MDBX mostly solve "long-lived" readers issue by using the Handle-Slow-Readers
|
||||
\ref MDBX_hsr_func callback which allows to abort long-lived read transactions,
|
||||
and using the \ref MDBX_LIFORECLAIM mode which addresses subsequent performance degradation.
|
||||
The "next" version of libmdbx (\ref MithrilDB) will completely solve this.
|
||||
MDBX mostly solve "long-lived" readers issue by using the
|
||||
Handle-Slow-Readers \ref MDBX_hsr_func callback which allows to abort
|
||||
long-lived read transactions, and using the \ref MDBX_LIFORECLAIM mode
|
||||
which addresses subsequent performance degradation. The "next" version
|
||||
of libmdbx (\ref MithrilDB) will completely solve this.
|
||||
|
||||
- Avoid suspending a process with active transactions. These would then be
|
||||
"long-lived" as above.
|
||||
@@ -80,6 +81,19 @@ list of pages to be retired.
|
||||
|
||||
Both of these issues will be addressed in MithrilDB.
|
||||
|
||||
#### Since v0.12.1 and later
|
||||
Some aspects related to GC have been refined and improved, in particular:
|
||||
|
||||
- The search for free consecutive/adjacent pages through GC has been
|
||||
significantly speeded, including acceleration using
|
||||
NOEN/SSE2/AVX2/AVX512 instructions.
|
||||
|
||||
- The `Big Foot` feature which significantly reduces GC overhead for
|
||||
processing large lists of retired pages from huge transactions. Now
|
||||
libmdbx avoid creating large chunks of PNLs (page number lists) which
|
||||
required a long sequences of free pages, aka large/overflow pages. Thus
|
||||
avoiding searching, allocating and storing such sequences inside GC.
|
||||
|
||||
|
||||
## Space reservation
|
||||
An MDBX database configuration will often reserve considerable unused
|
||||
@@ -87,6 +101,10 @@ memory address space and maybe file size for future growth. This does
|
||||
not use actual memory or disk space, but users may need to understand
|
||||
the difference so they won't be scared off.
|
||||
|
||||
However, on 64-bit systems with a relative small amount of RAM, such
|
||||
reservation can deplete system resources (trigger ENOMEM error, etc)
|
||||
when setting an inadequately large upper DB size using \ref
|
||||
mdbx_env_set_geometry() or \ref mdbx::env::geometry. So just avoid this.
|
||||
|
||||
## Remote filesystems
|
||||
Do not use MDBX databases on remote filesystems, even between processes
|
||||
|
||||
132
mdbx.h
132
mdbx.h
@@ -25,7 +25,7 @@ _The Future will (be) [Positive](https://www.ptsecurity.com). Всё будет
|
||||
|
||||
\section copyright LICENSE & COPYRIGHT
|
||||
|
||||
\authors Copyright (c) 2015-2023, Leonid Yuriev <leo@yuriev.ru>
|
||||
\authors Copyright (c) 2015-2024, Leonid Yuriev <leo@yuriev.ru>
|
||||
and other _libmdbx_ authors: please see [AUTHORS](./AUTHORS) file.
|
||||
|
||||
\copyright Redistribution and use in source and binary forms, with or without
|
||||
@@ -1876,7 +1876,8 @@ enum MDBX_error_t {
|
||||
MDBX_BAD_RSLOT = -30783,
|
||||
|
||||
/** 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,
|
||||
|
||||
/** Invalid size or alignment of key or data for target database,
|
||||
@@ -1936,7 +1937,7 @@ enum MDBX_error_t {
|
||||
MDBX_DUPLICATED_CLK = -30413,
|
||||
|
||||
/* 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)
|
||||
MDBX_ENODATA = ERROR_HANDLE_EOF,
|
||||
@@ -2118,7 +2119,8 @@ enum MDBX_option_t {
|
||||
* growth, or/and to the inability of put long values.
|
||||
*
|
||||
* The `MDBX_opt_rp_augment_limit` controls described limit for the current
|
||||
* process. Default is 262144, it is usually enough for most cases. */
|
||||
* process. By default this limit adjusted dynamically to 1/3 of current
|
||||
* quantity of DB pages, which is usually enough for most cases. */
|
||||
MDBX_opt_rp_augment_limit,
|
||||
|
||||
/** \brief Controls the in-process limit to grow a cache of dirty
|
||||
@@ -2351,7 +2353,6 @@ LIBMDBX_API int mdbx_env_get_option(const MDBX_env *env,
|
||||
* doesn't exist.
|
||||
* \retval MDBX_EACCES The user didn't have permission to access
|
||||
* the environment files.
|
||||
* \retval MDBX_EAGAIN The environment was locked by another process.
|
||||
* \retval MDBX_BUSY The \ref MDBX_EXCLUSIVE flag was specified and the
|
||||
* environment is in use by another process,
|
||||
* or the current process tries to open environment
|
||||
@@ -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
|
||||
* to disk, and 0 otherwise. Some possible errors are:
|
||||
*
|
||||
* \retval MDBX_EACCES the environment is read-only.
|
||||
* \retval MDBX_BUSY the environment is used by other thread
|
||||
* \retval MDBX_EACCES The environment is read-only.
|
||||
* \retval MDBX_BUSY The environment is used by other thread
|
||||
* and `nonblock=true`.
|
||||
* \retval MDBX_EINVAL an invalid parameter was specified.
|
||||
* \retval MDBX_EIO an error occurred during synchronization. */
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified.
|
||||
* \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);
|
||||
|
||||
/** \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,
|
||||
* and cursors must already be closed before calling this function. Attempts
|
||||
* to use any such handles after calling this function will cause a `SIGSEGV`.
|
||||
* The environment handle will be freed and must not be used again after this
|
||||
* call.
|
||||
* to use any such handles after calling this function is UB and would cause
|
||||
* a `SIGSEGV`. The environment handle will be freed and must not be used again
|
||||
* after this call.
|
||||
*
|
||||
* \param [in] env An environment handle returned by
|
||||
* \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
|
||||
* 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);
|
||||
|
||||
/** \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.
|
||||
* \retval MDBX_EINVAL Transaction handle is NULL.
|
||||
* \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. */
|
||||
LIBMDBX_INLINE_API(int, mdbx_txn_commit, (MDBX_txn * txn)) {
|
||||
return mdbx_txn_commit_ex(txn, NULL);
|
||||
@@ -4031,7 +4035,7 @@ LIBMDBX_API int mdbx_txn_renew(MDBX_txn *txn);
|
||||
/** \brief The fours integers markers (aka "canary") associated with the
|
||||
* environment.
|
||||
* \ingroup c_crud
|
||||
* \see mdbx_canary_set()
|
||||
* \see mdbx_canary_put()
|
||||
* \see mdbx_canary_get()
|
||||
*
|
||||
* The `x`, `y` and `z` values could be set by \ref mdbx_canary_put(), while the
|
||||
@@ -4069,10 +4073,10 @@ LIBMDBX_API int mdbx_canary_put(MDBX_txn *txn, const MDBX_canary *canary);
|
||||
/** \brief Returns fours integers markers (aka "canary") associated with the
|
||||
* environment.
|
||||
* \ingroup c_crud
|
||||
* \see mdbx_canary_set()
|
||||
* \see mdbx_canary_put()
|
||||
*
|
||||
* \param [in] txn A transaction handle returned by \ref mdbx_txn_begin().
|
||||
* \param [in] canary The address of an MDBX_canary structure where the
|
||||
* \param [in] canary The address of an \ref MDBX_canary structure where the
|
||||
* information will be copied.
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success. */
|
||||
@@ -4084,9 +4088,9 @@ LIBMDBX_API int mdbx_canary_get(const MDBX_txn *txn, MDBX_canary *canary);
|
||||
* \see mdbx_get_datacmp \see mdbx_dcmp()
|
||||
*
|
||||
* \anchor avoid_custom_comparators
|
||||
* It is recommend not using custom comparison functions, but instead
|
||||
* converting the keys to one of the forms that are suitable for built-in
|
||||
* comparators (for instance take look to the \ref value2key).
|
||||
* \deprecated It is recommend not using custom comparison functions, but
|
||||
* instead converting the keys to one of the forms that are suitable for
|
||||
* built-in comparators (for instance take look to the \ref value2key).
|
||||
* The reasons to not using custom comparators are:
|
||||
* - The order of records could not be validated without your code.
|
||||
* So `mdbx_chk` utility will reports "wrong order" errors
|
||||
@@ -4289,8 +4293,8 @@ mdbx_int64_from_key(const MDBX_val);
|
||||
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned
|
||||
* by current thread.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *stat,
|
||||
size_t bytes);
|
||||
LIBMDBX_API int mdbx_dbi_stat(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||
MDBX_stat *stat, size_t bytes);
|
||||
|
||||
/** \brief Retrieve depth (bitmask) information of nested dupsort (multi-value)
|
||||
* B+trees for given database.
|
||||
@@ -4307,7 +4311,7 @@ LIBMDBX_API int mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *stat,
|
||||
* by current thread.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified.
|
||||
* \retval MDBX_RESULT_TRUE The dbi isn't a dupsort (multi-value) database. */
|
||||
LIBMDBX_API int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi,
|
||||
LIBMDBX_API int mdbx_dbi_dupsort_depthmask(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||
uint32_t *mask);
|
||||
|
||||
/** \brief DBI state bits returted by \ref mdbx_dbi_flags_ex()
|
||||
@@ -4316,7 +4320,7 @@ LIBMDBX_API int mdbx_dbi_dupsort_depthmask(MDBX_txn *txn, MDBX_dbi dbi,
|
||||
enum MDBX_dbi_state_t {
|
||||
/** DB was written in this txn */
|
||||
MDBX_DBI_DIRTY = 0x01,
|
||||
/** Named-DB record is older than txnID */
|
||||
/** Cached Named-DB record is older than txnID */
|
||||
MDBX_DBI_STALE = 0x02,
|
||||
/** Named-DB handle opened in this txn */
|
||||
MDBX_DBI_FRESH = 0x04,
|
||||
@@ -4339,13 +4343,13 @@ DEFINE_ENUM_FLAG_OPERATORS(MDBX_dbi_state_t)
|
||||
* \param [out] state Address where the state will be returned.
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success. */
|
||||
LIBMDBX_API int mdbx_dbi_flags_ex(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags,
|
||||
unsigned *state);
|
||||
LIBMDBX_API int mdbx_dbi_flags_ex(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||
unsigned *flags, unsigned *state);
|
||||
/** \brief The shortcut to calling \ref mdbx_dbi_flags_ex() with `state=NULL`
|
||||
* for discarding it result.
|
||||
* \ingroup c_statinfo */
|
||||
LIBMDBX_INLINE_API(int, mdbx_dbi_flags,
|
||||
(MDBX_txn * txn, MDBX_dbi dbi, unsigned *flags)) {
|
||||
(const MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags)) {
|
||||
unsigned state;
|
||||
return mdbx_dbi_flags_ex(txn, dbi, flags, &state);
|
||||
}
|
||||
@@ -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().
|
||||
*
|
||||
* \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
|
||||
* modify it in any way. For values returned in a read-only transaction
|
||||
* any modification attempts will cause a `SIGSEGV`.
|
||||
* 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.
|
||||
*
|
||||
* \note Values returned from the database are valid only until a
|
||||
* subsequent update operation, or the end of the transaction.
|
||||
@@ -4416,7 +4425,7 @@ LIBMDBX_API int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, bool del);
|
||||
* by current thread.
|
||||
* \retval MDBX_NOTFOUND The key was not in the database.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
||||
LIBMDBX_API int mdbx_get(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
||||
MDBX_val *data);
|
||||
|
||||
/** \brief Get items from a database
|
||||
@@ -4449,7 +4458,7 @@ LIBMDBX_API int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
|
||||
* by current thread.
|
||||
* \retval MDBX_NOTFOUND The key was not in the database.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
LIBMDBX_API int mdbx_get_ex(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
MDBX_val *data, size_t *values_count);
|
||||
|
||||
/** \brief Get equal or great item from a database.
|
||||
@@ -4480,7 +4489,7 @@ LIBMDBX_API int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
* by current thread.
|
||||
* \retval MDBX_NOTFOUND The key was not in the database.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_get_equal_or_great(MDBX_txn *txn, MDBX_dbi dbi,
|
||||
LIBMDBX_API int mdbx_get_equal_or_great(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||
MDBX_val *key, MDBX_val *data);
|
||||
|
||||
/** \brief Store items into a database.
|
||||
@@ -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,
|
||||
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
|
||||
*
|
||||
* 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. */
|
||||
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
|
||||
* \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_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
|
||||
*
|
||||
* 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
|
||||
* the same database handle as it was created with. This may be done whether the
|
||||
@@ -4715,14 +4724,14 @@ mdbx_cursor_get_userctx(const MDBX_cursor *cursor);
|
||||
*
|
||||
* \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 [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,
|
||||
* some possible errors are:
|
||||
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned
|
||||
* by current thread.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *cursor,
|
||||
LIBMDBX_API int mdbx_cursor_bind(const MDBX_txn *txn, MDBX_cursor *cursor,
|
||||
MDBX_dbi dbi);
|
||||
|
||||
/** \brief Create a cursor handle for the specified transaction and DBI handle.
|
||||
@@ -4755,7 +4764,7 @@ LIBMDBX_API int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *cursor,
|
||||
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned
|
||||
* by current thread.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi,
|
||||
LIBMDBX_API int mdbx_cursor_open(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||
MDBX_cursor **cursor);
|
||||
|
||||
/** \brief Close a cursor handle.
|
||||
@@ -4774,15 +4783,14 @@ LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi,
|
||||
* or \ref mdbx_cursor_create(). */
|
||||
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
|
||||
*
|
||||
* The 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
|
||||
* previous transaction is live or dead.
|
||||
* A cursor may be associated with a new transaction whether the previous
|
||||
* transaction is running or finished.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \note In contrast to LMDB, the MDBX allow any cursor to be re-used by using
|
||||
@@ -4796,8 +4804,10 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor);
|
||||
* some possible errors are:
|
||||
* \retval MDBX_THREAD_MISMATCH Given transaction is not owned
|
||||
* by current thread.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor);
|
||||
* \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(const MDBX_txn *txn, MDBX_cursor *cursor);
|
||||
|
||||
/** \brief Return the cursor's transaction handle.
|
||||
* \ingroup c_cursors
|
||||
@@ -4834,6 +4844,16 @@ LIBMDBX_API int mdbx_cursor_copy(const MDBX_cursor *src, MDBX_cursor *dest);
|
||||
* to which data refers.
|
||||
* \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,out] key The key for 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.
|
||||
* \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 [out] count The number of key and value item returned, on success
|
||||
* it always be the even because the key-value
|
||||
@@ -5156,9 +5186,11 @@ LIBMDBX_API int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key,
|
||||
* \param [out] distance_items A pointer to store range estimation result.
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success. */
|
||||
LIBMDBX_API int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi,
|
||||
MDBX_val *begin_key, MDBX_val *begin_data,
|
||||
MDBX_val *end_key, MDBX_val *end_data,
|
||||
LIBMDBX_API int mdbx_estimate_range(const MDBX_txn *txn, MDBX_dbi dbi,
|
||||
const MDBX_val *begin_key,
|
||||
const MDBX_val *begin_data,
|
||||
const MDBX_val *end_key,
|
||||
const MDBX_val *end_data,
|
||||
ptrdiff_t *distance_items);
|
||||
|
||||
/** \brief The EPSILON value for mdbx_estimate_range()
|
||||
|
||||
377
mdbx.h++
377
mdbx.h++
@@ -1,7 +1,7 @@
|
||||
/// \file mdbx.h++
|
||||
/// \brief The libmdbx C++ API header file.
|
||||
///
|
||||
/// \author Copyright (c) 2020-2023, Leonid Yuriev <leo@yuriev.ru>.
|
||||
/// \author Copyright (c) 2020-2024, Leonid Yuriev <leo@yuriev.ru>.
|
||||
/// \copyright SPDX-License-Identifier: Apache-2.0
|
||||
///
|
||||
/// Tested with:
|
||||
@@ -80,7 +80,8 @@
|
||||
|
||||
#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L
|
||||
#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>
|
||||
#endif
|
||||
|
||||
@@ -361,13 +362,17 @@ using default_allocator = polymorphic_allocator;
|
||||
using default_allocator = legacy_allocator;
|
||||
#endif /* __cpp_lib_memory_resource >= 201603L */
|
||||
|
||||
/// \brief Default singe-byte string.
|
||||
template <class ALLOCATOR = legacy_allocator>
|
||||
/// \brief Default buffer.
|
||||
using default_buffer = buffer<default_allocator, default_capacity_policy>;
|
||||
|
||||
/// \brief Default single-byte string.
|
||||
template <class ALLOCATOR = default_allocator>
|
||||
using string = ::std::basic_string<char, ::std::char_traits<char>, ALLOCATOR>;
|
||||
|
||||
using filehandle = ::mdbx_filehandle_t;
|
||||
#if defined(DOXYGEN) || \
|
||||
(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) || \
|
||||
__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) && \
|
||||
(!defined(__IPHONE_OS_VERSION_MIN_REQUIRED) || \
|
||||
@@ -394,6 +399,16 @@ using path = ::std::wstring;
|
||||
using path = ::std::string;
|
||||
#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)
|
||||
/// \brief Duration in 1/65536 units of second.
|
||||
using duration = ::std::chrono::duration<unsigned, ::std::ratio<1, 65536>>;
|
||||
@@ -546,12 +561,14 @@ MDBX_DECLARE_EXCEPTION(something_busy);
|
||||
MDBX_DECLARE_EXCEPTION(thread_mismatch);
|
||||
MDBX_DECLARE_EXCEPTION(transaction_full);
|
||||
MDBX_DECLARE_EXCEPTION(transaction_overlapping);
|
||||
MDBX_DECLARE_EXCEPTION(duplicated_lck_file);
|
||||
#undef MDBX_DECLARE_EXCEPTION
|
||||
|
||||
[[noreturn]] LIBMDBX_API void throw_too_small_target_buffer();
|
||||
[[noreturn]] LIBMDBX_API void throw_max_length_exceeded();
|
||||
[[noreturn]] LIBMDBX_API void throw_out_range();
|
||||
[[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 headroom,
|
||||
size_t payload);
|
||||
@@ -719,6 +736,8 @@ struct LIBMDBX_API_TYPE slice : public ::MDBX_val {
|
||||
slice &operator=(const slice &) noexcept = default;
|
||||
inline slice &operator=(slice &&src) noexcept;
|
||||
inline slice &operator=(::MDBX_val &&src);
|
||||
operator MDBX_val *() noexcept { return this; }
|
||||
operator const MDBX_val *() const noexcept { return this; }
|
||||
|
||||
#if defined(DOXYGEN) || \
|
||||
(defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L)
|
||||
@@ -1029,6 +1048,35 @@ struct LIBMDBX_API_TYPE slice : public ::MDBX_val {
|
||||
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:
|
||||
MDBX_CXX11_CONSTEXPR slice(size_t invalid_length) noexcept
|
||||
: ::MDBX_val({nullptr, invalid_length}) {}
|
||||
@@ -1279,8 +1327,7 @@ struct LIBMDBX_API to_base58 {
|
||||
/// \brief Returns the buffer size in bytes needed for
|
||||
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump of passed slice.
|
||||
MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept {
|
||||
const size_t bytes =
|
||||
source.length() / 8 * 11 + (source.length() % 8 * 43 + 31) / 32;
|
||||
const size_t bytes = (source.length() * 11 + 7) / 8;
|
||||
return wrap_width ? bytes + bytes / wrap_width : bytes;
|
||||
}
|
||||
|
||||
@@ -1445,7 +1492,7 @@ struct LIBMDBX_API from_base58 {
|
||||
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump from a passed slice to
|
||||
/// decoded data.
|
||||
MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept {
|
||||
return source.length() / 11 * 8 + source.length() % 11 * 32 / 43;
|
||||
return source.length() /* могут быть все нули кодируемые один-к-одному */;
|
||||
}
|
||||
|
||||
/// \brief Fills the destination with data decoded from
|
||||
@@ -1533,10 +1580,6 @@ public:
|
||||
private:
|
||||
friend class txn;
|
||||
struct silo;
|
||||
using move_assign_alloc =
|
||||
allocation_aware_details::move_assign_alloc<silo, allocator_type>;
|
||||
using copy_assign_alloc =
|
||||
allocation_aware_details::copy_assign_alloc<silo, allocator_type>;
|
||||
using swap_alloc = allocation_aware_details::swap_alloc<silo, allocator_type>;
|
||||
struct silo /* Empty Base Class Optimization */ : public allocator_type {
|
||||
MDBX_CXX20_CONSTEXPR const allocator_type &get_allocator() const noexcept {
|
||||
@@ -2028,6 +2071,11 @@ public:
|
||||
/// \todo buffer& operator>>(buffer&, ...) for reading (delegated to slice)
|
||||
/// \todo template<class X> key(X) for encoding keys while writing
|
||||
|
||||
using move_assign_alloc =
|
||||
allocation_aware_details::move_assign_alloc<silo, allocator_type>;
|
||||
using copy_assign_alloc =
|
||||
allocation_aware_details::copy_assign_alloc<silo, allocator_type>;
|
||||
|
||||
/// \brief Returns the associated allocator.
|
||||
MDBX_CXX20_CONSTEXPR allocator_type get_allocator() const {
|
||||
return silo_.get_allocator();
|
||||
@@ -2292,6 +2340,130 @@ public:
|
||||
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 Returns a new buffer with a hexadecimal dump of the slice content.
|
||||
static buffer hex(const ::mdbx::slice &source, bool uppercase = false,
|
||||
unsigned wrap_width = 0,
|
||||
const allocator_type &allocator = allocator_type()) {
|
||||
return source.template encode_hex<ALLOCATOR, CAPACITY_POLICY>(
|
||||
uppercase, wrap_width, allocator);
|
||||
}
|
||||
|
||||
/// \brief Returns a new buffer with a
|
||||
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump of the slice content.
|
||||
static buffer base58(const ::mdbx::slice &source, unsigned wrap_width = 0,
|
||||
const allocator_type &allocator = allocator_type()) {
|
||||
return source.template encode_base58<ALLOCATOR, CAPACITY_POLICY>(wrap_width,
|
||||
allocator);
|
||||
}
|
||||
/// \brief Returns a new buffer with a
|
||||
/// [Base64](https://en.wikipedia.org/wiki/Base64) dump of the slice content.
|
||||
static buffer base64(const ::mdbx::slice &source, unsigned wrap_width = 0,
|
||||
const allocator_type &allocator = allocator_type()) {
|
||||
return source.template encode_base64<ALLOCATOR, CAPACITY_POLICY>(wrap_width,
|
||||
allocator);
|
||||
}
|
||||
|
||||
/// \brief Returns a new buffer with a hexadecimal dump of the given pod.
|
||||
template <typename POD>
|
||||
static buffer hex(const POD &pod, bool uppercase = false,
|
||||
unsigned wrap_width = 0,
|
||||
const allocator_type &allocator = allocator_type()) {
|
||||
return hex(mdbx::slice::wrap(pod), uppercase, wrap_width, allocator);
|
||||
}
|
||||
|
||||
/// \brief Returns a new buffer with a
|
||||
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump of the given pod.
|
||||
template <typename POD>
|
||||
static buffer base58(const POD &pod, unsigned wrap_width = 0,
|
||||
const allocator_type &allocator = allocator_type()) {
|
||||
return base58(mdbx::slice::wrap(pod), wrap_width, allocator);
|
||||
}
|
||||
|
||||
/// \brief Returns a new buffer with a
|
||||
/// [Base64](https://en.wikipedia.org/wiki/Base64) dump of the given pod.
|
||||
template <typename POD>
|
||||
static buffer base64(const POD &pod, unsigned wrap_width = 0,
|
||||
const allocator_type &allocator = allocator_type()) {
|
||||
return base64(mdbx::slice::wrap(pod), wrap_width, allocator);
|
||||
}
|
||||
|
||||
/// \brief Returns a new buffer with a hexadecimal dump of the slice content.
|
||||
buffer encode_hex(bool uppercase = false, unsigned wrap_width = 0,
|
||||
const allocator_type &allocator = allocator_type()) const {
|
||||
return slice().template encode_hex<ALLOCATOR, CAPACITY_POLICY>(
|
||||
uppercase, wrap_width, allocator);
|
||||
}
|
||||
|
||||
/// \brief Returns a new buffer with a
|
||||
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump of the slice content.
|
||||
buffer
|
||||
encode_base58(unsigned wrap_width = 0,
|
||||
const allocator_type &allocator = allocator_type()) const {
|
||||
return slice().template encode_base58<ALLOCATOR, CAPACITY_POLICY>(
|
||||
wrap_width, allocator);
|
||||
}
|
||||
/// \brief Returns a new buffer with a
|
||||
/// [Base64](https://en.wikipedia.org/wiki/Base64) dump of the slice content.
|
||||
buffer
|
||||
encode_base64(unsigned wrap_width = 0,
|
||||
const allocator_type &allocator = allocator_type()) const {
|
||||
return slice().template encode_base64<ALLOCATOR, CAPACITY_POLICY>(
|
||||
wrap_width, allocator);
|
||||
}
|
||||
|
||||
/// \brief Decodes hexadecimal dump from the slice content to returned buffer.
|
||||
static buffer hex_decode(const ::mdbx::slice &source,
|
||||
bool ignore_spaces = false,
|
||||
const allocator_type &allocator = allocator_type()) {
|
||||
return source.template hex_decode<ALLOCATOR, CAPACITY_POLICY>(ignore_spaces,
|
||||
allocator);
|
||||
}
|
||||
|
||||
/// \brief Decodes [Base58](https://en.wikipedia.org/wiki/Base58) dump
|
||||
/// from the slice content to returned buffer.
|
||||
static buffer
|
||||
base58_decode(const ::mdbx::slice &source, bool ignore_spaces = false,
|
||||
const allocator_type &allocator = allocator_type()) {
|
||||
return source.template base58_decode<ALLOCATOR, CAPACITY_POLICY>(
|
||||
ignore_spaces, allocator);
|
||||
}
|
||||
|
||||
/// \brief Decodes [Base64](https://en.wikipedia.org/wiki/Base64) dump
|
||||
/// from the slice content to returned buffer.
|
||||
static buffer
|
||||
base64_decode(const ::mdbx::slice &source, bool ignore_spaces = false,
|
||||
const allocator_type &allocator = allocator_type()) {
|
||||
return source.template base64_decode<ALLOCATOR, CAPACITY_POLICY>(
|
||||
ignore_spaces, allocator);
|
||||
}
|
||||
|
||||
/// \brief Decodes hexadecimal dump
|
||||
/// from the buffer content to new returned buffer.
|
||||
buffer hex_decode(bool ignore_spaces = false,
|
||||
const allocator_type &allocator = allocator_type()) const {
|
||||
return hex_decode(slice(), ignore_spaces, allocator);
|
||||
}
|
||||
|
||||
/// \brief Decodes [Base58](https://en.wikipedia.org/wiki/Base58) dump
|
||||
/// from the buffer content to new returned buffer.
|
||||
buffer
|
||||
base58_decode(bool ignore_spaces = false,
|
||||
const allocator_type &allocator = allocator_type()) const {
|
||||
return base58_decode(slice(), ignore_spaces, allocator);
|
||||
}
|
||||
|
||||
/// \brief Decodes [Base64](https://en.wikipedia.org/wiki/Base64) dump
|
||||
/// from the buffer content to new returned buffer.
|
||||
buffer
|
||||
base64_decode(bool ignore_spaces = false,
|
||||
const allocator_type &allocator = allocator_type()) const {
|
||||
return base64_decode(slice(), ignore_spaces, allocator);
|
||||
}
|
||||
|
||||
/// \brief Reserves storage space.
|
||||
void reserve(size_t wanna_headroom, size_t wanna_tailroom) {
|
||||
wanna_headroom = ::std::min(::std::max(headroom(), wanna_headroom),
|
||||
@@ -2936,6 +3108,7 @@ struct LIBMDBX_API_TYPE map_handle {
|
||||
map_handle(const map_handle &) noexcept = default;
|
||||
map_handle &operator=(const map_handle &) noexcept = default;
|
||||
operator bool() const noexcept { return dbi != 0; }
|
||||
operator MDBX_dbi() const { return dbi; }
|
||||
|
||||
using flags = ::MDBX_db_flags_t;
|
||||
using state = ::MDBX_dbi_state_t;
|
||||
@@ -2961,6 +3134,14 @@ struct LIBMDBX_API_TYPE map_handle {
|
||||
};
|
||||
};
|
||||
|
||||
using comparator = ::MDBX_cmp_func *;
|
||||
inline comparator default_comparator(key_mode mode) noexcept {
|
||||
return ::mdbx_get_keycmp(static_cast<MDBX_db_flags_t>(mode));
|
||||
}
|
||||
inline comparator default_comparator(value_mode mode) noexcept {
|
||||
return ::mdbx_get_keycmp(static_cast<MDBX_db_flags_t>(mode));
|
||||
}
|
||||
|
||||
/// \brief Key-value pairs put mode.
|
||||
enum put_mode {
|
||||
insert_unique = MDBX_NOOVERWRITE, ///< Insert only unique keys.
|
||||
@@ -3000,7 +3181,11 @@ public:
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/// Database geometry for size management.
|
||||
/// \brief Database geometry for size management.
|
||||
/// \see env_managed::create_parameters
|
||||
/// \see env_managed::env_managed(const ::std::string &pathname, const
|
||||
/// create_parameters &, const operate_parameters &, bool accede)
|
||||
|
||||
struct LIBMDBX_API_TYPE geometry {
|
||||
enum : int64_t {
|
||||
default_value = -1, ///< Means "keep current or use default"
|
||||
@@ -3394,7 +3579,7 @@ public:
|
||||
inline void *get_context() const noexcept;
|
||||
|
||||
/// \brief Sets the application context associated with the environment.
|
||||
inline env &set_context(void *);
|
||||
inline env &set_context(void *your_context);
|
||||
|
||||
/// \brief Sets threshold to force flush the data buffers to disk, for
|
||||
/// non-sync durability modes.
|
||||
@@ -3659,6 +3844,8 @@ public:
|
||||
bool accede = true);
|
||||
|
||||
/// \brief Additional parameters for creating a new database.
|
||||
/// \see env_managed(const ::std::string &pathname, const create_parameters &,
|
||||
/// const operate_parameters &, bool accede)
|
||||
struct create_parameters {
|
||||
env::geometry geometry;
|
||||
mdbx_mode_t file_mode_bits{0640};
|
||||
@@ -3750,6 +3937,12 @@ public:
|
||||
/// \brief Return the transaction's ID.
|
||||
inline uint64_t id() const;
|
||||
|
||||
/// \brief Returns the application context associated with the transaction.
|
||||
inline void *get_context() const noexcept;
|
||||
|
||||
/// \brief Sets the application context associated with the transaction.
|
||||
inline txn &set_context(void *your_context);
|
||||
|
||||
/// \brief Checks whether the given data is on a dirty page.
|
||||
inline bool is_dirty(const void *ptr) const;
|
||||
|
||||
@@ -3786,7 +3979,7 @@ public:
|
||||
txn_managed start_nested();
|
||||
|
||||
/// \brief Opens cursor for specified key-value map handle.
|
||||
inline cursor_managed open_cursor(map_handle map);
|
||||
inline cursor_managed open_cursor(map_handle map) const;
|
||||
|
||||
/// \brief Open existing key-value map.
|
||||
inline map_handle open_map(
|
||||
@@ -3969,16 +4162,28 @@ public:
|
||||
size_t values_count, put_mode mode,
|
||||
bool allow_partial = false);
|
||||
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,
|
||||
const ::std::vector<VALUE> &vector, put_mode mode) {
|
||||
put_multiple(map, key, sizeof(VALUE), vector.data(), vector.size(), mode,
|
||||
false);
|
||||
put_multiple(map, key, vector.data(), vector.size(), mode);
|
||||
}
|
||||
|
||||
inline ptrdiff_t estimate(map_handle map, pair from, pair to) const;
|
||||
inline ptrdiff_t estimate(map_handle map, slice from, slice to) const;
|
||||
inline ptrdiff_t estimate_from_first(map_handle map, slice to) const;
|
||||
inline ptrdiff_t estimate_to_last(map_handle map, slice from) const;
|
||||
inline ptrdiff_t estimate(map_handle map, const pair &from,
|
||||
const pair &to) const;
|
||||
inline ptrdiff_t estimate(map_handle map, const slice &from,
|
||||
const slice &to) const;
|
||||
inline ptrdiff_t estimate_from_first(map_handle map, const slice &to) const;
|
||||
inline ptrdiff_t estimate_to_last(map_handle map, const slice &from) const;
|
||||
};
|
||||
|
||||
/// \brief Managed database transaction.
|
||||
@@ -4059,6 +4264,7 @@ public:
|
||||
inline cursor &operator=(cursor &&other) noexcept;
|
||||
inline cursor(cursor &&other) noexcept;
|
||||
inline ~cursor() noexcept;
|
||||
inline cursor_managed clone(void *your_context = nullptr) const;
|
||||
MDBX_CXX14_CONSTEXPR operator bool() const noexcept;
|
||||
MDBX_CXX14_CONSTEXPR operator const MDBX_cursor *() const;
|
||||
MDBX_CXX14_CONSTEXPR operator MDBX_cursor *();
|
||||
@@ -4067,6 +4273,12 @@ public:
|
||||
friend MDBX_CXX11_CONSTEXPR bool operator!=(const cursor &a,
|
||||
const cursor &b) noexcept;
|
||||
|
||||
/// \brief Returns the application context associated with the cursor.
|
||||
inline void *get_context() const noexcept;
|
||||
|
||||
/// \brief Sets the application context associated with the cursor.
|
||||
inline cursor &set_context(void *your_context);
|
||||
|
||||
enum move_operation {
|
||||
first = MDBX_FIRST,
|
||||
last = MDBX_LAST,
|
||||
@@ -4091,10 +4303,13 @@ public:
|
||||
|
||||
struct move_result : public pair_result {
|
||||
inline move_result(const cursor &cursor, bool throw_notfound);
|
||||
inline move_result(cursor &cursor, move_operation operation,
|
||||
bool throw_notfound);
|
||||
inline move_result(cursor &cursor, move_operation operation,
|
||||
const slice &key, bool throw_notfound);
|
||||
move_result(cursor &cursor, move_operation operation, bool throw_notfound)
|
||||
: move_result(cursor, operation, slice::invalid(), slice::invalid(),
|
||||
throw_notfound) {}
|
||||
move_result(cursor &cursor, move_operation operation, const slice &key,
|
||||
bool throw_notfound)
|
||||
: move_result(cursor, operation, key, slice::invalid(),
|
||||
throw_notfound) {}
|
||||
inline move_result(cursor &cursor, move_operation operation,
|
||||
const slice &key, const slice &value,
|
||||
bool throw_notfound);
|
||||
@@ -4102,6 +4317,20 @@ public:
|
||||
move_result &operator=(const move_result &) noexcept = default;
|
||||
};
|
||||
|
||||
struct estimate_result : public pair {
|
||||
ptrdiff_t approximate_quantity;
|
||||
estimate_result(const cursor &cursor, move_operation operation)
|
||||
: estimate_result(cursor, operation, slice::invalid(),
|
||||
slice::invalid()) {}
|
||||
estimate_result(const cursor &cursor, move_operation operation,
|
||||
const slice &key)
|
||||
: estimate_result(cursor, operation, key, slice::invalid()) {}
|
||||
inline estimate_result(const cursor &cursor, move_operation operation,
|
||||
const slice &key, const slice &value);
|
||||
estimate_result(const estimate_result &) noexcept = default;
|
||||
estimate_result &operator=(const estimate_result &) noexcept = default;
|
||||
};
|
||||
|
||||
protected:
|
||||
inline bool move(move_operation operation, MDBX_val *key, MDBX_val *value,
|
||||
bool throw_notfound) const
|
||||
@@ -4146,19 +4375,20 @@ public:
|
||||
inline bool eof() const;
|
||||
inline bool on_first() const;
|
||||
inline bool on_last() const;
|
||||
inline ptrdiff_t estimate(slice key, slice value) const;
|
||||
inline ptrdiff_t estimate(slice key) const;
|
||||
inline ptrdiff_t estimate(move_operation operation) const;
|
||||
inline estimate_result estimate(const slice &key, const slice &value) const;
|
||||
inline estimate_result estimate(const slice &key) const;
|
||||
inline estimate_result estimate(move_operation operation) const;
|
||||
inline estimate_result estimate(move_operation operation, slice &key) const;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/// \brief Renew/bind a cursor with a new transaction and previously used
|
||||
/// key-value map handle.
|
||||
inline void renew(::mdbx::txn &txn);
|
||||
inline void renew(const ::mdbx::txn &txn);
|
||||
|
||||
/// \brief Bind/renew a cursor with a new transaction and specified key-value
|
||||
/// map handle.
|
||||
inline void bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle);
|
||||
inline void bind(const ::mdbx::txn &txn, ::mdbx::map_handle map_handle);
|
||||
|
||||
/// \brief Returns the cursor's transaction.
|
||||
inline ::mdbx::txn txn() const;
|
||||
@@ -4212,7 +4442,8 @@ class LIBMDBX_API_TYPE cursor_managed : public cursor {
|
||||
|
||||
public:
|
||||
/// \brief Creates a new managed cursor with underlying object.
|
||||
cursor_managed() : cursor_managed(::mdbx_cursor_create(nullptr)) {
|
||||
cursor_managed(void *your_context = nullptr)
|
||||
: cursor_managed(::mdbx_cursor_create(your_context)) {
|
||||
if (MDBX_UNLIKELY(!handle_))
|
||||
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_ENOMEM);
|
||||
}
|
||||
@@ -5134,7 +5365,7 @@ inline filehandle env::get_filehandle() const {
|
||||
}
|
||||
|
||||
inline MDBX_env_flags_t env::get_flags() const {
|
||||
unsigned bits;
|
||||
unsigned bits = 0;
|
||||
error::success_or_throw(::mdbx_env_get_flags(handle_, &bits));
|
||||
return MDBX_env_flags_t(bits);
|
||||
}
|
||||
@@ -5354,6 +5585,15 @@ MDBX_CXX11_CONSTEXPR bool operator!=(const txn &a, const txn &b) noexcept {
|
||||
return a.handle_ != b.handle_;
|
||||
}
|
||||
|
||||
inline void *txn::get_context() const noexcept {
|
||||
return mdbx_txn_get_userctx(handle_);
|
||||
}
|
||||
|
||||
inline txn &txn::set_context(void *ptr) {
|
||||
error::success_or_throw(::mdbx_txn_set_userctx(handle_, ptr));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool txn::is_dirty(const void *ptr) const {
|
||||
int err = ::mdbx_is_dirty(handle_, ptr);
|
||||
switch (err) {
|
||||
@@ -5394,7 +5634,7 @@ inline txn::info txn::get_info(bool scan_reader_lock_table) const {
|
||||
return r;
|
||||
}
|
||||
|
||||
inline cursor_managed txn::open_cursor(map_handle map) {
|
||||
inline cursor_managed txn::open_cursor(map_handle map) const {
|
||||
MDBX_cursor *ptr;
|
||||
error::success_or_throw(::mdbx_cursor_open(handle_, map.dbi, &ptr));
|
||||
return cursor_managed(ptr);
|
||||
@@ -5792,28 +6032,32 @@ inline size_t txn::put_multiple(map_handle map, const slice &key,
|
||||
return args[1].iov_len /* done item count */;
|
||||
}
|
||||
|
||||
inline ptrdiff_t txn::estimate(map_handle map, pair from, pair to) const {
|
||||
inline ptrdiff_t txn::estimate(map_handle map, const pair &from,
|
||||
const pair &to) const {
|
||||
ptrdiff_t result;
|
||||
error::success_or_throw(mdbx_estimate_range(
|
||||
handle_, map.dbi, &from.key, &from.value, &to.key, &to.value, &result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline ptrdiff_t txn::estimate(map_handle map, slice from, slice to) const {
|
||||
inline ptrdiff_t txn::estimate(map_handle map, const slice &from,
|
||||
const slice &to) const {
|
||||
ptrdiff_t result;
|
||||
error::success_or_throw(mdbx_estimate_range(handle_, map.dbi, &from, nullptr,
|
||||
&to, nullptr, &result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline ptrdiff_t txn::estimate_from_first(map_handle map, slice to) const {
|
||||
inline ptrdiff_t txn::estimate_from_first(map_handle map,
|
||||
const slice &to) const {
|
||||
ptrdiff_t result;
|
||||
error::success_or_throw(mdbx_estimate_range(handle_, map.dbi, nullptr,
|
||||
nullptr, &to, nullptr, &result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline ptrdiff_t txn::estimate_to_last(map_handle map, slice from) const {
|
||||
inline ptrdiff_t txn::estimate_to_last(map_handle map,
|
||||
const slice &from) const {
|
||||
ptrdiff_t result;
|
||||
error::success_or_throw(mdbx_estimate_range(handle_, map.dbi, &from, nullptr,
|
||||
nullptr, nullptr, &result));
|
||||
@@ -5824,6 +6068,21 @@ inline ptrdiff_t txn::estimate_to_last(map_handle map, slice from) const {
|
||||
|
||||
MDBX_CXX11_CONSTEXPR cursor::cursor(MDBX_cursor *ptr) noexcept : handle_(ptr) {}
|
||||
|
||||
inline cursor_managed cursor::clone(void *your_context) const {
|
||||
cursor_managed clone(your_context);
|
||||
error::success_or_throw(::mdbx_cursor_copy(handle_, clone.handle_));
|
||||
return clone;
|
||||
}
|
||||
|
||||
inline void *cursor::get_context() const noexcept {
|
||||
return mdbx_cursor_get_userctx(handle_);
|
||||
}
|
||||
|
||||
inline cursor &cursor::set_context(void *ptr) {
|
||||
error::success_or_throw(::mdbx_cursor_set_userctx(handle_, ptr));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline cursor &cursor::operator=(cursor &&other) noexcept {
|
||||
handle_ = other.handle_;
|
||||
other.handle_ = nullptr;
|
||||
@@ -5862,22 +6121,8 @@ MDBX_CXX11_CONSTEXPR bool operator!=(const cursor &a,
|
||||
|
||||
inline cursor::move_result::move_result(const cursor &cursor,
|
||||
bool throw_notfound)
|
||||
: pair_result(key, value, false) {
|
||||
done = cursor.move(get_current, &key, &value, throw_notfound);
|
||||
}
|
||||
|
||||
inline cursor::move_result::move_result(cursor &cursor,
|
||||
move_operation operation,
|
||||
bool throw_notfound)
|
||||
: pair_result(key, value, false) {
|
||||
done = cursor.move(operation, &key, &value, throw_notfound);
|
||||
}
|
||||
|
||||
inline cursor::move_result::move_result(cursor &cursor,
|
||||
move_operation operation,
|
||||
const slice &key, bool throw_notfound)
|
||||
: pair_result(key, slice(), false) {
|
||||
this->done = cursor.move(operation, &this->key, &this->value, throw_notfound);
|
||||
: pair_result(slice(), slice(), false) {
|
||||
done = cursor.move(get_current, &this->key, &this->value, throw_notfound);
|
||||
}
|
||||
|
||||
inline cursor::move_result::move_result(cursor &cursor,
|
||||
@@ -5904,6 +6149,14 @@ inline bool cursor::move(move_operation operation, MDBX_val *key,
|
||||
}
|
||||
}
|
||||
|
||||
inline cursor::estimate_result::estimate_result(const cursor &cursor,
|
||||
move_operation operation,
|
||||
const slice &key,
|
||||
const slice &value)
|
||||
: pair(key, value), approximate_quantity(PTRDIFF_MIN) {
|
||||
approximate_quantity = cursor.estimate(operation, &this->key, &this->value);
|
||||
}
|
||||
|
||||
inline ptrdiff_t cursor::estimate(move_operation operation, MDBX_val *key,
|
||||
MDBX_val *value) const {
|
||||
ptrdiff_t result;
|
||||
@@ -6026,24 +6279,26 @@ inline bool cursor::on_last() const {
|
||||
return error::boolean_or_throw(::mdbx_cursor_on_last(*this));
|
||||
}
|
||||
|
||||
inline ptrdiff_t cursor::estimate(slice key, slice value) const {
|
||||
return estimate(multi_exactkey_lowerboundvalue, &key, &value);
|
||||
inline cursor::estimate_result cursor::estimate(const slice &key,
|
||||
const slice &value) const {
|
||||
return estimate_result(*this, multi_exactkey_lowerboundvalue, key, value);
|
||||
}
|
||||
|
||||
inline ptrdiff_t cursor::estimate(slice key) const {
|
||||
return estimate(key_lowerbound, &key, nullptr);
|
||||
inline cursor::estimate_result cursor::estimate(const slice &key) const {
|
||||
return estimate_result(*this, key_lowerbound, key);
|
||||
}
|
||||
|
||||
inline ptrdiff_t cursor::estimate(move_operation operation) const {
|
||||
slice unused_key;
|
||||
return estimate(operation, &unused_key, nullptr);
|
||||
inline cursor::estimate_result
|
||||
cursor::estimate(move_operation operation) const {
|
||||
return estimate_result(*this, operation);
|
||||
}
|
||||
|
||||
inline void cursor::renew(::mdbx::txn &txn) {
|
||||
inline void cursor::renew(const ::mdbx::txn &txn) {
|
||||
error::success_or_throw(::mdbx_cursor_renew(txn, handle_));
|
||||
}
|
||||
|
||||
inline void cursor::bind(::mdbx::txn &txn, ::mdbx::map_handle map_handle) {
|
||||
inline void cursor::bind(const ::mdbx::txn &txn,
|
||||
::mdbx::map_handle map_handle) {
|
||||
error::success_or_throw(::mdbx_cursor_bind(txn, handle_, map_handle.dbi));
|
||||
}
|
||||
|
||||
|
||||
@@ -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?=
|
||||
=?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).
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
@@ -15,8 +15,9 @@ This patch adds libmdbx:
|
||||
in terms of reliability, features and performance.
|
||||
- https://gitflic.ru/project/erthink/libmdbx
|
||||
|
||||
The v0.12.5 "Dynamo" is stable release of frontward _libmdbx_ branch with new superior features
|
||||
on the day of 100 anniversary of USSR' «Dynamo» sports and fitness society.
|
||||
The v0.12.8 "Vladimir Utkin" is stable release of frontward _libmdbx_
|
||||
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
|
||||
|
||||
@@ -111,18 +112,18 @@ index 0000000000..a9a4ac45c5
|
||||
+ !BR2_TOOLCHAIN_GCC_AT_LEAST_4_4
|
||||
diff --git a/package/libmdbx/libmdbx.hash b/package/libmdbx/libmdbx.hash
|
||||
new file mode 100644
|
||||
index 0000000000..7a5b19952e
|
||||
index 0000000000..82cf28d6a9
|
||||
--- /dev/null
|
||||
+++ b/package/libmdbx/libmdbx.hash
|
||||
@@ -0,0 +1,5 @@
|
||||
+# 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
|
||||
+sha256 310fe25c858a9515fc8c8d7d1f24a67c9496f84a91e0a0e41ea9975b1371e569 LICENSE
|
||||
diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk
|
||||
new file mode 100644
|
||||
index 0000000000..9a196eda60
|
||||
index 0000000000..d198fe5b22
|
||||
--- /dev/null
|
||||
+++ b/package/libmdbx/libmdbx.mk
|
||||
@@ -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_SITE = https://libmdbx.dqdkfa.ru/release
|
||||
+LIBMDBX_SUPPORTS_IN_SOURCE_BUILD = NO
|
||||
@@ -169,5 +170,5 @@ index 0000000000..9a196eda60
|
||||
+
|
||||
+$(eval $(cmake-package))
|
||||
--
|
||||
2.34.1
|
||||
2.42.0
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
1042
src/core.c
1042
src/core.c
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -1376,8 +1376,12 @@ struct MDBX_env {
|
||||
struct MDBX_lockinfo *me_lck;
|
||||
|
||||
unsigned me_psize; /* DB page size, initialized from me_os_psize */
|
||||
unsigned me_leaf_nodemax; /* max size of a leaf-node */
|
||||
unsigned me_branch_nodemax; /* max size of a branch-node */
|
||||
uint16_t me_leaf_nodemax; /* max size of a leaf-node */
|
||||
uint16_t me_branch_nodemax; /* max size of a branch-node */
|
||||
uint16_t me_subpage_limit;
|
||||
uint16_t me_subpage_room_threshold;
|
||||
uint16_t me_subpage_reserve_prereq;
|
||||
uint16_t me_subpage_reserve_limit;
|
||||
atomic_pgno_t me_mlocked_pgno;
|
||||
uint8_t me_psize2log; /* log2 of DB page size */
|
||||
int8_t me_stuck_meta; /* recovery-only: target meta page or less that zero */
|
||||
@@ -1482,6 +1486,7 @@ struct MDBX_env {
|
||||
int me_valgrind_handle;
|
||||
#endif
|
||||
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
|
||||
MDBX_atomic_uint32_t me_ignore_EDEADLK;
|
||||
pgno_t me_poison_edge;
|
||||
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -822,6 +822,11 @@ __cold static int mdbx_ipclock_failed(MDBX_env *env, osal_ipclock_t *ipc,
|
||||
#error "FIXME"
|
||||
#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));
|
||||
if (rc != EDEADLK)
|
||||
env->me_flags |= MDBX_FATAL_ERROR;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.TH MDBX_CHK 1 "2023-04-29" "MDBX 0.12.6"
|
||||
.TH MDBX_CHK 1 "2024-03-13" "MDBX 0.12.10"
|
||||
.SH NAME
|
||||
mdbx_chk \- MDBX checking tool
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
||||
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.TH MDBX_COPY 1 "2023-04-29" "MDBX 0.12.6"
|
||||
.TH MDBX_COPY 1 "2024-03-13" "MDBX 0.12.10"
|
||||
.SH NAME
|
||||
mdbx_copy \- MDBX environment copy tool
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.\" Copyright 2021-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2021-2024 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.TH MDBX_DROP 1 "2023-04-29" "MDBX 0.12.6"
|
||||
.TH MDBX_DROP 1 "2024-03-13" "MDBX 0.12.10"
|
||||
.SH NAME
|
||||
mdbx_drop \- MDBX database delete tool
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
||||
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.TH MDBX_DUMP 1 "2023-04-29" "MDBX 0.12.6"
|
||||
.TH MDBX_DUMP 1 "2024-03-13" "MDBX 0.12.10"
|
||||
.SH NAME
|
||||
mdbx_dump \- MDBX environment export tool
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
||||
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.TH MDBX_LOAD 1 "2023-04-29" "MDBX 0.12.6"
|
||||
.TH MDBX_LOAD 1 "2024-03-13" "MDBX 0.12.10"
|
||||
.SH NAME
|
||||
mdbx_load \- MDBX environment import tool
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
||||
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.TH MDBX_STAT 1 "2023-04-29" "MDBX 0.12.6"
|
||||
.TH MDBX_STAT 1 "2024-03-13" "MDBX 0.12.10"
|
||||
.SH NAME
|
||||
mdbx_stat \- MDBX environment status tool
|
||||
.SH SYNOPSIS
|
||||
|
||||
544
src/mdbx.c++
544
src/mdbx.c++
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2020-2023, Leonid Yuriev <leo@yuriev.ru>.
|
||||
// Copyright (c) 2020-2024, Leonid Yuriev <leo@yuriev.ru>.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Non-inline part of the libmdbx C++ API
|
||||
@@ -207,6 +207,44 @@ __cold bug::~bug() noexcept {}
|
||||
|
||||
#endif /* Unused*/
|
||||
|
||||
struct line_wrapper {
|
||||
char *line, *ptr;
|
||||
line_wrapper(char *buf) noexcept : line(buf), ptr(buf) {}
|
||||
void put(char c, size_t wrap_width) noexcept {
|
||||
*ptr++ = c;
|
||||
if (wrap_width && ptr >= wrap_width + line) {
|
||||
*ptr++ = '\n';
|
||||
line = ptr;
|
||||
}
|
||||
}
|
||||
void put(const ::mdbx::slice &chunk, size_t wrap_width) noexcept {
|
||||
if (!wrap_width || wrap_width > (ptr - line) + chunk.length()) {
|
||||
memcpy(ptr, chunk.data(), chunk.length());
|
||||
ptr += chunk.length();
|
||||
} else {
|
||||
for (size_t i = 0; i < chunk.length(); ++i)
|
||||
put(chunk.char_ptr()[i], wrap_width);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TYPE, unsigned INPLACE_BYTES = unsigned(sizeof(void *) * 64)>
|
||||
struct temp_buffer {
|
||||
TYPE inplace[(INPLACE_BYTES + sizeof(TYPE) - 1) / sizeof(TYPE)];
|
||||
const size_t size;
|
||||
TYPE *const area;
|
||||
temp_buffer(size_t bytes)
|
||||
: size((bytes + sizeof(TYPE) - 1) / sizeof(TYPE)),
|
||||
area((bytes > sizeof(inplace)) ? new TYPE[size] : inplace) {
|
||||
memset(area, 0, sizeof(TYPE) * size);
|
||||
}
|
||||
~temp_buffer() {
|
||||
if (area != inplace)
|
||||
delete[] area;
|
||||
}
|
||||
TYPE *end() const { return area + size; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -233,6 +271,10 @@ namespace mdbx {
|
||||
"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
|
||||
: base(error.what()), error_(error) {}
|
||||
|
||||
@@ -281,7 +323,7 @@ DEFINE_EXCEPTION(something_busy)
|
||||
DEFINE_EXCEPTION(thread_mismatch)
|
||||
DEFINE_EXCEPTION(transaction_full)
|
||||
DEFINE_EXCEPTION(transaction_overlapping)
|
||||
|
||||
DEFINE_EXCEPTION(duplicated_lck_file)
|
||||
#undef DEFINE_EXCEPTION
|
||||
|
||||
__cold const char *error::what() const noexcept {
|
||||
@@ -367,6 +409,7 @@ __cold void error::throw_exception() const {
|
||||
CASE_EXCEPTION(thread_mismatch, MDBX_THREAD_MISMATCH);
|
||||
CASE_EXCEPTION(transaction_full, MDBX_TXN_FULL);
|
||||
CASE_EXCEPTION(transaction_overlapping, MDBX_TXN_OVERLAPPING);
|
||||
CASE_EXCEPTION(duplicated_lck_file, MDBX_DUPLICATED_CLK);
|
||||
#undef CASE_EXCEPTION
|
||||
default:
|
||||
if (is_mdbx_error())
|
||||
@@ -483,6 +526,109 @@ bool slice::is_printable(bool disable_utf8) const noexcept {
|
||||
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 {
|
||||
@@ -491,7 +637,7 @@ char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
|
||||
|
||||
auto ptr = dest;
|
||||
auto src = source.byte_ptr();
|
||||
const char alphabase = (uppercase ? 'A' : 'a') - 10;
|
||||
const char alpha_shift = (uppercase ? 'A' : 'a') - '9' - 1;
|
||||
auto line = ptr;
|
||||
for (const auto end = source.end_byte_ptr(); src != end; ++src) {
|
||||
if (wrap_width && size_t(ptr - line) >= wrap_width) {
|
||||
@@ -500,8 +646,8 @@ char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
|
||||
}
|
||||
const int8_t hi = *src >> 4;
|
||||
const int8_t lo = *src & 15;
|
||||
ptr[0] = char(alphabase + hi + (((hi - 10) >> 7) & -7));
|
||||
ptr[1] = char(alphabase + lo + (((lo - 10) >> 7) & -7));
|
||||
ptr[0] = char('0' + hi + (((9 - hi) >> 7) & alpha_shift));
|
||||
ptr[1] = char('0' + lo + (((9 - lo) >> 7) & alpha_shift));
|
||||
ptr += 2;
|
||||
assert(ptr <= dest + dest_size);
|
||||
}
|
||||
@@ -513,7 +659,7 @@ char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
|
||||
MDBX_CXX20_LIKELY {
|
||||
::std::ostream::sentry sentry(out);
|
||||
auto src = source.byte_ptr();
|
||||
const char alphabase = (uppercase ? 'A' : 'a') - 10;
|
||||
const char alpha_shift = (uppercase ? 'A' : 'a') - '9' - 1;
|
||||
unsigned width = 0;
|
||||
for (const auto end = source.end_byte_ptr(); src != end; ++src) {
|
||||
if (wrap_width && width >= wrap_width) {
|
||||
@@ -522,8 +668,8 @@ char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
|
||||
}
|
||||
const int8_t hi = *src >> 4;
|
||||
const int8_t lo = *src & 15;
|
||||
out.put(char(alphabase + hi + (((hi - 10) >> 7) & -7)));
|
||||
out.put(char(alphabase + lo + (((lo - 10) >> 7) & -7)));
|
||||
out.put(char('0' + hi + (((9 - hi) >> 7) & alpha_shift)));
|
||||
out.put(char('0' + lo + (((9 - lo) >> 7) & alpha_shift)));
|
||||
width += 2;
|
||||
}
|
||||
}
|
||||
@@ -554,11 +700,11 @@ char *from_hex::write_bytes(char *__restrict const dest,
|
||||
|
||||
int8_t hi = src[0];
|
||||
hi = (hi | 0x20) - 'a';
|
||||
hi += 10 + ((hi >> 7) & 7);
|
||||
hi += 10 + ((hi >> 7) & 39);
|
||||
|
||||
int8_t lo = src[1];
|
||||
lo = (lo | 0x20) - 'a';
|
||||
lo += 10 + ((lo >> 7) & 7);
|
||||
lo += 10 + ((lo >> 7) & 39);
|
||||
|
||||
*ptr++ = hi << 4 | lo;
|
||||
src += 2;
|
||||
@@ -601,156 +747,135 @@ enum : signed char {
|
||||
IL /* invalid */ = -1
|
||||
};
|
||||
|
||||
static const byte b58_alphabet[58] = {
|
||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
|
||||
'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
||||
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
|
||||
|
||||
#ifndef bswap64
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
static inline uint64_t bswap64(uint64_t v) noexcept {
|
||||
#if __GNUC_PREREQ(4, 4) || __CLANG_PREREQ(4, 0) || \
|
||||
__has_builtin(__builtin_bswap64)
|
||||
return __builtin_bswap64(v);
|
||||
#elif defined(_MSC_VER) && !defined(__clang__)
|
||||
return _byteswap_uint64(v);
|
||||
#elif defined(__bswap_64)
|
||||
return __bswap_64(v);
|
||||
#elif defined(bswap_64)
|
||||
return bswap_64(v);
|
||||
#if MDBX_WORDBITS > 32
|
||||
using b58_uint = uint_fast64_t;
|
||||
#else
|
||||
return v << 56 | v >> 56 | ((v << 40) & UINT64_C(0x00ff000000000000)) |
|
||||
((v << 24) & UINT64_C(0x0000ff0000000000)) |
|
||||
((v << 8) & UINT64_C(0x000000ff00000000)) |
|
||||
((v >> 8) & UINT64_C(0x00000000ff000000)) |
|
||||
((v >> 24) & UINT64_C(0x0000000000ff0000)) |
|
||||
((v >> 40) & UINT64_C(0x000000000000ff00));
|
||||
using b58_uint = uint_fast32_t;
|
||||
#endif
|
||||
}
|
||||
#endif /* __BYTE_ORDER__ */
|
||||
#endif /* ifndef bswap64 */
|
||||
|
||||
static inline char b58_8to11(uint64_t &v) noexcept {
|
||||
const unsigned i = unsigned(v % 58);
|
||||
struct b58_buffer : public temp_buffer<b58_uint> {
|
||||
b58_buffer(size_t bytes, size_t estimation_ratio_numerator,
|
||||
size_t estimation_ratio_denominator, size_t extra = 0)
|
||||
: temp_buffer((/* пересчитываем по указанной пропорции */
|
||||
bytes = (bytes * estimation_ratio_numerator +
|
||||
estimation_ratio_denominator - 1) /
|
||||
estimation_ratio_denominator,
|
||||
/* учитываем резервный старший байт в каждом слове */
|
||||
((bytes + sizeof(b58_uint) - 2) / (sizeof(b58_uint) - 1) *
|
||||
sizeof(b58_uint) +
|
||||
extra) *
|
||||
sizeof(b58_uint))) {}
|
||||
};
|
||||
|
||||
static byte b58_8to11(b58_uint &v) noexcept {
|
||||
static const char b58_alphabet[58] = {
|
||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
|
||||
'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
||||
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
|
||||
|
||||
const auto i = size_t(v % 58);
|
||||
v /= 58;
|
||||
return b58_alphabet[i];
|
||||
}
|
||||
|
||||
static slice b58_encode(b58_buffer &buf, const byte *begin, const byte *end) {
|
||||
auto high = buf.end();
|
||||
const auto modulo =
|
||||
b58_uint((sizeof(b58_uint) > 4) ? UINT64_C(0x1A636A90B07A00) /* 58^9 */
|
||||
: UINT32_C(0xACAD10) /* 58^4 */);
|
||||
static_assert(sizeof(modulo) == 4 || sizeof(modulo) == 8, "WTF?");
|
||||
while (begin < end) {
|
||||
b58_uint carry = *begin++;
|
||||
auto ptr = buf.end();
|
||||
do {
|
||||
assert(ptr > buf.area);
|
||||
carry += *--ptr << CHAR_BIT;
|
||||
*ptr = carry % modulo;
|
||||
carry /= modulo;
|
||||
} while (carry || ptr > high);
|
||||
high = ptr;
|
||||
}
|
||||
|
||||
byte *output = static_cast<byte *>(static_cast<void *>(buf.area));
|
||||
auto ptr = output;
|
||||
for (auto porous = high; porous < buf.end();) {
|
||||
auto chunk = *porous++;
|
||||
static_assert(sizeof(chunk) == 4 || sizeof(chunk) == 8, "WTF?");
|
||||
assert(chunk < modulo);
|
||||
if (sizeof(chunk) > 4) {
|
||||
ptr[8] = b58_8to11(chunk);
|
||||
ptr[7] = b58_8to11(chunk);
|
||||
ptr[6] = b58_8to11(chunk);
|
||||
ptr[5] = b58_8to11(chunk);
|
||||
ptr[4] = b58_8to11(chunk);
|
||||
ptr[3] = b58_8to11(chunk);
|
||||
ptr[2] = b58_8to11(chunk);
|
||||
ptr[1] = b58_8to11(chunk);
|
||||
ptr[0] = b58_8to11(chunk);
|
||||
ptr += 9;
|
||||
} else {
|
||||
ptr[3] = b58_8to11(chunk);
|
||||
ptr[2] = b58_8to11(chunk);
|
||||
ptr[1] = b58_8to11(chunk);
|
||||
ptr[0] = b58_8to11(chunk);
|
||||
ptr += 4;
|
||||
}
|
||||
assert(static_cast<void *>(ptr) < static_cast<void *>(porous));
|
||||
}
|
||||
|
||||
while (output < ptr && *output == '1')
|
||||
++output;
|
||||
return slice(output, ptr);
|
||||
}
|
||||
|
||||
char *to_base58::write_bytes(char *__restrict const dest,
|
||||
size_t dest_size) const {
|
||||
if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
|
||||
MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
|
||||
|
||||
auto ptr = dest;
|
||||
auto src = source.byte_ptr();
|
||||
size_t left = source.length();
|
||||
auto line = ptr;
|
||||
while (MDBX_LIKELY(left > 7)) {
|
||||
uint64_t v;
|
||||
std::memcpy(&v, src, 8);
|
||||
src += 8;
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
v = bswap64(v);
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#else
|
||||
#error "FIXME: Unsupported byte order"
|
||||
#endif /* __BYTE_ORDER__ */
|
||||
ptr[10] = b58_8to11(v);
|
||||
ptr[9] = b58_8to11(v);
|
||||
ptr[8] = b58_8to11(v);
|
||||
ptr[7] = b58_8to11(v);
|
||||
ptr[6] = b58_8to11(v);
|
||||
ptr[5] = b58_8to11(v);
|
||||
ptr[4] = b58_8to11(v);
|
||||
ptr[3] = b58_8to11(v);
|
||||
ptr[2] = b58_8to11(v);
|
||||
ptr[1] = b58_8to11(v);
|
||||
ptr[0] = b58_8to11(v);
|
||||
assert(v == 0);
|
||||
ptr += 11;
|
||||
left -= 8;
|
||||
if (wrap_width && size_t(ptr - line) >= wrap_width && left) {
|
||||
*ptr = '\n';
|
||||
line = ++ptr;
|
||||
}
|
||||
assert(ptr <= dest + dest_size);
|
||||
auto begin = source.byte_ptr();
|
||||
auto end = source.end_byte_ptr();
|
||||
line_wrapper wrapper(dest);
|
||||
while (MDBX_LIKELY(begin < end) && *begin == 0) {
|
||||
wrapper.put('1', wrap_width);
|
||||
assert(wrapper.ptr <= dest + dest_size);
|
||||
++begin;
|
||||
}
|
||||
|
||||
if (left) {
|
||||
uint64_t v = 0;
|
||||
unsigned parrots = 31;
|
||||
do {
|
||||
v = (v << 8) + *src++;
|
||||
parrots += 43;
|
||||
} while (--left);
|
||||
|
||||
auto tail = ptr += parrots >> 5;
|
||||
assert(ptr <= dest + dest_size);
|
||||
do {
|
||||
*--tail = b58_8to11(v);
|
||||
parrots -= 32;
|
||||
} while (parrots > 31);
|
||||
assert(v == 0);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
b58_buffer buf(end - begin, 11, 8);
|
||||
wrapper.put(b58_encode(buf, begin, end), wrap_width);
|
||||
return wrapper.ptr;
|
||||
}
|
||||
|
||||
::std::ostream &to_base58::output(::std::ostream &out) const {
|
||||
if (MDBX_LIKELY(!is_empty()))
|
||||
MDBX_CXX20_LIKELY {
|
||||
::std::ostream::sentry sentry(out);
|
||||
auto src = source.byte_ptr();
|
||||
size_t left = source.length();
|
||||
auto begin = source.byte_ptr();
|
||||
auto end = source.end_byte_ptr();
|
||||
unsigned width = 0;
|
||||
std::array<char, 11> buf;
|
||||
|
||||
while (MDBX_LIKELY(left > 7)) {
|
||||
uint64_t v;
|
||||
std::memcpy(&v, src, 8);
|
||||
src += 8;
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
v = bswap64(v);
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#else
|
||||
#error "FIXME: Unsupported byte order"
|
||||
#endif /* __BYTE_ORDER__ */
|
||||
buf[10] = b58_8to11(v);
|
||||
buf[9] = b58_8to11(v);
|
||||
buf[8] = b58_8to11(v);
|
||||
buf[7] = b58_8to11(v);
|
||||
buf[6] = b58_8to11(v);
|
||||
buf[5] = b58_8to11(v);
|
||||
buf[4] = b58_8to11(v);
|
||||
buf[3] = b58_8to11(v);
|
||||
buf[2] = b58_8to11(v);
|
||||
buf[1] = b58_8to11(v);
|
||||
buf[0] = b58_8to11(v);
|
||||
assert(v == 0);
|
||||
out.write(&buf.front(), 11);
|
||||
left -= 8;
|
||||
if (wrap_width && (width += 11) >= wrap_width && left) {
|
||||
while (MDBX_LIKELY(begin < end) && *begin == 0) {
|
||||
out.put('1');
|
||||
if (wrap_width && ++width >= wrap_width) {
|
||||
out << ::std::endl;
|
||||
width = 0;
|
||||
}
|
||||
++begin;
|
||||
}
|
||||
|
||||
if (left) {
|
||||
uint64_t v = 0;
|
||||
unsigned parrots = 31;
|
||||
do {
|
||||
v = (v << 8) + *src++;
|
||||
parrots += 43;
|
||||
} while (--left);
|
||||
|
||||
auto ptr = buf.end();
|
||||
do {
|
||||
*--ptr = b58_8to11(v);
|
||||
parrots -= 32;
|
||||
} while (parrots > 31);
|
||||
assert(v == 0);
|
||||
out.write(&*ptr, buf.end() - ptr);
|
||||
b58_buffer buf(end - begin, 11, 8);
|
||||
const auto chunk = b58_encode(buf, begin, end);
|
||||
if (!wrap_width || wrap_width > width + chunk.length())
|
||||
out.write(chunk.char_ptr(), chunk.length());
|
||||
else {
|
||||
for (size_t i = 0; i < chunk.length(); ++i) {
|
||||
out.put(chunk.char_ptr()[i]);
|
||||
if (wrap_width && ++width >= wrap_width) {
|
||||
out << ::std::endl;
|
||||
width = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
@@ -776,10 +901,46 @@ const signed char b58_map[256] = {
|
||||
IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL // f0
|
||||
};
|
||||
|
||||
static inline signed char b58_11to8(uint64_t &v, const byte c) noexcept {
|
||||
const signed char m = b58_map[c];
|
||||
v = v * 58 + m;
|
||||
return m;
|
||||
static slice b58_decode(b58_buffer &buf, const byte *begin, const byte *end,
|
||||
bool ignore_spaces) {
|
||||
auto high = buf.end();
|
||||
while (begin < end) {
|
||||
const auto c = b58_map[*begin++];
|
||||
if (MDBX_LIKELY(c >= 0)) {
|
||||
b58_uint carry = c;
|
||||
auto ptr = buf.end();
|
||||
do {
|
||||
assert(ptr > buf.area);
|
||||
carry += *--ptr * 58;
|
||||
*ptr = carry & (~b58_uint(0) >> CHAR_BIT);
|
||||
carry >>= CHAR_BIT * (sizeof(carry) - 1);
|
||||
} while (carry || ptr > high);
|
||||
high = ptr;
|
||||
} else if (MDBX_UNLIKELY(!ignore_spaces || !isspace(begin[-1])))
|
||||
MDBX_CXX20_UNLIKELY
|
||||
throw std::domain_error("mdbx::from_base58:: invalid base58 string");
|
||||
}
|
||||
|
||||
byte *output = static_cast<byte *>(static_cast<void *>(buf.area));
|
||||
auto ptr = output;
|
||||
for (auto porous = high; porous < buf.end(); ++porous) {
|
||||
auto chunk = *porous;
|
||||
static_assert(sizeof(chunk) == 4 || sizeof(chunk) == 8, "WTF?");
|
||||
assert(chunk <= (~b58_uint(0) >> CHAR_BIT));
|
||||
if (sizeof(chunk) > 4) {
|
||||
*ptr++ = byte(uint_fast64_t(chunk) >> CHAR_BIT * 6);
|
||||
*ptr++ = byte(uint_fast64_t(chunk) >> CHAR_BIT * 5);
|
||||
*ptr++ = byte(uint_fast64_t(chunk) >> CHAR_BIT * 4);
|
||||
*ptr++ = byte(chunk >> CHAR_BIT * 3);
|
||||
}
|
||||
*ptr++ = byte(chunk >> CHAR_BIT * 2);
|
||||
*ptr++ = byte(chunk >> CHAR_BIT * 1);
|
||||
*ptr++ = byte(chunk >> CHAR_BIT * 0);
|
||||
}
|
||||
|
||||
while (output < ptr && *output == 0)
|
||||
++output;
|
||||
return slice(output, ptr);
|
||||
}
|
||||
|
||||
char *from_base58::write_bytes(char *__restrict const dest,
|
||||
@@ -788,98 +949,33 @@ char *from_base58::write_bytes(char *__restrict const dest,
|
||||
MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
|
||||
|
||||
auto ptr = dest;
|
||||
auto src = source.byte_ptr();
|
||||
for (auto left = source.length(); left > 0;) {
|
||||
if (MDBX_UNLIKELY(isspace(*src)) && ignore_spaces) {
|
||||
++src;
|
||||
--left;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (MDBX_LIKELY(left > 10)) {
|
||||
uint64_t v = 0;
|
||||
if (MDBX_UNLIKELY((b58_11to8(v, src[0]) | b58_11to8(v, src[1]) |
|
||||
b58_11to8(v, src[2]) | b58_11to8(v, src[3]) |
|
||||
b58_11to8(v, src[4]) | b58_11to8(v, src[5]) |
|
||||
b58_11to8(v, src[6]) | b58_11to8(v, src[7]) |
|
||||
b58_11to8(v, src[8]) | b58_11to8(v, src[9]) |
|
||||
b58_11to8(v, src[10])) < 0))
|
||||
MDBX_CXX20_UNLIKELY goto bailout;
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
v = bswap64(v);
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#else
|
||||
#error "FIXME: Unsupported byte order"
|
||||
#endif /* __BYTE_ORDER__ */
|
||||
std::memcpy(ptr, &v, 8);
|
||||
ptr += 8;
|
||||
src += 11;
|
||||
left -= 11;
|
||||
assert(ptr <= dest + dest_size);
|
||||
continue;
|
||||
}
|
||||
|
||||
constexpr unsigned invalid_length_mask = 1 << 1 | 1 << 4 | 1 << 8;
|
||||
if (MDBX_UNLIKELY(invalid_length_mask & (1 << left)))
|
||||
MDBX_CXX20_UNLIKELY goto bailout;
|
||||
|
||||
uint64_t v = 1;
|
||||
unsigned parrots = 0;
|
||||
do {
|
||||
if (MDBX_UNLIKELY(b58_11to8(v, *src++) < 0))
|
||||
MDBX_CXX20_UNLIKELY goto bailout;
|
||||
parrots += 32;
|
||||
} while (--left);
|
||||
|
||||
auto tail = ptr += parrots / 43;
|
||||
assert(ptr <= dest + dest_size);
|
||||
do {
|
||||
*--tail = byte(v);
|
||||
v >>= 8;
|
||||
} while (v > 255);
|
||||
break;
|
||||
auto begin = source.byte_ptr();
|
||||
auto const end = source.end_byte_ptr();
|
||||
while (begin < end && *begin <= '1') {
|
||||
if (MDBX_LIKELY(*begin == '1'))
|
||||
MDBX_CXX20_LIKELY *ptr++ = 0;
|
||||
else if (MDBX_UNLIKELY(!ignore_spaces || !isspace(*begin)))
|
||||
MDBX_CXX20_UNLIKELY
|
||||
throw std::domain_error("mdbx::from_base58:: invalid base58 string");
|
||||
++begin;
|
||||
}
|
||||
return ptr;
|
||||
|
||||
bailout:
|
||||
throw std::domain_error("mdbx::from_base58:: invalid base58 string");
|
||||
b58_buffer buf(end - begin, 47, 64);
|
||||
auto slice = b58_decode(buf, begin, end, ignore_spaces);
|
||||
memcpy(ptr, slice.data(), slice.length());
|
||||
return ptr + slice.length();
|
||||
}
|
||||
|
||||
bool from_base58::is_erroneous() const noexcept {
|
||||
bool got = false;
|
||||
auto src = source.byte_ptr();
|
||||
for (auto left = source.length(); left > 0;) {
|
||||
if (MDBX_UNLIKELY(*src <= ' ') &&
|
||||
MDBX_LIKELY(ignore_spaces && isspace(*src))) {
|
||||
++src;
|
||||
--left;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (MDBX_LIKELY(left > 10)) {
|
||||
if (MDBX_UNLIKELY((b58_map[src[0]] | b58_map[src[1]] | b58_map[src[2]] |
|
||||
b58_map[src[3]] | b58_map[src[4]] | b58_map[src[5]] |
|
||||
b58_map[src[6]] | b58_map[src[7]] | b58_map[src[8]] |
|
||||
b58_map[src[9]] | b58_map[src[10]]) < 0))
|
||||
MDBX_CXX20_UNLIKELY return true;
|
||||
src += 11;
|
||||
left -= 11;
|
||||
got = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
constexpr unsigned invalid_length_mask = 1 << 1 | 1 << 4 | 1 << 8;
|
||||
if (invalid_length_mask & (1 << left))
|
||||
return false;
|
||||
|
||||
do
|
||||
if (MDBX_UNLIKELY(b58_map[*src++] < 0))
|
||||
MDBX_CXX20_UNLIKELY return true;
|
||||
while (--left);
|
||||
got = true;
|
||||
break;
|
||||
auto begin = source.byte_ptr();
|
||||
auto const end = source.end_byte_ptr();
|
||||
while (begin < end) {
|
||||
if (MDBX_UNLIKELY(b58_map[*begin] < 0 &&
|
||||
!(ignore_spaces && isspace(*begin))))
|
||||
return true;
|
||||
++begin;
|
||||
}
|
||||
return !got;
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* mdbx_chk.c - memory-mapped database check tool */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -537,26 +537,14 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
||||
data_tree_problems += !is_gc_tree;
|
||||
gc_tree_problems += is_gc_tree;
|
||||
}
|
||||
if (payload_bytes < 1) {
|
||||
if (nentries > 1) {
|
||||
problem_add("page", pgno, "zero size-of-entry",
|
||||
"%s-page: payload %" PRIuPTR " bytes, %" PRIuPTR " entries",
|
||||
pagetype_caption, payload_bytes, nentries);
|
||||
/* if ((size_t)header_bytes + unused_bytes < page_size) {
|
||||
// LY: hush a misuse error
|
||||
page_bytes = page_size;
|
||||
} */
|
||||
data_tree_problems += !is_gc_tree;
|
||||
gc_tree_problems += is_gc_tree;
|
||||
} else {
|
||||
problem_add("page", pgno, "empty",
|
||||
"%s-page: payload %" PRIuPTR " bytes, %" PRIuPTR
|
||||
" entries, deep %i",
|
||||
pagetype_caption, payload_bytes, nentries, deep);
|
||||
dbi->pages.empty += 1;
|
||||
data_tree_problems += !is_gc_tree;
|
||||
gc_tree_problems += is_gc_tree;
|
||||
}
|
||||
if (nentries < 1 || (pagetype == MDBX_page_branch && nentries < 2)) {
|
||||
problem_add("page", pgno, nentries ? "half-empty" : "empty",
|
||||
"%s-page: payload %" PRIuPTR " bytes, %" PRIuPTR
|
||||
" entries, deep %i",
|
||||
pagetype_caption, payload_bytes, nentries, deep);
|
||||
dbi->pages.empty += 1;
|
||||
data_tree_problems += !is_gc_tree;
|
||||
gc_tree_problems += is_gc_tree;
|
||||
}
|
||||
|
||||
if (pgnumber) {
|
||||
@@ -611,7 +599,7 @@ static int handle_freedb(const uint64_t record_number, const MDBX_val *key,
|
||||
problem_add("entry", txnid, "wrong idl size", "%" PRIuPTR,
|
||||
data->iov_len);
|
||||
size_t number = (data->iov_len >= sizeof(pgno_t)) ? *iptr++ : 0;
|
||||
if (number < 1 || number > MDBX_PGL_LIMIT)
|
||||
if (number > MDBX_PGL_LIMIT)
|
||||
problem_add("entry", txnid, "wrong idl length", "%" PRIuPTR, number);
|
||||
else if ((number + 1) * sizeof(pgno_t) > data->iov_len) {
|
||||
problem_add("entry", txnid, "trimmed idl",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* mdbx_copy.c - memory-mapped database backup tool */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* mdbx_drop.c - memory-mapped database delete tool */
|
||||
|
||||
/*
|
||||
* Copyright 2021-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2021-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
*
|
||||
* Copyright 2016-2021 Howard Chu, Symas Corp.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* mdbx_dump.c - memory-mapped database dump tool */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* mdbx_load.c - memory-mapped database load tool */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* mdbx_stat.c - memory-mapped database status tool */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -28,9 +28,17 @@
|
||||
#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY MDBX_OSX_WANNA_DURABILITY
|
||||
#endif /* MDBX_OSX_SPEED_INSTEADOF_DURABILITY */
|
||||
|
||||
/** Controls using of POSIX' madvise() and/or similar hints. */
|
||||
#ifndef MDBX_ENABLE_MADVISE
|
||||
#define MDBX_ENABLE_MADVISE 1
|
||||
#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
|
||||
#error MDBX_ENABLE_MADVISE must be defined as 0 or 1
|
||||
#endif /* MDBX_ENABLE_MADVISE */
|
||||
|
||||
/** Controls checking PID against reuse DB environment after the fork() */
|
||||
#ifndef MDBX_ENV_CHECKPID
|
||||
#if defined(MADV_DONTFORK) || defined(_WIN32) || defined(_WIN64)
|
||||
#if (defined(MADV_DONTFORK) && MDBX_ENABLE_MADVISE) || defined(_WIN32) || \
|
||||
defined(_WIN64)
|
||||
/* PID check could be omitted:
|
||||
* - on Linux when madvise(MADV_DONTFORK) is available, i.e. after the fork()
|
||||
* mapped pages will not be available for child process.
|
||||
@@ -96,8 +104,7 @@
|
||||
/** Controls using Unix' mincore() to determine whether DB-pages
|
||||
* are resident in memory. */
|
||||
#ifndef MDBX_ENABLE_MINCORE
|
||||
#if MDBX_ENABLE_PREFAULT && \
|
||||
(defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64)))
|
||||
#if defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64))
|
||||
#define MDBX_ENABLE_MINCORE 1
|
||||
#else
|
||||
#define MDBX_ENABLE_MINCORE 0
|
||||
@@ -118,13 +125,6 @@
|
||||
#error MDBX_ENABLE_BIGFOOT must be defined as 0 or 1
|
||||
#endif /* MDBX_ENABLE_BIGFOOT */
|
||||
|
||||
/** Controls using of POSIX' madvise() and/or similar hints. */
|
||||
#ifndef MDBX_ENABLE_MADVISE
|
||||
#define MDBX_ENABLE_MADVISE 1
|
||||
#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
|
||||
#error MDBX_ENABLE_MADVISE must be defined as 0 or 1
|
||||
#endif /* MDBX_ENABLE_MADVISE */
|
||||
|
||||
/** Disable some checks to reduce an overhead and detection probability of
|
||||
* database corruption to a values closer to the LMDB. */
|
||||
#ifndef MDBX_DISABLE_VALIDATION
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -1826,8 +1826,8 @@ MDBX_INTERNAL_FUNC int osal_check_fs_rdonly(mdbx_filehandle_t handle,
|
||||
#else
|
||||
struct statvfs info;
|
||||
if (err != MDBX_ENOFILE) {
|
||||
if (statvfs(pathname, &info) == 0 && (info.f_flag & ST_RDONLY) == 0)
|
||||
return err;
|
||||
if (statvfs(pathname, &info) == 0)
|
||||
return (info.f_flag & ST_RDONLY) ? MDBX_SUCCESS : err;
|
||||
if (errno != MDBX_ENOFILE)
|
||||
return errno;
|
||||
}
|
||||
@@ -2571,7 +2571,7 @@ retry_mapview:;
|
||||
ptr_disp(map->base, size),
|
||||
((map->current < map->limit) ? map->current : map->limit) - size);
|
||||
}
|
||||
map->current = size;
|
||||
map->current = (size < map->limit) ? size : map->limit;
|
||||
}
|
||||
|
||||
if (limit == map->limit)
|
||||
@@ -2732,6 +2732,7 @@ retry_mapview:;
|
||||
map->base = ptr;
|
||||
}
|
||||
map->limit = limit;
|
||||
map->current = size;
|
||||
|
||||
#if MDBX_ENABLE_MADVISE
|
||||
#ifdef MADV_DONTFORK
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -72,6 +72,10 @@ if(UNIX AND NOT SUBPROJECT)
|
||||
target_include_directories(test_extra_upsert_alldups PRIVATE "${PROJECT_SOURCE_DIR}")
|
||||
target_link_libraries(test_extra_upsert_alldups ${TOOL_MDBX_LIB})
|
||||
|
||||
add_executable(test_extra_dupfixed_addodd extra/dupfixed_addodd.c)
|
||||
target_include_directories(test_extra_dupfixed_addodd PRIVATE "${PROJECT_SOURCE_DIR}")
|
||||
target_link_libraries(test_extra_dupfixed_addodd ${TOOL_MDBX_LIB})
|
||||
|
||||
if(MDBX_BUILD_CXX)
|
||||
add_executable(test_extra_maindb_ordinal extra/maindb_ordinal.c++)
|
||||
target_include_directories(test_extra_maindb_ordinal PRIVATE "${PROJECT_SOURCE_DIR}")
|
||||
@@ -80,6 +84,13 @@ if(UNIX AND NOT SUBPROJECT)
|
||||
set_target_properties(test_extra_maindb_ordinal PROPERTIES
|
||||
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
||||
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()
|
||||
|
||||
@@ -159,4 +170,13 @@ else()
|
||||
REQUIRED_FILES uniq_nested.db-copy)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT SUBPROJECT)
|
||||
add_test(NAME extra_upsert_alldups COMMAND test_extra_upsert_alldups)
|
||||
add_test(NAME extra_dupfixed_addodd COMMAND test_extra_dupfixed_addodd)
|
||||
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()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -667,7 +667,10 @@ bool actor_config::deserialize(const char *str, actor_config &config) {
|
||||
}
|
||||
str = slash + 1;
|
||||
|
||||
uint64_t verify = std::stoull(std::string(str));
|
||||
uint64_t verify = 0;
|
||||
while (*str >= '0' && *str <= '9')
|
||||
verify = verify * 10 + *str++ - '0';
|
||||
|
||||
if (checksum.value != verify) {
|
||||
TRACE("<< actor_config::deserialize: checksum mismatch\n");
|
||||
return false;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
93
test/extra/dupfixed_addodd.c
Normal file
93
test/extra/dupfixed_addodd.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* @Dvirsw (https://t.me/Dvirsw)
|
||||
* I think there is a bug with DUPFIXED. The following code fails.
|
||||
*
|
||||
* https://t.me/libmdbx/5368
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "mdbx.h"
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main() {
|
||||
int rc;
|
||||
MDBX_env *env = NULL;
|
||||
MDBX_dbi dbi = 0;
|
||||
MDBX_val key, data;
|
||||
MDBX_txn *txn = NULL;
|
||||
|
||||
rc = mdbx_env_create(&env);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_env_create: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
rc = mdbx_env_set_maxdbs(env, 1);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_env_create: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
rc = mdbx_env_open(env, "./example-db",
|
||||
MDBX_NOSUBDIR | MDBX_COALESCE | MDBX_LIFORECLAIM, 0664);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_env_open: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
rc = mdbx_txn_begin(env, NULL, 0, &txn);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_txn_begin: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
rc = mdbx_dbi_open(txn, "test", MDBX_DUPSORT | MDBX_DUPFIXED | MDBX_CREATE,
|
||||
&dbi);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_dbi_open: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char key_bytes[32] = {0};
|
||||
key.iov_len = 32;
|
||||
key.iov_base = key_bytes;
|
||||
|
||||
// Another put after this will fail.
|
||||
unsigned char idx;
|
||||
for (idx = 0; idx < 129; idx++) {
|
||||
char data_bytes[15] = {idx};
|
||||
data.iov_len = 15;
|
||||
data.iov_base = data_bytes;
|
||||
rc = mdbx_put(txn, dbi, &key, &data, 0);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_put: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// This will fail and exit.
|
||||
char data_bytes[15] = {idx};
|
||||
data.iov_len = 15;
|
||||
data.iov_base = data_bytes;
|
||||
rc = mdbx_put(txn, dbi, &key, &data, 0);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_put: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
fprintf(stderr, "expected failure\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
rc = mdbx_txn_commit(txn);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdbx_txn_commit: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
* Copyright 2016-2024 Leonid Yuriev <leo@yuriev.ru>.
|
||||
* Copyright 2015 Vladimir Romanov
|
||||
* <https://www.linkedin.com/in/vladimirromanov>, Yota Lab.
|
||||
*
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
#include <unistd.h>
|
||||
|
||||
static int dump(MDBX_cursor *cur) {
|
||||
MDBX_val key = {};
|
||||
MDBX_val data = {};
|
||||
MDBX_val key = {NULL, 0};
|
||||
MDBX_val data = {NULL, 0};
|
||||
int rc = mdbx_cursor_get(cur, &key, &data, MDBX_FIRST);
|
||||
|
||||
while (rc == 0) {
|
||||
@@ -25,15 +25,14 @@ static int dump(MDBX_cursor *cur) {
|
||||
}
|
||||
|
||||
static int clear(MDBX_cursor *cur) {
|
||||
MDBX_val key = {};
|
||||
MDBX_val data = {};
|
||||
MDBX_val key = {NULL, 0};
|
||||
MDBX_val data = {NULL, 0};
|
||||
int rc = mdbx_cursor_get(cur, &key, &data, MDBX_FIRST);
|
||||
|
||||
while (rc == 0) {
|
||||
rc = mdbx_cursor_del(cur, MDBX_ALLDUPS);
|
||||
if (rc) {
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
rc = mdbx_cursor_get(cur, &key, &data, MDBX_NEXT);
|
||||
}
|
||||
return (rc == MDBX_NOTFOUND) ? 0 : rc;
|
||||
@@ -183,6 +182,7 @@ int main(int argc, const char *argv[]) {
|
||||
errmsg = "failed to mdbx_txn_commit: %s\n";
|
||||
goto Fail;
|
||||
}
|
||||
mdbx_cursor_close(cur);
|
||||
if ((rc = mdbx_env_close(env))) {
|
||||
errmsg = "failed to mdbx_env_close: %s\n";
|
||||
goto Fail;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -99,6 +99,37 @@ bool testcase_jitter::run() {
|
||||
jitter_delay();
|
||||
txn_begin(true);
|
||||
fetch_canary();
|
||||
if (flipcoin()) {
|
||||
MDBX_txn_info info;
|
||||
err = mdbx_txn_reset(txn_guard.get());
|
||||
if (err)
|
||||
failure_perror("mdbx_txn_reset()", err);
|
||||
err = mdbx_txn_info(txn_guard.get(), &info, false);
|
||||
if (err != MDBX_BAD_TXN)
|
||||
failure_perror("mdbx_txn_info(MDBX_BAD_TXN)", err);
|
||||
err = mdbx_txn_reset(txn_guard.get());
|
||||
if (err)
|
||||
failure_perror("mdbx_txn_reset(again)", err);
|
||||
err = mdbx_txn_break(txn_guard.get());
|
||||
if (err)
|
||||
failure_perror("mdbx_txn_break()", err);
|
||||
|
||||
err = mdbx_txn_abort(txn_guard.get());
|
||||
if (err)
|
||||
failure_perror("mdbx_txn_abort()", err);
|
||||
txn_guard.release();
|
||||
txn_begin(true);
|
||||
err = mdbx_txn_reset(txn_guard.get());
|
||||
if (err)
|
||||
failure_perror("mdbx_txn_reset()", err);
|
||||
|
||||
err = mdbx_txn_renew(txn_guard.get());
|
||||
if (err)
|
||||
failure_perror("mdbx_txn_renew()", err);
|
||||
err = mdbx_txn_info(txn_guard.get(), &info, false);
|
||||
if (err)
|
||||
failure_perror("mdbx_txn_info()", err);
|
||||
}
|
||||
jitter_delay();
|
||||
txn_end(flipcoin());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -432,6 +432,12 @@ for nops in 10 33 100 333 1000 3333 10000 33333 100000 333333 1000000 3333333 10
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--keygen.seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=9 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="Probe #$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--keygen.seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=11 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
|
||||
split=24
|
||||
caption="Probe #$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
@@ -446,6 +452,12 @@ for nops in 10 33 100 333 1000 3333 10000 33333 100000 333333 1000000 3333333 10
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--keygen.seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=10 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="Probe #$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--keygen.seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=12 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
|
||||
split=16
|
||||
caption="Probe #$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
@@ -468,6 +480,12 @@ for nops in 10 33 100 333 1000 3333 10000 33333 100000 333333 1000000 3333333 10
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--keygen.seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=9 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="Probe #$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--keygen.seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=11 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
|
||||
if [ "$EXTRA" != "no" ]; then
|
||||
split=10
|
||||
@@ -491,6 +509,12 @@ for nops in 10 33 100 333 1000 3333 10000 33333 100000 333333 1000000 3333333 10
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--keygen.seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=13 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="Probe #$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--keygen.seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=16 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
fi
|
||||
|
||||
split=4
|
||||
@@ -506,6 +530,12 @@ for nops in 10 33 100 333 1000 3333 10000 33333 100000 333333 1000000 3333333 10
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=-data.dups --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--keygen.seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=21 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="Probe #$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--keygen.seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=32 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
done # options
|
||||
loop=$((loop + 1))
|
||||
if [ -n "$LOOPS" ] && [ $loop -ge "$LOOPS" ]; then break; fi
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -24,9 +24,9 @@ const char *testcase2str(const actor_testcase testcase) {
|
||||
case ac_hill:
|
||||
return "hill";
|
||||
case ac_deadread:
|
||||
return "deadread";
|
||||
return "dead.reader";
|
||||
case ac_deadwrite:
|
||||
return "deadwrite";
|
||||
return "dead.writer";
|
||||
case ac_jitter:
|
||||
return "jitter";
|
||||
case ac_try:
|
||||
@@ -733,6 +733,18 @@ void testcase::speculum_check_iterator(const char *where, const char *stage,
|
||||
mdbx_dump_val(&v, dump_value, sizeof(dump_value)));
|
||||
}
|
||||
|
||||
void testcase::failure(const char *fmt, ...) const {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fflush(nullptr);
|
||||
logging::output_nocheckloglevel_ap(logging::failure, fmt, ap);
|
||||
va_end(ap);
|
||||
fflush(nullptr);
|
||||
if (txn_guard)
|
||||
mdbx_txn_commit(const_cast<testcase *>(this)->txn_guard.release());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#if SPECULUM_CURSORS
|
||||
void testcase::speculum_check_cursor(const char *where, const char *stage,
|
||||
const testcase::SET::const_iterator &it,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -277,6 +277,7 @@ protected:
|
||||
void signal();
|
||||
bool should_continue(bool check_timeout_only = false) const;
|
||||
|
||||
void failure(const char *fmt, ...) const;
|
||||
void generate_pair(const keygen::serial_t serial, keygen::buffer &out_key,
|
||||
keygen::buffer &out_value, keygen::serial_t data_age) {
|
||||
keyvalue_maker.pair(serial, out_key, out_value, data_age, false);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2024 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user