Compare commits

...

53 Commits

Author SHA1 Message Date
Леонид Юрьев (Leonid Yuriev)
aea40fb79f mdbx: выпуск 0.12.10 "СЭМ"
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов
в память Героя России гвардии майора Дмитрия Семёнова с позывным "СЭМ".

Значимые исправления и доработки:
---------------------------------

 - Устранение унаследованной от LMDB ошибки приводящей к повреждению БД при использовании `MDBX_DUPFIXED`.

 - Исправление ложной ошибки `MDBX_CORRUPTED (-30796)` в сценарии работы
   в режиме `MDBX_DUPFIXED` и нечетной длинной мульти-значений.

 - Исправление недочета корректировки сопутствующих курсоров при разделении страницы
   по сценарию добавления пустой страницы слева.

 - Доработка `rebalance()` ради уменьшения WAF.

 - Исправление assert-проверки внутри `check_txn()` для случая завершенных транзакций в режиме `MDBX_NO_TLS`.
   Последствий ошибки, кроме срабатывания assert-проверки в отладочных сборках, нет.

 - Устранение ошибки при открытии БД на файловой системе только-для-чтения.

 - Удалены излишне строгие проверки в утилите `mdbx_chk`, которые
   приводили к ложно-позитивным ошибкам при проверке БД после серии
   последних доработок.

Более подробная информация в [ChangeLog](https://libmdbx.dqdkfa.ru/md__change_log.html).

git diff' stat: 19 commits, 57 files changed, 751 insertions(+), 331 deletions(-)
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
2024-03-13 14:57:38 +03:00
Леонид Юрьев (Leonid Yuriev)
0741c81cfd mdbx-chk: не считаем ошибкой под-страницы без данных пользователя.
Коммитом 36a7e7ac24 был скорректирован
подсчет места занимаемого заголовками и данными. В частности, байты
занимаемые заголовков вложенной под-страницы теперь относится к
заголовкам, а не пользовательским данным.

Однако, в случае когда на под-странице, созданной для хранения куста
мульти-значений (MDBX_DUPSORT), после серии удалений остаётся одно
значение, которое в MDBX может нулевой длины, получается под-страница с
нулевым количеством пользовательских данных. Этот коммит исправляет
2024-03-12 09:02:50 +03:00
Леонид Юрьев (Leonid Yuriev)
781b3f64d5 mdbx-chk: не считаем ошибочными/проблемными записи нулевой длины в GC.
Технически такие записи не являются проблемными, а образовываются в
случае когда внутри update_gc() резервируется больше места, чем реально
остается номеров свободных страниц для возврата в GC.

Изначально такое избыточное резервирование считалось алгоритмическим
недостатком update_gc(). Поэтому утилита mdbx_chk была временно
доработана для выявления таких случаев в ходе стохастических тестов.

Постепенно все реальные недочеты update_gc() (если не считать
запутанности и неочевидности кода) были устранены, формирование пустых
записей в GC не наблюдалось и излишне строгий контроль в mdbx_chk не
создавал проблем.

В ходе же последних точечных доработок была предпринята попытка еще
немного уменьшить затраты ЦПУ внутри update_gc(), в частности уменьшить
кол-во циклов/повторов посредством улучшения сходимости, а также
уменьшить WAF. При этом образование пустых записей в GC стало возможным
в достаточно редких ситуациях, когда (например) для возврата в GC
остается только одна страница и добавление записи единичной длины
приводит к перебалансировке или разделению листовой страницы по
легковесному пути, без вовлечения других страниц дерева и без
переработки дополнительных записей GC, но с поглощением остававшейся на
возврат страницы.

Проще говоря, в актуальная версии MDBX пустые записи в GC могут
образовываться, когда это энергетически выгодно. Тогда как в предыдущих
выпусках в таких ситуациях выполнялось более дорогое обновление GC с
переработкой и возвратом дополнительных записей.
2024-03-12 02:38:17 +03:00
Леонид Юрьев (Leonid Yuriev)
446d6c9421 mdbx: исправление ошибки открытия БД на ФС только-для-чтения. 2024-03-11 00:34:04 +03:00
Леонид Юрьев (Leonid Yuriev)
fff3fbd866 mdbx: обновление ChangeLog (подготовка к выпуску). 2024-03-06 22:58:31 +03:00
Леонид Юрьев (Leonid Yuriev)
3e850981c7 mdbx-test: расширение стохастического теста dupfixed-сценариями (backport). 2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
36a7e7ac24 mdbx-chk: исправление подсчета места затраченного на выравнивание в случае нечетного кол-ва dupfixed-элементов нечетного размера (backport). 2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
2d7fe42327 mdbx: корректировка условия в assert-проверке для MDBX_TXN_DRAINED_GC (backport). 2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
2b88c6261f mdbx-test: добавление в jitter простого теста txn_reset+txn_renew (backport). 2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
e515bd56e9 mdbx: исправление assert-проверки внутри check_txn() для случая завершенных транзакций в режиме MDBX_NO_TLS (backport).
По сообщению о проблеме https://t.me/libmdbx/5424
2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
20160ae98f mdbx: доработка rebalance() ради уменьшения WAF (backport).
После предыдущей серии доработок весной 2021 года, функция `rebalance()`
обеспечивала слияние мало заполненной страницы с менее заполненной
соседней, одновременно пытаясь не вовлекать соседних страниц, если те
еще не были скопированы/клонированы/изменены в текущей транзакции.

В целом, реализованная тактика представляется успешной. Однако, при
обновлении GC она иногда приводила к исчерпанию подготовленного резерва
извлеченных из GC страниц. Это не является проблемой, если не считать
вероятность срабатывания `assert(txn->mt_flags & MDBX_TXN_DRAINED_GC)`
в отладочных сборках.

Тем не менее, из этой ситуации можно сделать вывод, что поведение
`rebalance()`, как минимум, может быть обогащено опцией уменьшения WAF
ценой меньшей сбалансированности дерева. Технически при этом слияние
выполняется преимущественно с грязной страницей, если на ней достаточно
места и соседняя страница с другой стороны еще чистая.

ВАЖНО: Соответствующая опция в `enum MDBX_option_t` будет добавлена чуть
позже в следующую версию, а в текущих ветках `master` и `stable` это
именение поведение будет заглушено.
2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
ea97fbae74 mdbx: устранение yнаследованной от LMDB ошибки приводящей к повреждению БД при использовании MDBX_DUPFIXED (backport).
Тезисно:

 - Использование DUPFIXED (включая INTEGERDUP) могло приводить к
   повреждению БД и/или потере данных. Этот коммит устраняет эту угрозу.

 - Вероятность проявления существенно увеличивается с увеличением
   размера/длины мульти-значений/дубликатов (не ключей).

 - В MDBX проблема унаследована от LMDB, где существует более 11 лет,
   начиная с коммита ccc4d23e74
   и до настоящего времени.

Для вложенных страниц типа LEAF2 (которые содержат только значения
одинаковой длины, без таблицы смещений к ним), упомянутым выше коммитом,
было добавлено резервирование места (что в целом спорно, но в некоторых
сценариях позволяет уменьшить накладные расходы). Ошибка была в том, что
в коде не исключалась возможность превышения размера страницы БД, что
далее приводило к арифметическому переполнению, повреждению БД и/или
просписи памяти.
2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
a0a4af7701 mdbx: исправление me_dxb_mmap.current > me_dxb_mmap.limit и срабатывания соответствующей assert-проверки (backport).
Устранение упущения приводящего к нелогичной ситуации `me_dxb_mmap.curren > me_dxb_mmap.limit` при "дребезге" размера БД.
В текущем понимании, последствий кроме срабатывания assert-проверки нет, а вероятность проявления близка к нулю.
2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
74f2bc813b mdbx: продолжение очистки/рефакторинга унаследованных ребусов в cursor_put_nochecklen() (backport). 2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
1a18369015 mdbx-test: фиксация транзакции при ошибках теста для последующего анализа БД (backport). 2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
e2f2fd8652 mdbx: рефакторинг node_shrink() для ясности исходного кода (backport). 2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
fb6be62046 mdbx: исправление недочета корректировки сопутствующих курсоров при разделении страницы по сценарию добавления пустой страницы слева (backport). 2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
f7e6bd770a mdbx-test: соответствие протоколируемых имен тестов опциям командной строки (backport). 2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
ba5c74e54d mdbx-test: добавление extra/dupfixed_addodd (backport). 2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
049b71c148 mdbx: исправление ложной ошибки MDBX_CORRUPTED (-30796) в сценарии "odd dupfixed" (backport).
Повреждение БД и/или потери данных не происходило, проблема лишь в
возврате ложной ошибки.

Благодарю пользователя/разработчика @Dvirsw (https://t.me/Dvirsw) за
сообщения о проблеме и предоставление минимального/оптимального сценария
воспроизведения.

--

Проблема была из-за излишнего условия при контроле внутренего поля
mp_upper в ходе проверки структуры страниц БД.

Поле mp_upper указывает на нижнуюю границу заполнения страницы от конца
к началу. Вследствие того, что значения ключей выравниваетня на четную
границу, это поле четно во всех случаях за исключением LEAF2-страницы
(листовая страница вложенного дерева для множественных значений
финсированной/одинаковой длины одного ключа), на которой размещено
нечетное количество значений нечетной длины.

Ошибка не проявлялась в большинстве случаев (в том числе в
стохастических тестах), так как штатно лишняя проверка производилась
только при чтении страницы и перебалансировке ключей, но не при каждом
добавлении значения. Тем не менее, сценарии тестов требуют
доработки/расширения для явного добавления нечетных dupfixed-сценариев.
2024-03-06 13:18:58 +03:00
Леонид Юрьев (Leonid Yuriev)
185e43f3a8 mdbx: выпуск 0.12.9 "Ясень-4"
Стабилизирующий выпуск с исправлением обнаруженных ошибок и устранением недочетов.

Исправления и доработки:
------------------------

 - Ликвидация зависимости от ранее удаленной опции `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 от текущего количества страниц в БД.

Более подробная информация в [ChangeLog](https://libmdbx.dqdkfa.ru/md__change_log.html).

git diff' stat: 32 commits, 8 files changed, 667 insertions(+), 401 deletions(-)
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
2023-12-11 23:24:05 +03:00
Леонид Юрьев (Leonid Yuriev)
990d4ea042 mdbx: обновление ChangeLog. 2023-11-28 21:48:56 +03:00
Леонид Юрьев (Leonid Yuriev)
8d67d23224 mdbx: исправление несущественной опечатки в комментарии. 2023-11-28 21:45:41 +03:00
Леонид Юрьев (Leonid Yuriev)
4a7a2034c0 mdbx: новый размер MDBX_opt_rp_augment_limit по умолчанию в 1/3 от текущего кол-ва страниц в БД. 2023-11-28 21:45:21 +03:00
Леонид Юрьев (Leonid Yuriev)
d963f3a971 mdbx: обновление ChangeLog. 2023-11-28 09:36:29 +03:00
Леонид Юрьев (Leonid Yuriev)
fb15c8ca0b mdbx++: дополнительные операторы преобразования к типам C API (backport). 2023-11-28 09:36:29 +03:00
Леонид Юрьев (Leonid Yuriev)
b6034e8045 mdbx-test: правка тестов для совместимости с проблемными версиями glibc и glibc++ (backport). 2023-11-28 09:36:29 +03:00
Леонид Юрьев (Leonid Yuriev)
ae01a8e891 mdbx++: перенос в public типов buffer::move_assign_alloc и buffer::copy_assign_alloc для старых стандартов C++ (backport). 2023-11-28 09:36:29 +03:00
Леонид Юрьев (Leonid Yuriev)
1277fe965d mdbx++: переделка поддержки base58 по RFC-draft (backport). 2023-11-28 09:36:10 +03:00
Леонид Юрьев (Leonid Yuriev)
7fc6a1b658 mdbx++: переработка/исправление to_hex() (backport). 2023-11-28 01:18:24 +03:00
Леонид Юрьев (Leonid Yuriev)
b1abcb8260 mdbx++: использование slice::invalid() для предотвращения незаметного неверного использования API (backport). 2023-11-28 01:18:24 +03:00
Леонид Юрьев (Leonid Yuriev)
7cd3dbbccb mdbx++: добавление mdbx::default_buffer (backport). 2023-11-28 01:18:24 +03:00
Леонид Юрьев (Leonid Yuriev)
352dd75ee8 mdbx++: исправление опечатки в doxygen-описании (backport). 2023-11-28 01:16:38 +03:00
Леонид Юрьев (Leonid Yuriev)
cf1541e4d7 mdbx++: добавление get/set_context для транзакций и курсоров (backport). 2023-11-28 01:16:38 +03:00
Леонид Юрьев (Leonid Yuriev)
446dbc9d6c mdbx++: добавление cursor::clone() (backport). 2023-11-28 01:13:24 +03:00
Леонид Юрьев (Leonid Yuriev)
64a5ad8c04 mdbx++: добавление методов buffer::hex_decode(), base64_decode(), base58_decode() (backport). 2023-11-28 01:13:24 +03:00
Леонид Юрьев (Leonid Yuriev)
0fd0d527d9 mdbx++: добавление типа mdbx::comparator и функций mdbx::default_comparator() (backport). 2023-11-28 01:13:24 +03:00
Леонид Юрьев (Leonid Yuriev)
4bed5d1779 mdbx++: добавление статических методов buffer::hex(), base64(), base58() (backport). 2023-11-28 01:13:24 +03:00
Леонид Юрьев (Leonid Yuriev)
6e4473777e mdbx: проверка pid только для запроса активной env (backport). 2023-11-28 01:10:23 +03:00
Леонид Юрьев (Leonid Yuriev)
5abb6a9bbf mdbx-doc: удаление устаревшего упоминания MDBX_EAGAIN. 2023-11-17 21:18:21 +03:00
Леонид Юрьев (Leonid Yuriev)
c014685c01 mdbx: обновление ChangeLog. 2023-11-12 21:46:52 +03:00
Леонид Юрьев (Leonid Yuriev)
476da5f8cf mdbx++: добавление cursor::estimation_result и переделка cursor::estimate() (backport). 2023-11-12 21:30:09 +03:00
Леонид Юрьев (Leonid Yuriev)
b905a6a391 mdbx: const для начала и конца диапазона в аргументах mdbx_estimate_range() (backport). 2023-11-12 21:30:09 +03:00
Леонид Юрьев (Leonid Yuriev)
d94f34b2c0 mdbx: рефакторинг обработки MDBX_GET_MULTIPLE добавление проверки key на NULL (backport). 2023-11-12 21:30:09 +03:00
Леонид Юрьев (Leonid Yuriev)
f5ce7322c4 mdbx: исправление авто-установки MDBX_ENV_CHECKPID для случая MDBX_ENABLE_MADVISE=0 (backport). 2023-11-12 21:30:09 +03:00
Леонид Юрьев (Leonid Yuriev)
ab5d290f11 mdbx: проверка номеров корневых страниц в coherency_check() (backport). 2023-11-12 21:29:18 +03:00
Леонид Юрьев (Leonid Yuriev)
7eb2f4130e mdbx: использование const MDBX_txn где это возможно в API (backport). 2023-11-12 19:33:27 +03:00
Леонид Юрьев (Leonid Yuriev)
ed8c7ead4e mdbx: ликвидация ошибочной зависимости от удаленной опции MDBX_ENABLE_PREFAULT. 2023-10-29 12:20:54 +03:00
Леонид Юрьев (Leonid Yuriev)
080875cd6d mdbx: Обновление ChangeLog. 2023-10-23 18:13:35 +03:00
Леонид Юрьев (Leonid Yuriev)
753cfd00eb mdbx: обновление патча для старых версий buildroot. 2023-10-23 18:12:21 +03:00
Леонид Юрьев (Leonid Yuriev)
311a6e5d10 mdbx++: добавление забытого исключения mdbx::duplicated_lck_file. 2023-10-23 16:33:34 +03:00
Леонид Юрьев (Leonid Yuriev)
e58b582639 mdbx: исправление MDBX_LAST_ADDED_ERRCODE. 2023-10-23 16:33:30 +03:00
Леонид Юрьев (Leonid Yuriev)
e2ed55853d mdbx: удаление устаревших mdbx_set_compare() и mdbx_set_dupsort(). 2023-10-23 16:17:05 +03:00
59 changed files with 1418 additions and 732 deletions

View File

@@ -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.
##

View File

@@ -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.

View File

@@ -4,6 +4,151 @@ 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
@@ -379,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`.
- Изменение тактики слияния страниц при удалении.
Теперь слияние выполняется преимущественно с уже измененной/грязной страницей.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

40
mdbx.h
View File

@@ -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
@@ -1937,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,
@@ -2119,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
@@ -2352,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
@@ -4293,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.
@@ -4311,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()
@@ -4343,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);
}
@@ -4425,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
@@ -4458,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.
@@ -4489,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.
@@ -4731,7 +4731,7 @@ mdbx_cursor_get_userctx(const 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_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.
@@ -4764,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.
@@ -4807,7 +4807,7 @@ LIBMDBX_API void mdbx_cursor_close(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(MDBX_txn *txn, MDBX_cursor *cursor);
LIBMDBX_API int mdbx_cursor_renew(const MDBX_txn *txn, MDBX_cursor *cursor);
/** \brief Return the cursor's transaction handle.
* \ingroup c_cursors
@@ -5186,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()

305
mdbx.h++
View File

@@ -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:
@@ -362,8 +362,11 @@ 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;
@@ -558,6 +561,7 @@ 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();
@@ -732,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)
@@ -1321,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;
}
@@ -1487,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
@@ -1575,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 {
@@ -2070,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();
@@ -2338,6 +2344,126 @@ public:
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),
@@ -2982,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;
@@ -3007,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.
@@ -3444,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.
@@ -3802,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;
@@ -3838,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(
@@ -4037,10 +4178,12 @@ public:
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.
@@ -4121,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 *();
@@ -4129,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,
@@ -4153,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);
@@ -4164,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
@@ -4208,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;
@@ -4274,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);
}
@@ -5416,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) {
@@ -5456,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);
@@ -5854,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));
@@ -5886,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;
@@ -5924,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,
@@ -5966,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;
@@ -6088,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));
}

View File

@@ -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

View File

@@ -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.
*

View File

@@ -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.
*

File diff suppressed because it is too large Load Diff

View File

@@ -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 */

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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-10-17" "MDBX 0.12.8"
.TH MDBX_CHK 1 "2024-03-13" "MDBX 0.12.10"
.SH NAME
mdbx_chk \- MDBX checking tool
.SH SYNOPSIS

View File

@@ -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-10-17" "MDBX 0.12.8"
.TH MDBX_COPY 1 "2024-03-13" "MDBX 0.12.10"
.SH NAME
mdbx_copy \- MDBX environment copy tool
.SH SYNOPSIS

View File

@@ -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-10-17" "MDBX 0.12.8"
.TH MDBX_DROP 1 "2024-03-13" "MDBX 0.12.10"
.SH NAME
mdbx_drop \- MDBX database delete tool
.SH SYNOPSIS

View File

@@ -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-10-17" "MDBX 0.12.8"
.TH MDBX_DUMP 1 "2024-03-13" "MDBX 0.12.10"
.SH NAME
mdbx_dump \- MDBX environment export tool
.SH SYNOPSIS

View File

@@ -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-10-17" "MDBX 0.12.8"
.TH MDBX_LOAD 1 "2024-03-13" "MDBX 0.12.10"
.SH NAME
mdbx_load \- MDBX environment import tool
.SH SYNOPSIS

View File

@@ -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-10-17" "MDBX 0.12.8"
.TH MDBX_STAT 1 "2024-03-13" "MDBX 0.12.10"
.SH NAME
mdbx_stat \- MDBX environment status tool
.SH SYNOPSIS

View File

@@ -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
//------------------------------------------------------------------------------
@@ -285,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 {
@@ -371,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())
@@ -598,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) {
@@ -607,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);
}
@@ -620,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) {
@@ -629,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;
}
}
@@ -661,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;
@@ -708,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;
@@ -883,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,
@@ -895,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;
}
//------------------------------------------------------------------------------

View File

@@ -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",

View File

@@ -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.
*

View File

@@ -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.

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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

View File

@@ -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

View File

@@ -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.
*

View File

@@ -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}")
@@ -168,6 +172,7 @@ else()
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)

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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;

View File

@@ -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.
*

View File

@@ -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.
*

View 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);
}
}

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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());
}

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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,

View File

@@ -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);

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*