mirror of
https://github.com/isar/libmdbx.git
synced 2025-06-06 17:32:37 +08:00
mdbx: update README and refine API description.
Change-Id: I162eab823df0dbf6528dce74a9b9842fb8b79d1b
This commit is contained in:
parent
83da954725
commit
22f6e53520
840
README-RU.md
840
README-RU.md
@ -1,840 +0,0 @@
|
|||||||
### The [repository now only mirrored on the Github](https://abf.io/erthink/libmdbx) due to illegal discriminatory restrictions for Russian Crimea and for sovereign crimeans.
|
|
||||||
<!-- Required extensions: pymdownx.betterem, pymdownx.tilde, pymdownx.emoji, pymdownx.tasklist, pymdownx.superfences -->
|
|
||||||
-----
|
|
||||||
|
|
||||||
libmdbx
|
|
||||||
======================================
|
|
||||||
Доработанный и расширенный потомок [Lightning Memory-Mapped
|
|
||||||
Database](https://ru.bmstu.wiki/LMDB_(Lightning_Memory-Mapped_Database))
|
|
||||||
(aka _LMDB_). Свободная не-копилефт BSD-подобная лицензия [OpenLDAP
|
|
||||||
Public License 2.8](LICENSE). English version of this README is [here](README.md).
|
|
||||||
|
|
||||||
_libmdbx_ превосходит LMDB по возможностям и надежности, не уступая в
|
|
||||||
производительности. _libmdbx_ работает на Linux, FreeBSD, MacOS X и
|
|
||||||
других ОС соответствующих POSIX.1-2008, а также поддерживает Windows в
|
|
||||||
качестве дополнительной платформы.
|
|
||||||
|
|
||||||
Отдельно ведётся не-публичная разработка следующей версии, которая будет
|
|
||||||
называться **_MithrilDB_** и `libmithrildb` в виде библиотек и пакетов.
|
|
||||||
Мифический
|
|
||||||
[Мифрил](https://ru.wikipedia.org/wiki/%D0%9C%D0%B8%D1%84%D1%80%D0%B8%D0%BB)
|
|
||||||
похож на серебро, но прочнее и легче стали. Поэтому _MithrilDB_
|
|
||||||
представляется подходящим и отражающим суть названием.
|
|
||||||
|
|
||||||
_MithrilDB_ будет кардинально отличаться от _libmdbx_ новым форматом
|
|
||||||
базы данных и API основанным на C++17, а также [Лицензией Apache
|
|
||||||
2.0](https://www.apache.org/licenses/LICENSE-2.0). Цель этой революции -
|
|
||||||
обеспечение более четкого и надежного API, добавление новых функций, а
|
|
||||||
также наделение базы данных новыми свойствами.
|
|
||||||
|
|
||||||
*Всё будет хорошо. The Future will (be) [Positive](https://www.ptsecurity.ru).*
|
|
||||||
|
|
||||||
[](https://travis-ci.org/leo-yuriev/libmdbx)
|
|
||||||
[](https://ci.appveyor.com/project/leo-yuriev/libmdbx/branch/master)
|
|
||||||
[](https://scan.coverity.com/projects/reopen-libmdbx)
|
|
||||||
|
|
||||||
## Содержание
|
|
||||||
- [Обзор](#Обзор)
|
|
||||||
- [Сравнение с другими базами данных](#Сравнение-с-другими-базами-данных)
|
|
||||||
- [История & Выражение признательности](#История)
|
|
||||||
- [Описание](#Описание)
|
|
||||||
- [Ключевые свойства](#Ключевые-свойства)
|
|
||||||
- [Доработки и усовершенствования относительно LMDB](#Доработки-и-усовершенствования-относительно-lmdb)
|
|
||||||
- [Недостатки и Компромиссы](#Недостатки-и-Компромиссы)
|
|
||||||
- [Проблема долгих чтений](#Проблема-долгих-чтений)
|
|
||||||
- [Сохранность данных в режиме асинхронной фиксации](#Сохранность-данных-в-режиме-асинхронной-фиксации)
|
|
||||||
- [Использование](#Использование)
|
|
||||||
- [Сборка](#Сборка)
|
|
||||||
- [Привязки к другим языкам](#Привязки-к-другим-языкам)
|
|
||||||
- [Сравнение производительности](#Сравнение-производительности)
|
|
||||||
- [Интегральная производительность](#Интегральная-производительность)
|
|
||||||
- [Масштабируемость чтения](#Масштабируемость-чтения)
|
|
||||||
- [Синхронная фиксация](#Синхронная-фиксация)
|
|
||||||
- [Отложенная фиксация](#Отложенная-фиксация)
|
|
||||||
- [Асинхронная фиксация](#Асинхронная-фиксация)
|
|
||||||
- [Потребление ресурсов](#Потребление-ресурсов)
|
|
||||||
|
|
||||||
-----
|
|
||||||
|
|
||||||
## Обзор
|
|
||||||
_libmdbx_ - это встраиваемый key-value движок хранения со специфическим
|
|
||||||
набором свойств и возможностей, ориентированный на создание уникальных
|
|
||||||
легковесных решений с предельной производительностью.
|
|
||||||
|
|
||||||
_libmdbx_ позволяет множеству процессов совместно читать и обновлять
|
|
||||||
несколько key-value таблиц с соблюдением
|
|
||||||
[ACID](https://ru.wikipedia.org/wiki/ACID), при минимальных накладных
|
|
||||||
расходах и амортизационной стоимости любых операций Olog(N).
|
|
||||||
|
|
||||||
_libmdbx_ обеспечивает
|
|
||||||
[serializability](https://en.wikipedia.org/wiki/Serializability)
|
|
||||||
изменений и согласованность данных после аварий. При этом транзакции,
|
|
||||||
изменяющие данные, никак не мешают операциям чтения и выполняются строго
|
|
||||||
последовательно с использованием единственного
|
|
||||||
[мьютекса](https://en.wikipedia.org/wiki/Mutual_exclusion).
|
|
||||||
|
|
||||||
_libmdbx_ позволяет выполнять операции чтения с гарантиями
|
|
||||||
[wait-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom),
|
|
||||||
параллельно на каждом ядре CPU, без использования атомарных операций
|
|
||||||
и/или примитивов синхронизации.
|
|
||||||
|
|
||||||
_libmdbx_ не использует
|
|
||||||
[LSM](https://en.wikipedia.org/wiki/Log-structured_merge-tree), а
|
|
||||||
основан на [B+Tree](https://en.wikipedia.org/wiki/B%2B_tree) с
|
|
||||||
[отображением](https://en.wikipedia.org/wiki/Memory-mapped_file) всех
|
|
||||||
данных в память, при этом текущая версия не использует
|
|
||||||
[WAL](https://en.wikipedia.org/wiki/Write-ahead_logging). Это
|
|
||||||
предопределяет многие свойства, в том числе удачные и противопоказанные
|
|
||||||
сценарии использования.
|
|
||||||
|
|
||||||
|
|
||||||
### Сравнение с другими базами данных
|
|
||||||
|
|
||||||
На данный момент, пожалуйста, обратитесь к [главе "сравнение BoltDB с
|
|
||||||
другими базами
|
|
||||||
данных"](https://github.com/coreos/bbolt#comparison-with-other-databases),
|
|
||||||
которая также (в основном) применима к MDBX.
|
|
||||||
|
|
||||||
|
|
||||||
### История
|
|
||||||
_libmdbx_ является результатом переработки и развития "Lightning
|
|
||||||
Memory-Mapped Database", известной под аббревиатурой
|
|
||||||
[LMDB](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
|
|
||||||
Изначально доработка производилась в составе проекта
|
|
||||||
[ReOpenLDAP](https://github.com/leo-yuriev/ReOpenLDAP). Примерно за год
|
|
||||||
работы внесенные изменения приобрели самостоятельную ценность. Осенью
|
|
||||||
2015 доработанный движок был выделен в отдельный проект, который был
|
|
||||||
[представлен на конференции Highload++
|
|
||||||
2015](http://www.highload.ru/2015/abstracts/1831.html).
|
|
||||||
|
|
||||||
В начале 2017 года движок _libmdbx_ получил новый импульс развития,
|
|
||||||
благодаря использованию в [Fast Positive
|
|
||||||
Tables](https://github.com/leo-yuriev/libfpta), aka ["Позитивные
|
|
||||||
Таблицы"](https://github.com/leo-yuriev/libfpta) by [Positive
|
|
||||||
Technologies](https://www.ptsecurity.ru).
|
|
||||||
|
|
||||||
|
|
||||||
### Выражение признательности
|
|
||||||
|
|
||||||
Говард Чу (Howard Chu) <hyc@openldap.org> является автором движка LMDB, от
|
|
||||||
которого в 2015 году произошел MDBX.
|
|
||||||
|
|
||||||
Мартин Хеденфальк (Martin Hedenfalk) <martin@bzero.se> является автором кода
|
|
||||||
`btree.c`, который использовался для начала разработки LMDB.
|
|
||||||
|
|
||||||
-----
|
|
||||||
|
|
||||||
Описание
|
|
||||||
========
|
|
||||||
|
|
||||||
## Ключевые свойства
|
|
||||||
|
|
||||||
_libmdbx_ наследует все ключевые возможности и особенности своего
|
|
||||||
прародителя
|
|
||||||
[LMDB](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database),
|
|
||||||
но с устранением ряда описываемых далее проблем и архитектурных
|
|
||||||
недочетов.
|
|
||||||
|
|
||||||
1. Данные хранятся в упорядоченном отображении (ordered map), ключи
|
|
||||||
всегда отсортированы, поддерживается выборка диапазонов (range lookups).
|
|
||||||
|
|
||||||
2. Данные отображается в память каждого работающего с БД процесса. К
|
|
||||||
данным и ключам обеспечивается прямой доступ в памяти без необходимости
|
|
||||||
их копирования.
|
|
||||||
|
|
||||||
3. Транзакции согласно [ACID](https://ru.wikipedia.org/wiki/ACID),
|
|
||||||
посредством [MVCC](https://ru.wikipedia.org/wiki/MVCC) и
|
|
||||||
[COW](https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B8_%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D0%B8).
|
|
||||||
Изменения строго последовательны и не блокируются чтением, конфликты
|
|
||||||
между транзакциями невозможны. При этом гарантируется чтение только
|
|
||||||
зафиксированных данных, см [relaxing
|
|
||||||
serializability](https://en.wikipedia.org/wiki/Serializability).
|
|
||||||
|
|
||||||
4. Чтение и поиск [без
|
|
||||||
блокировок](https://ru.wikipedia.org/wiki/%D0%9D%D0%B5%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B0%D1%8F_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F),
|
|
||||||
без [атомарных
|
|
||||||
операций](https://ru.wikipedia.org/wiki/%D0%90%D1%82%D0%BE%D0%BC%D0%B0%D1%80%D0%BD%D0%B0%D1%8F_%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F).
|
|
||||||
Читатели не блокируются операциями записи и не конкурируют между собой,
|
|
||||||
чтение масштабируется линейно по ядрам CPU.
|
|
||||||
> Для точности следует отметить, что "подключение к БД" (старт первой
|
|
||||||
> читающей транзакции в потоке) и "отключение от БД" (закрытие БД или
|
|
||||||
> завершение потока) требуют краткосрочного захвата блокировки для
|
|
||||||
> регистрации/дерегистрации текущего потока в "таблице читателей".
|
|
||||||
|
|
||||||
5. Эффективное хранение дубликатов (ключей с несколькими значениями),
|
|
||||||
без дублирования ключей, с сортировкой значений, в том числе
|
|
||||||
целочисленных (для вторичных индексов).
|
|
||||||
|
|
||||||
6. Эффективная поддержка коротких ключей фиксированной длины, в том
|
|
||||||
числе целочисленных.
|
|
||||||
|
|
||||||
7. Амортизационная стоимость любой операции Olog(N),
|
|
||||||
[WAF](https://en.wikipedia.org/wiki/Write_amplification) (Write
|
|
||||||
Amplification Factor) и RAF (Read Amplification Factor) также Olog(N).
|
|
||||||
|
|
||||||
8. Нет [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) и
|
|
||||||
журнала транзакций, после сбоев не требуется восстановление. Не
|
|
||||||
требуется компактификация или какое-либо периодическое обслуживание.
|
|
||||||
Поддерживается резервное копирование "по горячему", на работающей БД без
|
|
||||||
приостановки изменения данных.
|
|
||||||
|
|
||||||
9. Отсутствует какое-либо внутреннее управление памятью или
|
|
||||||
кэшированием. Всё необходимое штатно выполняет ядро ОС.
|
|
||||||
|
|
||||||
|
|
||||||
## Доработки и усовершенствования относительно LMDB
|
|
||||||
|
|
||||||
1. Автоматическое динамическое управление размером БД согласно
|
|
||||||
параметрам задаваемым функцией `mdbx_env_set_geometry()`, включая шаг
|
|
||||||
приращения и порог уменьшения размера БД, а также выбор размера
|
|
||||||
страницы. Соответственно, это позволяет снизить фрагментированность
|
|
||||||
файла БД на диске и освободить место, в том числе в **Windows**.
|
|
||||||
|
|
||||||
2. Автоматическая без-затратная компактификация БД путем возврата
|
|
||||||
освобождающихся страниц в область нераспределенного резерва в конце
|
|
||||||
файла данных. При этом уменьшается количество страниц находящихся в
|
|
||||||
памяти и участвующих в в обмене с диском.
|
|
||||||
|
|
||||||
3. Режим `LIFO RECLAIM`.
|
|
||||||
|
|
||||||
Для повторного использования выбираются не самые старые, а
|
|
||||||
самые новые страницы из доступных. За счет этого цикл
|
|
||||||
использования страниц всегда имеет минимальную длину и не
|
|
||||||
зависит от общего числа выделенных страниц.
|
|
||||||
|
|
||||||
В результате механизмы кэширования и обратной записи работают с
|
|
||||||
максимально возможной эффективностью. В случае использования
|
|
||||||
контроллера дисков или системы хранения с
|
|
||||||
[BBWC](https://en.wikipedia.org/wiki/BBWC) возможно
|
|
||||||
многократное увеличение производительности по записи
|
|
||||||
(обновлению данных).
|
|
||||||
|
|
||||||
4. Быстрая оценка количества элементов попадающих в запрашиваемый
|
|
||||||
диапазон значений ключа посредством функций `mdbx_estimate_range()`,
|
|
||||||
`mdbx_estimate_move()` и `mdbx_estimate_distance()` для выбора
|
|
||||||
оптимального плана выполнения запроса.
|
|
||||||
|
|
||||||
5. Утилита `mdbx_chk` для проверки целостности структуры БД.
|
|
||||||
|
|
||||||
6. Поддержка ключей и значений нулевой длины, включая сортированные
|
|
||||||
дубликаты.
|
|
||||||
|
|
||||||
7. Возможность связать с каждой завершаемой транзакцией до 3
|
|
||||||
дополнительных маркеров посредством `mdbx_canary_put()`, и прочитать их
|
|
||||||
в транзакции чтения посредством `mdbx_canary_get()`.
|
|
||||||
|
|
||||||
8. Возможность посредством `mdbx_replace()` обновить или удалить запись
|
|
||||||
с получением предыдущего значения данных, а также адресно изменить
|
|
||||||
конкретное multi-значение.
|
|
||||||
|
|
||||||
9. Генерация последовательностей посредством `mdbx_dbi_sequence()`.
|
|
||||||
|
|
||||||
10. Обработчик `OOM-KICK`.
|
|
||||||
|
|
||||||
Посредством `mdbx_env_set_oomfunc()` может быть установлен
|
|
||||||
внешний обработчик (callback), который будет вызван при
|
|
||||||
исчерпании свободных страниц по причине долгой операцией чтения
|
|
||||||
на фоне интенсивного изменения данных.
|
|
||||||
Обработчику будет передан PID и pthread_id виновника.
|
|
||||||
В свою очередь обработчик может предпринять одно из действий:
|
|
||||||
|
|
||||||
* нейтрализовать виновника (отправить сигнал kill #9), если
|
|
||||||
долгое чтение выполняется сторонним процессом;
|
|
||||||
|
|
||||||
* отменить или перезапустить проблемную операцию чтения, если
|
|
||||||
операция выполняется одним из потоков текущего процесса;
|
|
||||||
|
|
||||||
* подождать некоторое время, в расчете на то, что проблемная операция
|
|
||||||
чтения будет штатно завершена;
|
|
||||||
|
|
||||||
* прервать текущую операцию изменения данных с возвратом кода
|
|
||||||
ошибки.
|
|
||||||
|
|
||||||
11. Возможность открыть БД в эксклюзивном режиме посредством флага
|
|
||||||
`MDBX_EXCLUSIVE`, в том числе на сетевом носителе.
|
|
||||||
|
|
||||||
12. Возможность получить отставание текущей транзакции чтения от
|
|
||||||
последней версии данных в БД посредством `mdbx_txn_straggler()`.
|
|
||||||
|
|
||||||
13. Возможность явно запросить обновление существующей записи, без
|
|
||||||
создания новой посредством флажка `MDBX_CURRENT` для `mdbx_put()`.
|
|
||||||
|
|
||||||
14. Исправленный вариант `mdbx_cursor_count()`, возвращающий корректное
|
|
||||||
количество дубликатов для всех типов таблиц и любого положения курсора.
|
|
||||||
|
|
||||||
15. Возможность получить посредством `mdbx_env_info()` дополнительную
|
|
||||||
информацию, включая номер самой старой версии БД (снимка данных),
|
|
||||||
который используется одним из читателей.
|
|
||||||
|
|
||||||
16. Функция `mdbx_del()` не игнорирует дополнительный (уточняющий)
|
|
||||||
аргумент `data` для таблиц без дубликатов (без флажка `MDBX_DUPSORT`), а
|
|
||||||
при его ненулевом значении всегда использует его для сверки с удаляемой
|
|
||||||
записью.
|
|
||||||
|
|
||||||
17. Возможность открыть dbi-таблицу, одновременно с установкой
|
|
||||||
компараторов для ключей и данных, посредством `mdbx_dbi_open_ex()`.
|
|
||||||
|
|
||||||
18. Возможность посредством `mdbx_is_dirty()` определить находятся ли
|
|
||||||
некоторый ключ или данные в "грязной" странице БД. Таким образом,
|
|
||||||
избегая лишнего копирования данных перед выполнением модифицирующих
|
|
||||||
операций (значения, размещенные в "грязных" страницах, могут быть
|
|
||||||
перезаписаны при изменениях, иначе они будут неизменны).
|
|
||||||
|
|
||||||
19. Корректное обновление текущей записи, в том числе сортированного
|
|
||||||
дубликата, при использовании режима `MDBX_CURRENT` в
|
|
||||||
`mdbx_cursor_put()`.
|
|
||||||
|
|
||||||
20. Возможность узнать есть ли за текущей позицией курсора строка данных
|
|
||||||
посредством `mdbx_cursor_eof()`.
|
|
||||||
|
|
||||||
21. Дополнительный код ошибки `MDBX_EMULTIVAL`, который возвращается из
|
|
||||||
`mdbx_put()` и `mdbx_replace()` при попытке выполнить неоднозначное
|
|
||||||
обновление или удаления одного из нескольких значений с одним ключом.
|
|
||||||
|
|
||||||
22. Возможность посредством `mdbx_get_ex()` получить значение по
|
|
||||||
заданному ключу, одновременно с количеством дубликатов.
|
|
||||||
|
|
||||||
23. Наличие функций `mdbx_cursor_on_first()` и `mdbx_cursor_on_last()`,
|
|
||||||
которые позволяют быстро выяснить стоит ли курсор на первой/последней
|
|
||||||
позиции.
|
|
||||||
|
|
||||||
24. Возможность автоматического формирования контрольных точек (сброса
|
|
||||||
данных на диск) при накоплении заданного объёма изменений,
|
|
||||||
устанавливаемого функцией `mdbx_env_set_syncbytes()`.
|
|
||||||
|
|
||||||
25. Управление отладкой и получение отладочных сообщений посредством
|
|
||||||
`mdbx_setup_debug()`.
|
|
||||||
|
|
||||||
26. Функция `mdbx_env_pgwalk()` для обхода всех страниц БД.
|
|
||||||
|
|
||||||
27. Три мета-страницы вместо двух, что позволяет гарантированно
|
|
||||||
консистентно обновлять слабые контрольные точки фиксации без риска
|
|
||||||
повредить крайнюю сильную точку фиксации.
|
|
||||||
|
|
||||||
28. Гарантия сохранности БД в режиме `WRITEMAP+MAPSYNC`.
|
|
||||||
> В текущей версии _libmdbx_ вам предоставляется выбор между безопасным
|
|
||||||
> режимом (по умолчанию) асинхронной фиксации, и режимом `UTTERLY_NOSYNC`
|
|
||||||
> когда при системной аварии есть шанс полного разрушения БД как в LMDB.
|
|
||||||
> Для подробностей смотрите раздел
|
|
||||||
> [Сохранность данных в режиме асинхронной фиксации](#Сохранность-данных-в-режиме-асинхронной-фиксации).
|
|
||||||
|
|
||||||
29. Возможность закрыть БД в "грязном" состоянии (без сброса данных и
|
|
||||||
формирования сильной точки фиксации) посредством `mdbx_env_close_ex()`.
|
|
||||||
|
|
||||||
30. При завершении читающих транзакций, открытые в них DBI-хендлы не
|
|
||||||
закрываются и не теряются при завершении таких транзакций посредством
|
|
||||||
`mdbx_txn_abort()` или `mdbx_txn_reset()`. Что позволяет избавится от ряда
|
|
||||||
сложно обнаруживаемых ошибок.
|
|
||||||
|
|
||||||
31. Все курсоры, как в транзакциях только для чтения, так и в пишущих,
|
|
||||||
могут быть переиспользованы посредством `mdbx_cursor_renew()` и ДОЛЖНЫ
|
|
||||||
ОСВОБОЖДАТЬСЯ ЯВНО.
|
|
||||||
>
|
|
||||||
> ## _ВАЖНО_, Обратите внимание!
|
|
||||||
>
|
|
||||||
> Это единственное изменение в API, которое значимо меняет
|
|
||||||
> семантику управления курсорами и может приводить к утечкам
|
|
||||||
> памяти. Следует отметить, что это изменение вынужденно.
|
|
||||||
> Так устраняется неоднозначность с массой тяжких последствий:
|
|
||||||
>
|
|
||||||
> - обращение к уже освобожденной памяти;
|
|
||||||
> - попытки повторного освобождения памяти;
|
|
||||||
> - повреждение памяти и ошибки сегментации.
|
|
||||||
|
|
||||||
32. На **MacOS X** для синхронизации данных с диском _по-умолчанию_
|
|
||||||
используется системная функция `fcntl(F_FULLFSYNC)`, так как [только
|
|
||||||
этим гарантируется сохранность
|
|
||||||
данных](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsync.2.html)
|
|
||||||
при сбое электропитания. К сожалению, в сценариях с высокой
|
|
||||||
интенсивностью пишущих транзакций, использование `F_FULLFSYNC` приводит
|
|
||||||
к существенной деградации производительности в сравнении с LMDB, где
|
|
||||||
используется системная функция `fsync()`. Поэтому _libmdbx_ позволяет
|
|
||||||
переопределить это поведение определением опции
|
|
||||||
`MDBX_OSX_SPEED_INSTEADOF_DURABILITY=1` при сборке библиотеки.
|
|
||||||
|
|
||||||
33. На **Windows** _libmdbx_ использует файловые блокировки
|
|
||||||
`LockFileEx()`, так как это позволяет размещать БД на сетевых дисках, а
|
|
||||||
также обеспечивает защиту от некомпетентных действий пользователя
|
|
||||||
([защиту от
|
|
||||||
дурака](https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%B0_%D0%BE%D1%82_%D0%B4%D1%83%D1%80%D0%B0%D0%BA%D0%B0)).
|
|
||||||
Поэтому _libmdbx_ может немного отставать в тестах производительность от
|
|
||||||
LMDB, где используются именованные мьютексы.
|
|
||||||
|
|
||||||
|
|
||||||
## Недостатки и Компромиссы
|
|
||||||
|
|
||||||
1. Единовременно может выполняться не более одной транзакция изменения данных
|
|
||||||
(один писатель). Зато все изменения всегда последовательны, не может быть
|
|
||||||
конфликтов или логических ошибок при откате транзакций.
|
|
||||||
|
|
||||||
2. Отсутствие [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging)
|
|
||||||
обуславливает относительно большой
|
|
||||||
[WAF](https://en.wikipedia.org/wiki/Write_amplification) (Write
|
|
||||||
Amplification Factor). Поэтому фиксация изменений на диске может быть
|
|
||||||
достаточно дорогой и являться главным ограничением производительности
|
|
||||||
при интенсивном изменении данных.
|
|
||||||
> В качестве компромисса _libmdbx_ предлагает несколько режимов ленивой
|
|
||||||
> и/или периодической фиксации. В том числе режим `MAPASYNC`, при котором
|
|
||||||
> изменения происходят только в памяти и асинхронно фиксируются на диске
|
|
||||||
> ядром ОС.
|
|
||||||
>
|
|
||||||
> Однако, следует воспринимать это свойство аккуратно и взвешенно.
|
|
||||||
> Например, полная фиксация транзакции в БД с журналом потребует минимум 2
|
|
||||||
> IOPS (скорее всего 3-4) из-за накладных расходов в файловой системе. В
|
|
||||||
> _libmdbx_ фиксация транзакции также требует от 2 IOPS. Однако, в БД с
|
|
||||||
> журналом кол-во IOPS будет меняться в зависимости от файловой системы,
|
|
||||||
> но не от кол-ва записей или их объема. Тогда как в _libmdbx_ кол-во
|
|
||||||
> будет расти логарифмически от кол-ва записей/строк в БД (по высоте
|
|
||||||
> b+tree).
|
|
||||||
|
|
||||||
3. [COW](https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B8_%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D0%B8)
|
|
||||||
для реализации [MVCC](https://ru.wikipedia.org/wiki/MVCC) выполняется на
|
|
||||||
уровне страниц в [B+
|
|
||||||
дереве](https://ru.wikipedia.org/wiki/B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE).
|
|
||||||
Поэтому изменение данных амортизационно требует копирования Olog(N)
|
|
||||||
страниц, что расходует [пропускную способность оперативной
|
|
||||||
памяти](https://en.wikipedia.org/wiki/Memory_bandwidth) и является
|
|
||||||
основным ограничителем производительности в режиме `MAPASYNC`.
|
|
||||||
> Этот недостаток неустраним, тем не менее следует дать некоторые пояснения.
|
|
||||||
> Дело в том, что фиксация изменений на диске потребует гораздо более
|
|
||||||
> значительного копирования данных в памяти и массы других затратных операций.
|
|
||||||
> Поэтому обусловленное этим недостатком падение производительности становится
|
|
||||||
> заметным только при отказе от фиксации изменений на диске.
|
|
||||||
> Соответственно, корректнее сказать, что _libmdbx_ позволяет
|
|
||||||
> получить персистентность ценой минимального падения производительности.
|
|
||||||
> Если же нет необходимости оперативно сохранять данные, то логичнее
|
|
||||||
> использовать `std::map`.
|
|
||||||
|
|
||||||
4. В _LMDB_ существует проблема долгих чтений (приостановленных читателей),
|
|
||||||
которая приводит к деградации производительности и переполнению БД.
|
|
||||||
> В _libmdbx_ предложены средства для предотвращения, быстрого выхода из
|
|
||||||
> некомфортной ситуации и устранения её последствий. Подробности ниже.
|
|
||||||
|
|
||||||
5. В _LMDB_ есть вероятность разрушения БД в режиме `WRITEMAP+MAPASYNC`.
|
|
||||||
В _libmdbx_ для `WRITEMAP+MAPASYNC` гарантируется как сохранность базы,
|
|
||||||
так и согласованность данных.
|
|
||||||
> Дополнительно, в качестве альтернативы, предложен режим `UTTERLY_NOSYNC`.
|
|
||||||
> Подробности ниже.
|
|
||||||
|
|
||||||
|
|
||||||
### Проблема долгих чтений
|
|
||||||
*Следует отметить*, что проблема "сборки мусора" так или иначе
|
|
||||||
существует во всех СУБД (Vacuum в PostgreSQL). Однако в случае _libmdbx_
|
|
||||||
и LMDB она проявляется более остро, прежде всего из-за высокой
|
|
||||||
производительности, а также из-за намеренного упрощения внутренних
|
|
||||||
механизмов ради производительности.
|
|
||||||
|
|
||||||
Понимание проблемы требует некоторых пояснений, которые
|
|
||||||
изложены ниже, но могут быть сложны для быстрого восприятия.
|
|
||||||
Поэтому, тезисно:
|
|
||||||
|
|
||||||
* Изменение данных на фоне долгой операции чтения может
|
|
||||||
приводить к исчерпанию места в БД.
|
|
||||||
|
|
||||||
* После чего любая попытка обновить данные будет приводить к
|
|
||||||
ошибке `MAP_FULL` до завершения долгой операции чтения.
|
|
||||||
|
|
||||||
* Характерными примерами долгих чтений являются горячее
|
|
||||||
резервное копирования и отладка клиентского приложения при
|
|
||||||
активной транзакции чтения.
|
|
||||||
|
|
||||||
* В оригинальной _LMDB_ после этого будет наблюдаться
|
|
||||||
устойчивая деградация производительности всех механизмов
|
|
||||||
обратной записи на диск (в I/O контроллере, в гипервизоре,
|
|
||||||
в ядре ОС).
|
|
||||||
|
|
||||||
* В _libmdbx_ предусмотрен механизм аварийного прерывания таких
|
|
||||||
операций, а также режим `LIFO RECLAIM` устраняющий последующую
|
|
||||||
деградацию производительности.
|
|
||||||
|
|
||||||
Операции чтения выполняются в контексте снимка данных (версии
|
|
||||||
БД), который был актуальным на момент старта транзакции чтения. Такой
|
|
||||||
читаемый снимок поддерживается неизменным до завершения операции. В свою
|
|
||||||
очередь, это не позволяет повторно использовать страницы БД в
|
|
||||||
последующих версиях (снимках БД).
|
|
||||||
|
|
||||||
Другими словами, если обновление данных выполняется на фоне долгой
|
|
||||||
операции чтения, то вместо повторного использования "старых" ненужных
|
|
||||||
страниц будут выделяться новые, так как "старые" страницы составляют
|
|
||||||
снимок БД, который еще используется долгой операцией чтения.
|
|
||||||
|
|
||||||
В результате, при интенсивном изменении данных и достаточно длительной
|
|
||||||
операции чтения, в БД могут быть исчерпаны свободные страницы, что не
|
|
||||||
позволит создавать новые снимки/версии БД. Такая ситуация будет
|
|
||||||
сохраняться до завершения операции чтения, которая использует старый
|
|
||||||
снимок данных и препятствует повторному использованию страниц БД.
|
|
||||||
|
|
||||||
Однако, на этом проблемы не заканчиваются. После описанной ситуации, все
|
|
||||||
дополнительные страницы, которые были выделены пока переработка старых
|
|
||||||
была невозможна, будут участвовать в цикле выделения/освобождения до
|
|
||||||
конца жизни экземпляра БД. В оригинальной _LMDB_ этот цикл использования
|
|
||||||
страниц работает по принципу [FIFO](https://ru.wikipedia.org/wiki/FIFO).
|
|
||||||
Поэтому увеличение количества циркулирующий страниц, с точки зрения
|
|
||||||
механизмов кэширования и/или обратной записи, выглядит как увеличение
|
|
||||||
рабочего набор данных. Проще говоря, однократное попадание в ситуацию
|
|
||||||
"уснувшего читателя" приводит к устойчивому эффекту вымывания I/O кэша
|
|
||||||
при всех последующих изменениях данных.
|
|
||||||
|
|
||||||
Для устранения описанных проблемы в _libmdbx_ сделаны существенные
|
|
||||||
доработки, подробности ниже. Иллюстрации к проблеме "долгих чтений"
|
|
||||||
можно найти в [слайдах презентации](http://www.slideshare.net/leoyuriev/lmdb).
|
|
||||||
|
|
||||||
Там же приведен пример количественной оценки прироста производительности
|
|
||||||
за счет эффективной работы [BBWC](https://en.wikipedia.org/wiki/BBWC)
|
|
||||||
при включении `LIFO RECLAIM` в _libmdbx_.
|
|
||||||
|
|
||||||
### Сохранность данных в режиме асинхронной фиксации
|
|
||||||
При работе в режиме `WRITEMAP+MAPSYNC` запись измененных страниц
|
|
||||||
выполняется ядром ОС, что имеет ряд преимуществ. Так например, при крахе
|
|
||||||
приложения, ядро ОС сохранит все изменения.
|
|
||||||
|
|
||||||
Однако, при аварийном отключении питания или сбое в ядре ОС, на диске
|
|
||||||
может быть сохранена только часть измененных страниц БД. При этом с
|
|
||||||
большой вероятностью может оказаться, что будут сохранены мета-страницы
|
|
||||||
со ссылками на страницы с новыми версиями данных, но не сами новые
|
|
||||||
данные. В этом случае БД будет безвозвратна разрушена, даже если до
|
|
||||||
аварии производилась полная синхронизация данных (посредством
|
|
||||||
`mdbx_env_sync()`).
|
|
||||||
|
|
||||||
В _libmdbx_ эта проблема устранена путем полной переработки
|
|
||||||
пути записи данных:
|
|
||||||
|
|
||||||
* В режиме `WRITEMAP+MAPSYNC` _libmdbx_ не обновляет
|
|
||||||
мета-страницы непосредственно, а поддерживает их теневые копии
|
|
||||||
с переносом изменений после фиксации данных.
|
|
||||||
|
|
||||||
* При завершении транзакций, в зависимости от состояния
|
|
||||||
синхронности данных между диском и оперативной памятью,
|
|
||||||
_libmdbx_ помечает точки фиксации либо как сильные (strong),
|
|
||||||
либо как слабые (weak). Так например, в режиме
|
|
||||||
`WRITEMAP+MAPSYNC` завершаемые транзакции помечаются как
|
|
||||||
слабые, а при явной синхронизации данных - как сильные.
|
|
||||||
|
|
||||||
* В _libmdbx_ поддерживается не две, а три отдельные мета-страницы.
|
|
||||||
Это позволяет выполнять фиксацию транзакций с формированием как
|
|
||||||
сильной, так и слабой точки фиксации, без потери двух предыдущих
|
|
||||||
точек фиксации (из которых одна может быть сильной, а вторая слабой).
|
|
||||||
В результате, _libmdbx_ позволяет в произвольном порядке чередовать
|
|
||||||
сильные и слабые точки фиксации без нарушения соответствующих
|
|
||||||
гарантий в случае неожиданной системной аварии во время фиксации.
|
|
||||||
|
|
||||||
* При открытии БД выполняется автоматический откат к последней
|
|
||||||
сильной фиксации. Этим обеспечивается гарантия сохранности БД.
|
|
||||||
|
|
||||||
Такая гарантия надежности не дается бесплатно. Для сохранности данных,
|
|
||||||
страницы, формирующие крайний снимок с сильной фиксацией, не должны
|
|
||||||
повторно использоваться (перезаписываться) до формирования следующей
|
|
||||||
сильной точки фиксации. Таким образом, крайняя точка фиксации создает
|
|
||||||
описанный выше эффект "долгого чтения". Разница же здесь в том, что при
|
|
||||||
исчерпании свободных страниц ситуация будет автоматически исправлена,
|
|
||||||
посредством записи изменений на диск и формирования новой сильной точки
|
|
||||||
фиксации.
|
|
||||||
|
|
||||||
Таким образом, в режиме безопасной асинхронной фиксации _libmdbx_ будет
|
|
||||||
всегда использовать новые страницы до исчерпания места в БД или до
|
|
||||||
явного формирования сильной точки фиксации посредством
|
|
||||||
`mdbx_env_sync()`. При этом суммарный трафик записи на диск будет
|
|
||||||
примерно такой же, как если бы отдельно фиксировалась каждая транзакция.
|
|
||||||
|
|
||||||
В текущей версии _libmdbx_ вам предоставляется выбор между безопасным
|
|
||||||
режимом (по умолчанию) асинхронной фиксации, и режимом `UTTERLY_NOSYNC`
|
|
||||||
когда при системной аварии есть шанс полного разрушения БД как в LMDB.
|
|
||||||
|
|
||||||
В последующих версиях _libmdbx_ будут предусмотрены средства для
|
|
||||||
асинхронной записи данных на диск с автоматическим формированием сильных
|
|
||||||
точек фиксации.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Использование
|
|
||||||
=============
|
|
||||||
|
|
||||||
## Сборка
|
|
||||||
|
|
||||||
Для сборки на всех платформах кроме Windows вам потребуются не-дремучие
|
|
||||||
версии: GNU Make, [bash](https://ru.wikipedia.org/wiki/Bash), компиляторы C и C++ совместимые с GCC или CLANG.
|
|
||||||
|
|
||||||
Исторически сборка _libmdbx_ основывается на одном
|
|
||||||
[Makefile](https://ru.wikipedia.org/wiki/Makefile), что предполагает
|
|
||||||
разные рецепты сборки в зависимости от целевой платформы. В следующих
|
|
||||||
версиях планируется переход на использование
|
|
||||||
[CMake](https://ru.wikipedia.org/wiki/CMake), с отказом от поддержки
|
|
||||||
других инструментов.
|
|
||||||
|
|
||||||
#### Выгрузка DSO/DLL и деструкторы Thread-Local-Storage объектов
|
|
||||||
При сборке _libmdbx_ в виде разделяемой библиотеки, либо использовании
|
|
||||||
статической _libmdbx_ в составе другой динамической библиотеке,
|
|
||||||
желательно убедиться, что ваша система обеспечивает корректность вызова
|
|
||||||
деструкторов Thread-Local-Storage объектов при выгрузке динамических
|
|
||||||
библиотек.
|
|
||||||
|
|
||||||
Если это не так, то при выгрузке динамической библиотеки с _libmdbx_
|
|
||||||
внутри возможна либо утечка ресурсов, либо падения из-за вызова
|
|
||||||
деструкторов из уже выгруженного DSO/DLL объекта. Проблема может
|
|
||||||
проявляться только в многопоточном приложении, которое производит
|
|
||||||
выгрузку разделяемых динамических библиотек с кодом _libmdbx_ внутри,
|
|
||||||
после использования _libmdbx_. Заведомо известно, что TLS-деструкторы
|
|
||||||
корректно обслуживаются:
|
|
||||||
|
|
||||||
- На всех актуальных версиях Windows (Windows 7 и последующих).
|
|
||||||
|
|
||||||
- На системах c функцией
|
|
||||||
[`__cxa_thread_atexit_impl()`](https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables)
|
|
||||||
в стандартной библиотеке C. В том числе на системах с GNU libc версии
|
|
||||||
2.18 и выше.
|
|
||||||
|
|
||||||
- На системах с libpthread/ntpl из состава GNU libc с исправлением
|
|
||||||
ошибок [#21031](https://sourceware.org/bugzilla/show_bug.cgi?id=21031) и
|
|
||||||
[#21032](https://sourceware.org/bugzilla/show_bug.cgi?id=21032), либо
|
|
||||||
где нет подобных ошибок в реализации pthreads.
|
|
||||||
|
|
||||||
### Linux и другие платформы с GNU Make
|
|
||||||
Для сборки библиотеки достаточно выполнить `make all` в директории с
|
|
||||||
исходными текстами, а для выполнения базовых тестов `make check`.
|
|
||||||
|
|
||||||
Если установленный в система `make` не является GNU Make, то при попытке
|
|
||||||
сборки будет масса ошибок от make. В этом случае, возможно, вместо
|
|
||||||
`make` вам следует использовать `gmake`, либо даже `gnu-make` и т.п.
|
|
||||||
|
|
||||||
### FreeBSD и родственные платформы
|
|
||||||
Как правило, на таких системах по-умолчанию используется Berkeley Make.
|
|
||||||
А GNU Make вызывается командой `gmake` или может отсутствовать. Кроме
|
|
||||||
этого может отсутствовать [`bash`](https://ru.wikipedia.org/wiki/Bash).
|
|
||||||
|
|
||||||
Вам необходимо установить требуемые компоненты: GNU Make, bash,
|
|
||||||
компиляторы C и C++ совместимые с GCC или CLANG. После этого для сборки
|
|
||||||
библиотеки достаточно выполнить `gmake all` (или `make all`) в
|
|
||||||
директории с исходными текстами, а для выполнения базовых тестов `gmake
|
|
||||||
check` (или `make check`).
|
|
||||||
|
|
||||||
### Windows
|
|
||||||
Для сборки libmdbx_ для ОС Windows рекомендуется использовать [Microsoft
|
|
||||||
Visual Studio](https://ru.wikipedia.org/wiki/Microsoft_Visual_Studio),
|
|
||||||
но не такие инструменты как MinGW, MSYS или Cygwin. Для этого в набор
|
|
||||||
исходных кодов _libmdbx_ входят соответствующие файлы проектов
|
|
||||||
совместимые с Visual Studio 2015, Windows SDK для Windows 8.1 и более
|
|
||||||
поздними версиями. Достаточно открыть `mdbx.sln` и выполнить сборку
|
|
||||||
библиотеки.
|
|
||||||
|
|
||||||
Для сборки с более новыми версиями SDK или Visual Studio должно быть
|
|
||||||
достаточно выполнить "Retarget solution". Для сборки под старые версии
|
|
||||||
Windows (например Windows XP) или более старыми компиляторами вам
|
|
||||||
потребуется самостоятельно преобразовать или воссоздать файлы проектов.
|
|
||||||
|
|
||||||
Сборка посредством MinGW, MSYS или Cygwin потенциально возможна. Однако,
|
|
||||||
эти сценарии не тестируются и вероятно потребуют от вас доработки
|
|
||||||
`Makefile`. Следует отметить, что в _libmdbx_ предприняты усилия для
|
|
||||||
устранения runtime зависимостей от CRT и других библиотек Visual Studio.
|
|
||||||
Для этого достаточно при сборке определить опцию `MDBX_AVOID_CRT`.
|
|
||||||
|
|
||||||
Пример запуска базового сценария тестирования можно найти в
|
|
||||||
[CI-сценарии](appveyor.yml) для [AppVeyor](https://www.appveyor.com/).
|
|
||||||
Для выполнения [сценария длительного стохастического
|
|
||||||
тестирования](test/long_stochastic.sh) потребуется
|
|
||||||
[`bash`](https://ru.wikipedia.org/wiki/Bash), а само тестирование
|
|
||||||
рекомендуется выполнять с размещением тестовых данных на
|
|
||||||
[RAM-диске](https://ru.wikipedia.org/wiki/RAM-%D0%B4%D0%B8%D1%81%D0%BA).
|
|
||||||
|
|
||||||
### MacOS X
|
|
||||||
Актуальные [нативные сборочные
|
|
||||||
инструменты](https://ru.wikipedia.org/wiki/Xcode) для MacOS X включают
|
|
||||||
GNU Make, CLANG и устаревшую версию bash. Поэтому для сборки библиотеки
|
|
||||||
достаточно выполнить `make all` в директории с исходными текстами, а для
|
|
||||||
выполнения базовых тестов `make check`. Если же что-то пойдет не так, то
|
|
||||||
рекомендуется установить [Homebrew](https://brew.sh/) и попробовать ещё
|
|
||||||
раз.
|
|
||||||
|
|
||||||
Для выполнения [сценария длительного стохастического
|
|
||||||
тестирования](test/long_stochastic.sh) потребуется установка актуальной
|
|
||||||
(не устаревшей) версии [`bash`](https://ru.wikipedia.org/wiki/Bash). Для
|
|
||||||
этого рекомендуется установить [Homebrew](https://brew.sh/), а затем
|
|
||||||
выполнить `brew install bash`.
|
|
||||||
|
|
||||||
## Привязки к другим языкам
|
|
||||||
|
|
||||||
| Runtime | GitHub | Author |
|
|
||||||
| -------- | ------ | ------ |
|
|
||||||
| Java | [mdbxjni](https://github.com/castortech/mdbxjni) | [Castor Technologies](https://castortech.com/) |
|
|
||||||
| .NET | [mdbx.NET](https://github.com/wangjia184/mdbx.NET) | [Jerry Wang](https://github.com/wangjia184) |
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Сравнение производительности
|
|
||||||
============================
|
|
||||||
|
|
||||||
Все представленные ниже данные получены многократным прогоном тестов на
|
|
||||||
ноутбуке Lenovo Carbon-2, i7-4600U 2.1 ГГц, 8 Гб ОЗУ, с SSD-диском
|
|
||||||
SAMSUNG MZNTD512HAGL-000L1 (DXT23L0Q) 512 Гб.
|
|
||||||
|
|
||||||
Исходный код бенчмарка [_IOArena_](https://github.com/pmwkaa/ioarena) и
|
|
||||||
сценарии тестирования [доступны на
|
|
||||||
github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015).
|
|
||||||
|
|
||||||
|
|
||||||
## Интегральная производительность
|
|
||||||
|
|
||||||
Показана соотнесенная сумма ключевых показателей производительности в трёх
|
|
||||||
бенчмарках:
|
|
||||||
|
|
||||||
- Чтение/Поиск на машине с 4-мя процессорами;
|
|
||||||
|
|
||||||
- Транзакции с [CRUD](https://ru.wikipedia.org/wiki/CRUD)-операциями
|
|
||||||
(вставка, чтение, обновление, удаление) в режиме **синхронной фиксации**
|
|
||||||
данных (fdatasync при завершении каждой транзакции или аналог);
|
|
||||||
|
|
||||||
- Транзакции с [CRUD](https://ru.wikipedia.org/wiki/CRUD)-операциями
|
|
||||||
(вставка, чтение, обновление, удаление) в режиме **отложенной фиксации**
|
|
||||||
данных (отложенная запись посредством файловой систем или аналог);
|
|
||||||
|
|
||||||
*Бенчмарк в режиме асинхронной записи не включен по двум причинам:*
|
|
||||||
|
|
||||||
1. Такое сравнение не совсем правомочно, его следует делать с движками
|
|
||||||
ориентированными на хранение данных в памяти ([Tarantool](https://tarantool.io/), [Redis](https://redis.io/)).
|
|
||||||
|
|
||||||
2. Превосходство libmdbx становится еще более подавляющим, что мешает
|
|
||||||
восприятию информации.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
## Масштабируемость чтения
|
|
||||||
|
|
||||||
Для каждого движка показана суммарная производительность при
|
|
||||||
одновременном выполнении запросов чтения/поиска в 1-2-4-8 потоков на
|
|
||||||
машине с 4-мя физическими процессорами.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
## Синхронная фиксация
|
|
||||||
|
|
||||||
- Линейная шкала слева и темные прямоугольники соответствуют количеству
|
|
||||||
транзакций в секунду, усредненному за всё время теста.
|
|
||||||
|
|
||||||
- Логарифмическая шкала справа и желтые интервальные отрезки
|
|
||||||
соответствуют времени выполнения транзакций. При этом каждый отрезок
|
|
||||||
показывает минимальное и максимальное время, затраченное на выполнение
|
|
||||||
транзакций, а крестиком отмечено среднеквадратичное значение.
|
|
||||||
|
|
||||||
Выполняется **10.000 транзакций в режиме синхронной фиксации данных** на
|
|
||||||
диске. При этом требуется гарантия, что при аварийном выключении питания
|
|
||||||
(или другом подобном сбое) все данные будут консистентны и полностью
|
|
||||||
соответствовать последней завершенной транзакции. В _libmdbx_ в этом
|
|
||||||
режиме при фиксации каждой транзакции выполняется системный вызов
|
|
||||||
[fdatasync](https://linux.die.net/man/2/fdatasync).
|
|
||||||
|
|
||||||
В каждой транзакции выполняется комбинированная CRUD-операция (две
|
|
||||||
вставки, одно чтение, одно обновление, одно удаление). Бенчмарк стартует
|
|
||||||
на пустой базе, а при завершении, в результате выполняемых действий, в
|
|
||||||
базе насчитывается 10.000 небольших key-value записей.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
## Отложенная фиксация
|
|
||||||
|
|
||||||
- Линейная шкала слева и темные прямоугольники соответствуют количеству
|
|
||||||
транзакций в секунду, усредненному за всё время теста.
|
|
||||||
|
|
||||||
- Логарифмическая шкала справа и желтые интервальные отрезки
|
|
||||||
соответствуют времени выполнения транзакций. При этом каждый отрезок
|
|
||||||
показывает минимальное и максимальное время, затраченное на выполнение
|
|
||||||
транзакций, а крестиком отмечено среднеквадратичное значение.
|
|
||||||
|
|
||||||
Выполняется **100.000 транзакций в режиме отложенной фиксации данных**
|
|
||||||
на диске. При этом требуется гарантия, что при аварийном выключении
|
|
||||||
питания (или другом подобном сбое) все данные будут консистентны на
|
|
||||||
момент завершения одной из транзакций, но допускается потеря изменений
|
|
||||||
из некоторого количества последних транзакций, что для многих движков
|
|
||||||
предполагает включение
|
|
||||||
[WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) (write-ahead
|
|
||||||
logging) либо журнала транзакций, который в свою очередь опирается на
|
|
||||||
гарантию упорядоченности данных в журналируемой файловой системе.
|
|
||||||
_libmdbx_ при этом не ведет WAL, а передает весь контроль файловой
|
|
||||||
системе и ядру ОС.
|
|
||||||
|
|
||||||
В каждой транзакции выполняется комбинированная CRUD-операция (две
|
|
||||||
вставки, одно чтение, одно обновление, одно удаление). Бенчмарк стартует
|
|
||||||
на пустой базе, а при завершении, в результате выполняемых действий, в
|
|
||||||
базе насчитывается 100.000 небольших key-value записей.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
## Асинхронная фиксация
|
|
||||||
|
|
||||||
- Линейная шкала слева и темные прямоугольники соответствуют количеству
|
|
||||||
транзакций в секунду, усредненному за всё время теста.
|
|
||||||
|
|
||||||
- Логарифмическая шкала справа и желтые интервальные отрезки
|
|
||||||
соответствуют времени выполнения транзакций. При этом каждый отрезок
|
|
||||||
показывает минимальное и максимальное время, затраченное на выполнение
|
|
||||||
транзакций, а крестиком отмечено среднеквадратичное значение.
|
|
||||||
|
|
||||||
Выполняется **1.000.000 транзакций в режиме асинхронной фиксации
|
|
||||||
данных** на диске. При этом требуется гарантия, что при аварийном
|
|
||||||
выключении питания (или другом подобном сбое) все данные будут
|
|
||||||
консистентны на момент завершения одной из транзакций, но допускается
|
|
||||||
потеря изменений из значительного количества последних транзакций. Во
|
|
||||||
всех движках при этом включался режим предполагающий минимальную
|
|
||||||
нагрузку на диск по записи, и соответственно минимальную гарантию
|
|
||||||
сохранности данных. В _libmdbx_ при этом используется режим асинхронной
|
|
||||||
записи измененных страниц на диск посредством ядра ОС и системного
|
|
||||||
вызова [msync(MS_ASYNC)](https://linux.die.net/man/2/msync).
|
|
||||||
|
|
||||||
В каждой транзакции выполняется комбинированная CRUD-операция (две
|
|
||||||
вставки, одно чтение, одно обновление, одно удаление). Бенчмарк стартует
|
|
||||||
на пустой базе, а при завершении, в результате выполняемых действий, в
|
|
||||||
базе насчитывается 10.000 небольших key-value записей.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
## Потребление ресурсов
|
|
||||||
|
|
||||||
Показана соотнесенная сумма использованных ресурсов в ходе бенчмарка в
|
|
||||||
режиме отложенной фиксации:
|
|
||||||
|
|
||||||
- суммарное количество операций ввода-вывода (IOPS), как записи, так и
|
|
||||||
чтения.
|
|
||||||
|
|
||||||
- суммарное затраченное время процессора, как в режиме пользовательских
|
|
||||||
процессов, так и в режиме ядра ОС.
|
|
||||||
|
|
||||||
- использованное место на диске при завершении теста, после закрытия БД
|
|
||||||
из тестирующего процесса, но без ожидания всех внутренних операций
|
|
||||||
обслуживания (компактификации LSM и т.п.).
|
|
||||||
|
|
||||||
Движок _ForestDB_ был исключен при оформлении результатов, так как
|
|
||||||
относительно конкурентов многократно превысил потребление каждого из
|
|
||||||
ресурсов (потратил процессорное время на генерацию IOPS для заполнения
|
|
||||||
диска), что не позволяло наглядно сравнить показатели остальных движков
|
|
||||||
на одной диаграмме.
|
|
||||||
|
|
||||||
Все данные собирались посредством системного вызова
|
|
||||||
[getrusage()](http://man7.org/linux/man-pages/man2/getrusage.2.html) и
|
|
||||||
сканированием директорий с данными.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
```
|
|
||||||
$ objdump -f -h -j .text libmdbx.so
|
|
||||||
|
|
||||||
libmdbx.so: file format elf64-x86-64
|
|
||||||
architecture: i386:x86-64, flags 0x00000150:
|
|
||||||
HAS_SYMS, DYNAMIC, D_PAGED
|
|
||||||
start address 0x0000000000003870
|
|
||||||
|
|
||||||
Sections:
|
|
||||||
Idx Name Size VMA LMA File off Algn
|
|
||||||
11 .text 000173d4 0000000000003870 0000000000003870 00003870 2**4
|
|
||||||
CONTENTS, ALLOC, LOAD, READONLY, CODE
|
|
||||||
|
|
||||||
```
|
|
430
README.md
430
README.md
@ -4,30 +4,25 @@
|
|||||||
|
|
||||||
libmdbx
|
libmdbx
|
||||||
======================================
|
======================================
|
||||||
MDBX is compact, fast, powerful, and robust and implements a simplified
|
|
||||||
variant of the BerkeleyDB API. In fact _libmdbx_ is revised and extended
|
|
||||||
descendant of [Lightning Memory-Mapped
|
|
||||||
Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database)
|
|
||||||
(aka _LMDB_). Permissive non-copyleft BSD-style [OpenLDAP Public License
|
|
||||||
2.8](LICENSE). Русскоязычная версия этого README [здесь](README-RU.md).
|
|
||||||
|
|
||||||
_libmdbx_ is superior to LMDB in terms of features and reliability, not
|
_libmdbx_ is an extremely fast, compact, powerful, embedded
|
||||||
inferior in performance. In comparison to LMDB, _libmdbx_ makes many
|
transactional [key-value
|
||||||
things just work perfectly, not silently and catastrophically break
|
store](https://en.wikipedia.org/wiki/Key-value_database)
|
||||||
down. _libmdbx_ supports Linux, Windows, MacOS, FreeBSD and other
|
database, with permissive [OpenLDAP Public License](LICENSE).
|
||||||
systems compliant with POSIX.1-2008.
|
_libmdbx_ has a specific set of properties and capabilities,
|
||||||
|
focused on creating unique lightweight solutions with
|
||||||
|
extraordinary performance.
|
||||||
|
|
||||||
The next version is under active non-public development and will be
|
The next version is under active non-public development and will be
|
||||||
released as **_MithrilDB_** and `libmithrildb` for libraries & packages.
|
released as **_MithrilDB_** and `libmithrildb` for libraries & packages.
|
||||||
Admittedly mythical [Mithril](https://en.wikipedia.org/wiki/Mithril) is
|
Admittedly mythical [Mithril](https://en.wikipedia.org/wiki/Mithril) is
|
||||||
resembling silver but being stronger and lighter than steel. Therefore
|
resembling silver but being stronger and lighter than steel. Therefore
|
||||||
_MithrilDB_ is rightly relevant name.
|
_MithrilDB_ is rightly relevant name.
|
||||||
|
> _MithrilDB_ will be radically different from _libmdbx_ by the new
|
||||||
_MithrilDB_ will be radically different from _libmdbx_ by the new
|
> database format and API based on C++17, as well as the [Apache 2.0
|
||||||
database format and API based on C++17, as well as the [Apache 2.0
|
> License](https://www.apache.org/licenses/LICENSE-2.0). The goal of this
|
||||||
License](https://www.apache.org/licenses/LICENSE-2.0). The goal of this
|
> revolution is to provide a clearer and robust API, add more features and
|
||||||
revolution is to provide a clearer and robust API, add more features and
|
> new valuable properties of database.
|
||||||
new valuable properties of database.
|
|
||||||
|
|
||||||
*The Future will (be) [Positive](https://www.ptsecurity.com). Всё будет хорошо.*
|
*The Future will (be) [Positive](https://www.ptsecurity.com). Всё будет хорошо.*
|
||||||
|
|
||||||
@ -43,8 +38,6 @@ new valuable properties of database.
|
|||||||
- [Key features](#key-features)
|
- [Key features](#key-features)
|
||||||
- [Improvements over LMDB](#improvements-over-lmdb)
|
- [Improvements over LMDB](#improvements-over-lmdb)
|
||||||
- [Gotchas](#gotchas)
|
- [Gotchas](#gotchas)
|
||||||
- [Problem of long-time reading](#problem-of-long-time-reading)
|
|
||||||
- [Durability in asynchronous writing mode](#durability-in-asynchronous-writing-mode)
|
|
||||||
- [Usage](#usage)
|
- [Usage](#usage)
|
||||||
- [Building](#building)
|
- [Building](#building)
|
||||||
- [Bindings](#bindings)
|
- [Bindings](#bindings)
|
||||||
@ -59,15 +52,23 @@ new valuable properties of database.
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
_libmdbx_ is an embedded lightweight key-value database engine oriented
|
|
||||||
for performance.
|
|
||||||
|
|
||||||
_libmdbx_ allows multiple processes to read and update several key-value
|
_libmdbx_ is revised and extended descendant of amazing [Lightning
|
||||||
|
Memory-Mapped
|
||||||
|
Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
|
||||||
|
_libmdbx_ inherits all features and characteristics from
|
||||||
|
[LMDB](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database),
|
||||||
|
but resolves some issues and adds several features.
|
||||||
|
|
||||||
|
- _libmdbx_ guarantee data integrity after crash unless this was explicitly
|
||||||
|
neglected in favour of write performance.
|
||||||
|
|
||||||
|
- _libmdbx_ allows multiple processes to read and update several key-value
|
||||||
tables concurrently, while being
|
tables concurrently, while being
|
||||||
[ACID](https://en.wikipedia.org/wiki/ACID)-compliant, with minimal
|
[ACID](https://en.wikipedia.org/wiki/ACID)-compliant, with minimal
|
||||||
overhead and Olog(N) operation cost.
|
overhead and Olog(N) operation cost.
|
||||||
|
|
||||||
_libmdbx_ enforce
|
- _libmdbx_ enforce
|
||||||
[serializability](https://en.wikipedia.org/wiki/Serializability) for
|
[serializability](https://en.wikipedia.org/wiki/Serializability) for
|
||||||
writers by single
|
writers by single
|
||||||
[mutex](https://en.wikipedia.org/wiki/Mutual_exclusion) and affords
|
[mutex](https://en.wikipedia.org/wiki/Mutual_exclusion) and affords
|
||||||
@ -75,29 +76,31 @@ writers by single
|
|||||||
for parallel readers without atomic/interlocked operations, while
|
for parallel readers without atomic/interlocked operations, while
|
||||||
writing and reading transactions do not block each other.
|
writing and reading transactions do not block each other.
|
||||||
|
|
||||||
_libmdbx_ can guarantee consistency after crash depending of operation
|
- _libmdbx_ uses [B+Trees](https://en.wikipedia.org/wiki/B%2B_tree) and
|
||||||
mode.
|
|
||||||
|
|
||||||
_libmdbx_ uses [B+Trees](https://en.wikipedia.org/wiki/B%2B_tree) and
|
|
||||||
[Memory-Mapping](https://en.wikipedia.org/wiki/Memory-mapped_file),
|
[Memory-Mapping](https://en.wikipedia.org/wiki/Memory-mapped_file),
|
||||||
doesn't use [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging)
|
doesn't use [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging)
|
||||||
which might be a caveat for some workloads.
|
which might be a caveat for some workloads.
|
||||||
|
|
||||||
|
- _libmdbx_ implements a simplified variant of the [Berkeley
|
||||||
|
DB](https://en.wikipedia.org/wiki/Berkeley_DB) and/or
|
||||||
|
[dbm](https://en.wikipedia.org/wiki/DBM_(computing)) API.
|
||||||
|
|
||||||
|
- _libmdbx_ supports Linux, Windows, MacOS, FreeBSD and other systems
|
||||||
|
compliant with POSIX.1-2008.
|
||||||
|
|
||||||
### Comparison with other databases
|
### Comparison with other databases
|
||||||
For now please refer to [chapter of "BoltDB comparison with other
|
For now please refer to [chapter of "BoltDB comparison with other
|
||||||
databases"](https://github.com/coreos/bbolt#comparison-with-other-databases)
|
databases"](https://github.com/coreos/bbolt#comparison-with-other-databases)
|
||||||
which is also (mostly) applicable to MDBX.
|
which is also (mostly) applicable to _libmdbx_.
|
||||||
|
|
||||||
### History
|
### History
|
||||||
The _libmdbx_ design is based on [Lightning Memory-Mapped
|
At first the development was carried out within the
|
||||||
Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
|
|
||||||
Initial development was going in
|
|
||||||
[ReOpenLDAP](https://github.com/leo-yuriev/ReOpenLDAP) project. About a
|
[ReOpenLDAP](https://github.com/leo-yuriev/ReOpenLDAP) project. About a
|
||||||
year later libmdbx was isolated to separate project, which was
|
year later _libmdbx_ was separated into standalone project, which was
|
||||||
[presented at Highload++ 2015
|
[presented at Highload++ 2015
|
||||||
conference](http://www.highload.ru/2015/abstracts/1831.html).
|
conference](http://www.highload.ru/2015/abstracts/1831.html).
|
||||||
|
|
||||||
Since early 2017 _libmdbx_ is used in [Fast Positive Tables](https://github.com/leo-yuriev/libfpta),
|
Since 2017 _libmdbx_ is used in [Fast Positive Tables](https://github.com/leo-yuriev/libfpta),
|
||||||
and development is funded by [Positive Technologies](https://www.ptsecurity.com).
|
and development is funded by [Positive Technologies](https://www.ptsecurity.com).
|
||||||
|
|
||||||
### Acknowledgments
|
### Acknowledgments
|
||||||
@ -114,9 +117,6 @@ Description
|
|||||||
|
|
||||||
## Key features
|
## Key features
|
||||||
|
|
||||||
_libmdbx_ inherits all features and characteristics from
|
|
||||||
[LMDB](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database):
|
|
||||||
|
|
||||||
1. Key-value pairs are stored in ordered map(s), keys are always sorted,
|
1. Key-value pairs are stored in ordered map(s), keys are always sorted,
|
||||||
range lookups are supported.
|
range lookups are supported.
|
||||||
|
|
||||||
@ -160,146 +160,90 @@ without freezing writers.
|
|||||||
|
|
||||||
## Improvements over LMDB
|
## Improvements over LMDB
|
||||||
|
|
||||||
1. Automatic dynamic DB size management according to the parameters
|
_libmdbx_ is superior to _legendary [LMDB](https://symas.com/lmdb/)_ in
|
||||||
specified by `mdbx_env_set_geometry()` function. Including
|
terms of features and reliability, not inferior in performance. In
|
||||||
growth step and truncation threshold, as well as the choice of page
|
comparison to LMDB, _libmdbx_ make things "just work" perfectly and
|
||||||
size.
|
out-of-the-box, not silently and catastrophically break down. The list
|
||||||
|
below is pruned down to the improvements most notable and obvious from
|
||||||
|
the user's point of view.
|
||||||
|
|
||||||
2. Automatic returning of freed pages into unallocated space at the end
|
1. Automatic on-the-fly database size control by preset parameters, both
|
||||||
of database file, with optionally automatic shrinking it. This reduces
|
reduction and increment.
|
||||||
amount of pages resides in RAM and circulated in disk I/O. In fact
|
> _libmdbx_ manage the database size according to parameters specified
|
||||||
_libmdbx_ constantly performs DB compactification, without spending
|
> by `mdbx_env_set_geometry()` function,
|
||||||
additional resources for that.
|
> ones include the growth step and the truncation threshold.
|
||||||
|
|
||||||
3. `LIFO RECLAIM` mode:
|
2. Automatic continuous zero-overhead database compactification.
|
||||||
|
> _libmdbx_ logically move as possible a freed pages
|
||||||
|
> at end of allocation area into unallocated space,
|
||||||
|
> and then release such space if a lot of.
|
||||||
|
|
||||||
The newest pages are picked for reuse instead of the oldest. This allows
|
3. LIFO policy for recycling a Garbage Collection items. On systems with a disk
|
||||||
to minimize reclaim loop and make it execution time independent of total
|
write-back cache, this can significantly increase write performance, up to
|
||||||
page count.
|
several times in a best case scenario.
|
||||||
|
> LIFO means that for reuse pages will be taken which became unused the lastest.
|
||||||
|
> Therefore the loop of database pages circulation becomes as short as possible.
|
||||||
|
> In other words, the number of pages, that are overwritten in memory
|
||||||
|
> and on disk during a series of write transactions, will be as small as possible.
|
||||||
|
> Thus creates ideal conditions for the efficient operation of the disk write-back cache.
|
||||||
|
|
||||||
This results in OS kernel cache mechanisms working with maximum
|
4. Fast estimation of range query result volume, i.e. how many items can
|
||||||
efficiency. In case of using disk controllers or storages with
|
be found between a `KEY1` and a `KEY2`. This is prerequisite for build
|
||||||
[BBWC](https://en.wikipedia.org/wiki/Disk_buffer#Write_acceleration)
|
and/or optimize query execution plans.
|
||||||
this may greatly improve write performance.
|
> _libmdbx_ performs a rough estimate based only on b-tree pages that
|
||||||
|
> are common for the both stacks of cursors that were set to corresponing
|
||||||
|
> keys.
|
||||||
|
|
||||||
4. Fast estimation of range query result size via functions
|
5. `mdbx_chk` tool for database integrity check.
|
||||||
`mdbx_estimate_range()`, `mdbx_estimate_move()` and
|
|
||||||
`mdbx_estimate_distance()`. E.g. for selection the optimal query
|
|
||||||
execution plan.
|
|
||||||
|
|
||||||
5. `mdbx_chk` tool for DB integrity check.
|
6. Guarantee of database integrity even in asynchronous unordered write-to-disk mode.
|
||||||
|
> _libmdbx_ propose additional trade-off by implementing append-like manner for updates
|
||||||
|
> in `NOSYNC` and `MAPASYNC` modes, that avoid database corruption after a system crash
|
||||||
|
> contrary to LMDB. Nevertheless, the `MDBX_UTTERLY_NOSYNC` mode available to match LMDB behaviour,
|
||||||
|
> and for a special use-cases.
|
||||||
|
|
||||||
6. Support for keys and values of zero length, including multi-values
|
7. Automated steady flush to disk upon volume of changes and/or by
|
||||||
|
timeout via cheap polling.
|
||||||
|
|
||||||
|
8. Sequence generation and three cheap persistent 64-bit markers with ACID.
|
||||||
|
|
||||||
|
9. Support for keys and values of zero length, including multi-values
|
||||||
(aka sorted duplicates).
|
(aka sorted duplicates).
|
||||||
|
|
||||||
7. Ability to assign up to 3 persistent 64-bit markers to commiting
|
10. The handler of lack-of-space condition with a callback,
|
||||||
transaction with `mdbx_canary_put()` and then get them in read
|
that allow you to control and resolve such situations.
|
||||||
transaction by `mdbx_canary_get()`.
|
|
||||||
|
|
||||||
8. Ability to update or delete record and get previous value via
|
11. Support for opening a database in the exclusive mode, including on a network share.
|
||||||
`mdbx_replace()`. Also allows update the specific item from multi-value
|
|
||||||
with the same key.
|
|
||||||
|
|
||||||
9. Sequence generation via `mdbx_dbi_sequence()`.
|
12. Extended transaction info, including dirty and leftover space info
|
||||||
|
for a write transaction, reading lag and hold over space for read
|
||||||
|
transactions.
|
||||||
|
|
||||||
10. `OOM-KICK` callback.
|
13. Extended whole-database info (aka environment) and reader enumeration.
|
||||||
|
|
||||||
`mdbx_env_set_oomfunc()` allows to set a callback, which will be called
|
14. Extended update or delete, _at once_ with getting previous value
|
||||||
in the event of DB space exhausting during long-time read transaction in
|
and addressing the particular item from multi-value with the same key.
|
||||||
parallel with extensive updating. Callback will be invoked with PID and
|
|
||||||
pthread_id of offending thread as parameters. Callback can do any of
|
|
||||||
these things to remedy the problem:
|
|
||||||
|
|
||||||
* wait for read transaction to finish normally;
|
15. Support for explicitly updating the existing record, not insertion a new one.
|
||||||
|
|
||||||
* kill the offending process (signal 9), if separate process is doing
|
16. All cursors are uniformly, can be reused and should be closed explicitly,
|
||||||
long-time read;
|
regardless ones were opened within write or read transaction.
|
||||||
|
|
||||||
* abort or restart offending read transaction if it's running in sibling
|
17. Correct update of current record with `MDBX_CURRENT` flag when size
|
||||||
thread;
|
of key or data was changed, including sorted duplicated.
|
||||||
|
|
||||||
* abort current write transaction with returning error code.
|
18. Opening database handles is spared from race conditions and
|
||||||
|
pre-opening is not needed.
|
||||||
|
|
||||||
11. Ability to open DB in exclusive mode by `MDBX_EXCLUSIVE` flag.
|
19. Ability to determine whether the particular data is on a dirty page
|
||||||
|
or not, that allows to avoid copy-out before updates.
|
||||||
|
|
||||||
12. Ability to get how far current read-transaction snapshot lags
|
20. Ability to determine whether the cursor is pointed to a key-value
|
||||||
from the latest version of the DB by `mdbx_txn_straggler()`.
|
pair, to the first, to the last, or not set to anything.
|
||||||
|
|
||||||
13. Ability to explicitly update the existing record, not insertion
|
21. Returning `MDBX_EMULTIVAL` error in case of ambiguous update or delete.
|
||||||
a new one. Implemented as `MDBX_CURRENT` flag for `mdbx_put()`.
|
|
||||||
|
|
||||||
14. Fixed `mdbx_cursor_count()`, which returns correct count of
|
22. On **MacOS** the `fcntl(F_FULLFSYNC)` syscall is used _by
|
||||||
duplicated (aka multi-value) for all cases and any cursor position.
|
|
||||||
|
|
||||||
15. `mdbx_env_info()` to getting additional info, including number of
|
|
||||||
the oldest snapshot of DB, which is used by someone of the readers.
|
|
||||||
|
|
||||||
16. `mdbx_del()` doesn't ignore additional argument (specifier) `data`
|
|
||||||
for tables without duplicates (without flag `MDBX_DUPSORT`), if `data`
|
|
||||||
is not null then always uses it to verify record, which is being
|
|
||||||
deleted.
|
|
||||||
|
|
||||||
17. Ability to open dbi-table with simultaneous with race-free setup
|
|
||||||
of comparators for keys and values, via `mdbx_dbi_open_ex()`.
|
|
||||||
|
|
||||||
18. `mdbx_is_dirty()`to find out if given key or value is on dirty page, that
|
|
||||||
useful to avoid copy-out before updates.
|
|
||||||
|
|
||||||
19. Correct update of current record in `MDBX_CURRENT` mode of
|
|
||||||
`mdbx_cursor_put()`, including sorted duplicated.
|
|
||||||
|
|
||||||
20. Check if there is a row with data after current cursor position via
|
|
||||||
`mdbx_cursor_eof()`.
|
|
||||||
|
|
||||||
21. Additional error code `MDBX_EMULTIVAL`, which is returned by
|
|
||||||
`mdbx_put()` and `mdbx_replace()` in case is ambiguous update or delete.
|
|
||||||
|
|
||||||
22. Ability to get value by key and duplicates count by `mdbx_get_ex()`.
|
|
||||||
|
|
||||||
23. Functions `mdbx_cursor_on_first()` and `mdbx_cursor_on_last()`,
|
|
||||||
which allows to check cursor is currently on first or last position
|
|
||||||
respectively.
|
|
||||||
|
|
||||||
24. Automatic creation of steady commit-points (flushing data to the
|
|
||||||
disk) when the volume of changes reaches a threshold, which can be
|
|
||||||
set by `mdbx_env_set_syncbytes()`.
|
|
||||||
|
|
||||||
25. Control over debugging and receiving of debugging messages via
|
|
||||||
`mdbx_setup_debug()`.
|
|
||||||
|
|
||||||
26. Function `mdbx_env_pgwalk()` for page-walking the DB.
|
|
||||||
|
|
||||||
27. Three meta-pages instead of two, that allows to guarantee
|
|
||||||
consistency of data when updating weak commit-points without the
|
|
||||||
risk of damaging the last steady commit-point.
|
|
||||||
|
|
||||||
28. Guarantee of DB integrity in `WRITEMAP+MAPSYNC` mode:
|
|
||||||
> Current _libmdbx_ gives a choice of safe async-write mode (default)
|
|
||||||
> and `UTTERLY_NOSYNC` mode which may result in full
|
|
||||||
> DB corruption during system crash as with LMDB. For details see
|
|
||||||
> [Data safety in async-write mode](#data-safety-in-async-write-mode).
|
|
||||||
|
|
||||||
29. Ability to close DB in "dirty" state (without data flush and
|
|
||||||
creation of steady synchronization point) via `mdbx_env_close_ex()`.
|
|
||||||
|
|
||||||
30. If read transaction is aborted via `mdbx_txn_abort()` or
|
|
||||||
`mdbx_txn_reset()` then DBI-handles, which were opened during it,
|
|
||||||
will not be closed or deleted. In several cases this allows
|
|
||||||
to avoid hard-to-debug errors.
|
|
||||||
|
|
||||||
31. All cursors in all read and write transactions can be reused by
|
|
||||||
`mdbx_cursor_renew()` and MUST be freed explicitly.
|
|
||||||
> ## Caution, please pay attention!
|
|
||||||
>
|
|
||||||
> This is the only change of API, which changes semantics of cursor management
|
|
||||||
> and can lead to memory leaks on misuse. This is a needed change as it eliminates ambiguity
|
|
||||||
> which helps to avoid such errors as:
|
|
||||||
> - use-after-free;
|
|
||||||
> - double-free;
|
|
||||||
> - memory corruption and segfaults.
|
|
||||||
|
|
||||||
|
|
||||||
32. On **Mac OS X** the `fcntl(F_FULLFSYNC)` syscall is used _by
|
|
||||||
default_ to synchronize data with the disk, as this is [the only way to
|
default_ to synchronize data with the disk, as this is [the only way to
|
||||||
guarantee data
|
guarantee data
|
||||||
durability](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsync.2.html)
|
durability](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsync.2.html)
|
||||||
@ -309,7 +253,7 @@ compared to LMDB, where the `fsync()` syscall is used. Therefore,
|
|||||||
_libmdbx_ allows you to override this behavior by defining the
|
_libmdbx_ allows you to override this behavior by defining the
|
||||||
`MDBX_OSX_SPEED_INSTEADOF_DURABILITY=1` option while build the library.
|
`MDBX_OSX_SPEED_INSTEADOF_DURABILITY=1` option while build the library.
|
||||||
|
|
||||||
33. On **Windows** the `LockFileEx()` syscall is used for locking, since
|
23. On **Windows** the `LockFileEx()` syscall is used for locking, since
|
||||||
it allows place the database on network drives, and provides protection
|
it allows place the database on network drives, and provides protection
|
||||||
against incompetent user actions (aka
|
against incompetent user actions (aka
|
||||||
[poka-yoke](https://en.wikipedia.org/wiki/Poka-yoke)). Therefore
|
[poka-yoke](https://en.wikipedia.org/wiki/Poka-yoke)). Therefore
|
||||||
@ -319,8 +263,9 @@ named mutexes are used.
|
|||||||
|
|
||||||
## Gotchas
|
## Gotchas
|
||||||
|
|
||||||
1. There cannot be more than one writer at a time. This allows serialize an
|
1. There cannot be more than one writer at a time.
|
||||||
updates and eliminate any possibility of conflicts, deadlocks or logical errors.
|
> On the other hand, this allows serialize an updates and eliminate any
|
||||||
|
> possibility of conflicts, deadlocks or logical errors.
|
||||||
|
|
||||||
2. No [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) means
|
2. No [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) means
|
||||||
relatively big [WAF](https://en.wikipedia.org/wiki/Write_amplification)
|
relatively big [WAF](https://en.wikipedia.org/wiki/Write_amplification)
|
||||||
@ -344,7 +289,7 @@ is done on memory page level with
|
|||||||
[B+trees](https://ru.wikipedia.org/wiki/B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE).
|
[B+trees](https://ru.wikipedia.org/wiki/B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE).
|
||||||
Therefore altering data requires to copy about Olog(N) memory pages,
|
Therefore altering data requires to copy about Olog(N) memory pages,
|
||||||
which uses [memory bandwidth](https://en.wikipedia.org/wiki/Memory_bandwidth) and is main
|
which uses [memory bandwidth](https://en.wikipedia.org/wiki/Memory_bandwidth) and is main
|
||||||
performance bottleneck in `MAPASYNC` mode.
|
performance bottleneck in `MDBX_MAPASYNC` mode.
|
||||||
> This is unavoidable, but isn't that bad. Syncing data to disk requires
|
> This is unavoidable, but isn't that bad. Syncing data to disk requires
|
||||||
> much more similar operations which will be done by OS, therefore this is
|
> much more similar operations which will be done by OS, therefore this is
|
||||||
> noticeable only if data sync to persistent storage is fully disabled.
|
> noticeable only if data sync to persistent storage is fully disabled.
|
||||||
@ -352,120 +297,61 @@ performance bottleneck in `MAPASYNC` mode.
|
|||||||
> performance overhead. If there is no need to save data to persistent
|
> performance overhead. If there is no need to save data to persistent
|
||||||
> storage then it's much more preferable to use `std::map`.
|
> storage then it's much more preferable to use `std::map`.
|
||||||
|
|
||||||
|
4. Massive altering of data during a parallel long read operation will
|
||||||
|
increase the process work set, may exhaust entire free database space and
|
||||||
|
result in subsequent write performance degradation.
|
||||||
|
> _libmdbx_ mostly solve this issue by lack-of-space callback and `MDBX_LIFORECLAIM` mode.
|
||||||
|
> See [`mdbx.h`](mdbx.h) with API description for details.
|
||||||
|
> The "next" version of libmdbx (MithrilDB) will completely solve this.
|
||||||
|
|
||||||
4. _LMDB_ has a problem of long-time readers which degrades performance
|
5. There are no built-in checksums or digests to verify database integrity.
|
||||||
and bloats DB.
|
> The "next" version of _libmdbx_ (MithrilDB) will solve this issue employing [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree).
|
||||||
> _libmdbx_ addresses that, details below.
|
|
||||||
|
|
||||||
5. _LMDB_ is susceptible to DB corruption in `WRITEMAP+MAPASYNC` mode.
|
|
||||||
_libmdbx_ in `WRITEMAP+MAPASYNC` guarantees DB integrity and consistency
|
|
||||||
of data.
|
|
||||||
> Additionally there is an alternative: `UTTERLY_NOSYNC` mode.
|
|
||||||
> Details below.
|
|
||||||
|
|
||||||
|
|
||||||
### Problem of long-time reading
|
|
||||||
Garbage collection problem exists in all databases one way or another
|
|
||||||
(e.g. VACUUM in PostgreSQL). But in _libmdbx_ and LMDB it's even more
|
|
||||||
discernible because of high transaction rate and intentional internals
|
|
||||||
simplification in favor of performance.
|
|
||||||
|
|
||||||
Understanding the problem requires some explanation, but can be
|
|
||||||
difficult for quick perception. So is is reasonable
|
|
||||||
to simplify this as follows:
|
|
||||||
|
|
||||||
* Massive altering of data during a parallel long read operation may
|
|
||||||
exhaust the free DB space.
|
|
||||||
|
|
||||||
* If the available space is exhausted, any attempt to update the data
|
|
||||||
will cause a "MAP_FULL" error until a long read transaction is
|
|
||||||
completed.
|
|
||||||
|
|
||||||
* A good example of long readers is a hot backup or debugging of
|
|
||||||
a client application while retaining an active read transaction.
|
|
||||||
|
|
||||||
* In _LMDB_ this results in degraded performance of all operations of
|
|
||||||
writing data to persistent storage.
|
|
||||||
|
|
||||||
* _libmdbx_ has the `OOM-KICK` mechanism which allow to abort such
|
|
||||||
operations and the `LIFO RECLAIM` mode which addresses performance
|
|
||||||
degradation.
|
|
||||||
|
|
||||||
### Durability in asynchronous writing mode
|
|
||||||
In `WRITEMAP+MAPSYNC` mode updated (aka dirty) pages are written to
|
|
||||||
persistent storage by the OS kernel. This means that if the application
|
|
||||||
fails, the OS kernel will finish writing all updated data to disk and
|
|
||||||
nothing will be lost. However, in the case of hardware malfunction or OS
|
|
||||||
kernel fatal error, only some updated data can be written to disk and
|
|
||||||
the database structure is likely to be destroyed. In such situation, DB
|
|
||||||
is completely corrupted and can't be repaired.
|
|
||||||
|
|
||||||
_libmdbx_ addresses this by fully reimplementing write path of data:
|
|
||||||
|
|
||||||
* In `WRITEMAP+MAPSYNC` mode meta-data pages aren't updated in place,
|
|
||||||
instead their shadow copies are used and their updates are synced after
|
|
||||||
data is flushed to disk.
|
|
||||||
|
|
||||||
* During transaction commit _libmdbx_ marks it as a steady or weak
|
|
||||||
depending on synchronization status between RAM and persistent storage.
|
|
||||||
For instance, in the `WRITEMAP+MAPSYNC` mode committed transactions
|
|
||||||
are marked as weak by default, but as steady after explicit data flushes.
|
|
||||||
|
|
||||||
* _libmdbx_ maintains three separate meta-pages instead of two. This
|
|
||||||
allows to commit transaction as steady or weak without losing two
|
|
||||||
previous commit points (one of them can be steady, and another
|
|
||||||
weak). Thus, after a fatal system failure, it will be possible to
|
|
||||||
rollback to the last steady commit point.
|
|
||||||
|
|
||||||
* During DB open _libmdbx_ rollbacks to the last steady commit point,
|
|
||||||
this guarantees database integrity after a crash. However, if the
|
|
||||||
database opening in read-only mode, such rollback cannot be performed
|
|
||||||
which will cause returning the MDBX_WANNA_RECOVERY error.
|
|
||||||
|
|
||||||
For data integrity a pages which form database snapshot with steady
|
|
||||||
commit point, must not be updated until next steady commit point.
|
|
||||||
Therefore the last steady commit point creates an effect analogues to
|
|
||||||
"long-time read". The only difference that now in case of space
|
|
||||||
exhaustion the problem will be immediately addressed by writing changes
|
|
||||||
to disk and forming the new steady commit point.
|
|
||||||
|
|
||||||
So in async-write mode _libmdbx_ will always use new pages until the
|
|
||||||
free DB space will be exhausted or `mdbx_env_sync()` will be invoked,
|
|
||||||
and the total write traffic to the disk will be the same as in
|
|
||||||
sync-write mode.
|
|
||||||
|
|
||||||
Currently libmdbx gives a choice between a safe async-write mode
|
|
||||||
(default) and `UTTERLY_NOSYNC` mode which may lead to DB corruption
|
|
||||||
after a system crash, i.e. like the LMDB.
|
|
||||||
|
|
||||||
Next version of _libmdbx_ will be automatically create steady commit
|
|
||||||
points in async-write mode upon completion transfer data to the disk.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
=====
|
=====
|
||||||
|
|
||||||
|
## Source code embedding
|
||||||
|
|
||||||
|
_libmdbx_ provides two official ways for integration in source code form:
|
||||||
|
|
||||||
|
1. Using the amalgamated source code.
|
||||||
|
> The amalgamated source code includes all files requires to build and
|
||||||
|
> use _libmdbx_, but not for testing _libmdbx_ itself.
|
||||||
|
|
||||||
|
2. Adding the complete original source code as a `git submodule`.
|
||||||
|
> This allows you to build as _libmdbx_ and testing tool.
|
||||||
|
> On the other hand, this way requires you to pull git tags, and use C++11 compiler for test tool.
|
||||||
|
|
||||||
|
**_Please, avoid using any other techniques._** Otherwise, at least
|
||||||
|
don't ask for support and don't name such chimeras `libmdbx`.
|
||||||
|
|
||||||
|
The amalgamated source code could be created from original clone of git
|
||||||
|
repository on Linux by executing `make dist`. As a result, the desired
|
||||||
|
set of files will be formed in the `dist` subdirectory.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
To build on all platforms except Windows the prerequirements are the
|
Both amalgamated and original source code provides build through the use
|
||||||
same: non-obsolete versions of GNU Make,
|
[CMake](https://cmake.org/) or [GNU
|
||||||
[bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)), C and C++
|
Make](https://www.gnu.org/software/make/) with
|
||||||
compilers compatible with GCC or CLANG. On Windows you will need only :
|
[bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)). All build ways
|
||||||
Microsoft Visual Studio 2015 or later, Windows SDK for Windows 8 or
|
are completely traditional and have minimal prerequirements like
|
||||||
later.
|
`build-essential`, i.e. the non-obsolete C/C++ compiler and a
|
||||||
|
[SDK](https://en.wikipedia.org/wiki/Software_development_kit) for the
|
||||||
|
target platform. Obviously you need building tools itself, i.e. `git`,
|
||||||
|
`cmake` or GNU `make` with `bash`.
|
||||||
|
|
||||||
Historically, the libmdbx builing is based on single
|
So just use CMake or GNU Make in your habitual manner and feel free to
|
||||||
[Makefile](https://en.wikipedia.org/wiki/Makefile) which assumes
|
fill an issue or make pull request in the case something will be
|
||||||
different recipes depending on target platform. In the next versions, it
|
unexpected or broken down.
|
||||||
is planned to switch to [CMake](https://en.wikipedia.org/wiki/CMake),
|
|
||||||
with the refusal to support other tools.
|
|
||||||
|
|
||||||
#### DSO/DLL unloading and destructors of Thread-Local-Storage objects
|
#### DSO/DLL unloading and destructors of Thread-Local-Storage objects
|
||||||
When building _libmdbx_ as a shared library or use static _libmdbx_ as a
|
When building _libmdbx_ as a shared library or use static _libmdbx_ as a
|
||||||
part of another dynamic library, it is advisable to make sure that your
|
part of another dynamic library, it is advisable to make sure that your
|
||||||
system ensures the correctness of the call destructors of
|
system ensures the correctness of the call destructors of
|
||||||
Thread-Local-Storage objects when unloading dynamic libraries'.
|
Thread-Local-Storage objects when unloading dynamic libraries.
|
||||||
|
|
||||||
If this is not the case, then unloading a dynamic-link library with
|
If this is not the case, then unloading a dynamic-link library with
|
||||||
_libmdbx_ code inside, can result in either a resource leak or a crash
|
_libmdbx_ code inside, can result in either a resource leak or a crash
|
||||||
@ -507,22 +393,15 @@ directory with source code, and `gmake check` (or `make check`) to run
|
|||||||
the basic tests.
|
the basic tests.
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
For building _libmdbx_ on Windows the [Microsoft Visual
|
For build _libmdbx_ on Windows the _original_ CMake and [Microsoft Visual
|
||||||
Studio](https://en.wikipedia.org/wiki/Microsoft_Visual_Studio) is
|
Studio](https://en.wikipedia.org/wiki/Microsoft_Visual_Studio) are
|
||||||
recommended, but not tools such as MinGW, MSYS, or Cygwin. To do this,
|
recommended.
|
||||||
the libmdbx source code includes the set of appropriate project files
|
|
||||||
that are compatible with Visual Studio 2015, the Windows SDK for Windows
|
|
||||||
8.1, and later. Just open `mdbx.sln` in Visual Studio and build the
|
|
||||||
library.
|
|
||||||
|
|
||||||
To build with newer versions of the SDK or Visual Studio, it should be
|
|
||||||
sufficient to execute "Retarget solution". To build for older versions
|
|
||||||
of Windows (such as Windows XP) or by older compilers, you will need to
|
|
||||||
convert or recreate the corresponding project files yourself.
|
|
||||||
|
|
||||||
Building by MinGW, MSYS or Cygwin is potentially possible. However,
|
Building by MinGW, MSYS or Cygwin is potentially possible. However,
|
||||||
these scripts are not tested and will probably require you to modify the
|
these scripts are not tested and will probably require you to modify the
|
||||||
Makefile. It should be noted that in _libmdbx_ was efforts to resolve
|
CMakeLists.txt or Makefile respectively.
|
||||||
|
|
||||||
|
It should be noted that in _libmdbx_ was efforts to resolve
|
||||||
runtime dependencies from CRT and other libraries Visual Studio.
|
runtime dependencies from CRT and other libraries Visual Studio.
|
||||||
For this is enough define the `MDBX_AVOID_CRT` during build.
|
For this is enough define the `MDBX_AVOID_CRT` during build.
|
||||||
|
|
||||||
@ -533,9 +412,9 @@ run the [long stochastic test scenario](test/long_stochastic.sh),
|
|||||||
the such testing is recommended with place the test data on the
|
the such testing is recommended with place the test data on the
|
||||||
[RAM-disk](https://en.wikipedia.org/wiki/RAM_drive).
|
[RAM-disk](https://en.wikipedia.org/wiki/RAM_drive).
|
||||||
|
|
||||||
### MacOS X
|
### MacOS
|
||||||
Current [native build tools](https://en.wikipedia.org/wiki/Xcode) for
|
Current [native build tools](https://en.wikipedia.org/wiki/Xcode) for
|
||||||
MacOS X include GNU Make, CLANG and an outdated version of bash.
|
MacOS include GNU Make, CLANG and an outdated version of bash.
|
||||||
Therefore, to build the library, it is enough to run `make all` in the
|
Therefore, to build the library, it is enough to run `make all` in the
|
||||||
directory with source code, and run `make check` to execute the base
|
directory with source code, and run `make check` to execute the base
|
||||||
tests. If something goes wrong, it is recommended to install
|
tests. If something goes wrong, it is recommended to install
|
||||||
@ -703,11 +582,10 @@ $ objdump -f -h -j .text libmdbx.so
|
|||||||
libmdbx.so: file format elf64-x86-64
|
libmdbx.so: file format elf64-x86-64
|
||||||
architecture: i386:x86-64, flags 0x00000150:
|
architecture: i386:x86-64, flags 0x00000150:
|
||||||
HAS_SYMS, DYNAMIC, D_PAGED
|
HAS_SYMS, DYNAMIC, D_PAGED
|
||||||
start address 0x0000000000003870
|
start address 0x0000000000003710
|
||||||
|
|
||||||
Sections:
|
Sections:
|
||||||
Idx Name Size VMA LMA File off Algn
|
Idx Name Size VMA LMA File off Algn
|
||||||
11 .text 000173d4 0000000000003870 0000000000003870 00003870 2**4
|
11 .text 00015eff 0000000000003710 0000000000003710 00003710 2**4
|
||||||
CONTENTS, ALLOC, LOAD, READONLY, CODE
|
CONTENTS, ALLOC, LOAD, READONLY, CODE
|
||||||
|
|
||||||
```
|
```
|
||||||
|
320
mdbx.h
320
mdbx.h
@ -301,7 +301,7 @@
|
|||||||
* - estimate size of range query result
|
* - estimate size of range query result
|
||||||
* - double perfomance by LIFO reclaiming on storages with write-back
|
* - double perfomance by LIFO reclaiming on storages with write-back
|
||||||
* - use sequences and canary markers
|
* - use sequences and canary markers
|
||||||
* - use out-of-space callback (aka OOM-KICK)
|
* - use lack-of-space callback (aka OOM-KICK)
|
||||||
* - use exclusive mode
|
* - use exclusive mode
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
@ -408,8 +408,35 @@
|
|||||||
* Write transactions prevent other write transactions, since writes are
|
* Write transactions prevent other write transactions, since writes are
|
||||||
* serialized.
|
* serialized.
|
||||||
*
|
*
|
||||||
* The "next" version of libmdbx (MithrilDB) will solve this issue
|
* Understanding the problem of long-lived read transactions requires some
|
||||||
* for read-only transactions.
|
* explanation, but can be difficult for quick perception. So is is
|
||||||
|
* reasonable to simplify this as follows:
|
||||||
|
* 1. Garbage collection problem exists in all databases one way or
|
||||||
|
* another, e.g. VACUUM in PostgreSQL. But in _libmdbx_ it's even more
|
||||||
|
* discernible because of high transaction rate and intentional
|
||||||
|
* internals simplification in favor of performance.
|
||||||
|
*
|
||||||
|
* 2. MDBX employs Multiversion concurrency control on the Copy-on-Write
|
||||||
|
* basis, that allows multiple readers runs in parallel with a write
|
||||||
|
* transaction without blocking. An each write transaction needs free
|
||||||
|
* pages to put the changed data, that pages will be placed in the new
|
||||||
|
* b-tree snapshot at commit. MDBX efficiently recycling pages from
|
||||||
|
* previous created unused snapshots, BUT this is impossible if anyone
|
||||||
|
* a read transaction use such snapshot.
|
||||||
|
*
|
||||||
|
* 3. Thus massive altering of data during a parallel long read operation
|
||||||
|
* will increase the process's work set and may exhaust entire free
|
||||||
|
* database space.
|
||||||
|
*
|
||||||
|
* A good example of long readers is a hot backup to the slow destination
|
||||||
|
* or debugging of a client application while retaining an active read
|
||||||
|
* transaction. LMDB this results in MAP_FULL error and subsequent write
|
||||||
|
* performance degradation.
|
||||||
|
*
|
||||||
|
* MDBX mostly solve "long-lived" readers issue by the lack-of-space callback
|
||||||
|
* which allow to aborts long readers, and by the MDBX_LIFORECLAIM mode which
|
||||||
|
* addresses subsequent performance degradation.
|
||||||
|
* The "next" version of libmdbx (MithrilDB) will completely solve this.
|
||||||
*
|
*
|
||||||
* - Avoid suspending a process with active transactions. These would then be
|
* - Avoid suspending a process with active transactions. These would then be
|
||||||
* "long-lived" as above.
|
* "long-lived" as above.
|
||||||
@ -615,7 +642,7 @@ typedef pthread_t mdbx_tid_t;
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*** MDBX version information *************************************************/
|
/**** MDBX version information ************************************************/
|
||||||
typedef struct mdbx_version_info {
|
typedef struct mdbx_version_info {
|
||||||
uint8_t major;
|
uint8_t major;
|
||||||
uint8_t minor;
|
uint8_t minor;
|
||||||
@ -976,7 +1003,7 @@ LIBMDBX_API char *mdbx_dump_val(const MDBX_val *key, char *const buf,
|
|||||||
* write-back cache, this can significantly increase write performance, up to
|
* write-back cache, this can significantly increase write performance, up to
|
||||||
* several times in a best case scenario.
|
* several times in a best case scenario.
|
||||||
*
|
*
|
||||||
* LIFO's recycling policy means that for reuse pages will be taken which became
|
* LIFO recycling policy means that for reuse pages will be taken which became
|
||||||
* unused the lastest (i.e. just now or most recently). Therefore the loop of
|
* unused the lastest (i.e. just now or most recently). Therefore the loop of
|
||||||
* database pages circulation becomes as short as possible. In other words, the
|
* database pages circulation becomes as short as possible. In other words, the
|
||||||
* number of pages, that are overwritten in memory and on disk during a series
|
* number of pages, that are overwritten in memory and on disk during a series
|
||||||
@ -1170,43 +1197,43 @@ LIBMDBX_API char *mdbx_dump_val(const MDBX_val *key, char *const buf,
|
|||||||
* for particular write transaction.
|
* for particular write transaction.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* don't sync meta-page after commit,
|
/* Don't sync meta-page after commit,
|
||||||
* see description in the "SYNC MODES" section above. */
|
* see description in the "SYNC MODES" section above. */
|
||||||
#define MDBX_NOMETASYNC 0x40000u
|
#define MDBX_NOMETASYNC 0x40000u
|
||||||
|
|
||||||
/* don't sync anything but keep previous steady commits,
|
/* Don't sync anything but keep previous steady commits,
|
||||||
* see description in the "SYNC MODES" section above.
|
* see description in the "SYNC MODES" section above.
|
||||||
*
|
*
|
||||||
* (!) don't combine this flag with MDBX_MAPASYNC
|
* (!) don't combine this flag with MDBX_MAPASYNC
|
||||||
* since you will got MDBX_UTTERLY_NOSYNC in that way (see below) */
|
* since you will got MDBX_UTTERLY_NOSYNC in that way (see below) */
|
||||||
#define MDBX_NOSYNC 0x10000u
|
#define MDBX_NOSYNC 0x10000u
|
||||||
|
|
||||||
/* use asynchronous msync when MDBX_WRITEMAP is used,
|
/* Use asynchronous msync when MDBX_WRITEMAP is used,
|
||||||
* see description in the "SYNC MODES" section above.
|
* see description in the "SYNC MODES" section above.
|
||||||
*
|
*
|
||||||
* (!) don't combine this flag with MDBX_NOSYNC
|
* (!) don't combine this flag with MDBX_NOSYNC
|
||||||
* since you will got MDBX_UTTERLY_NOSYNC in that way (see below) */
|
* since you will got MDBX_UTTERLY_NOSYNC in that way (see below) */
|
||||||
#define MDBX_MAPASYNC 0x100000u
|
#define MDBX_MAPASYNC 0x100000u
|
||||||
|
|
||||||
/* don't sync anything and wipe previous steady commits,
|
/* Don't sync anything and wipe previous steady commits,
|
||||||
* see description in the "SYNC MODES" section above. */
|
* see description in the "SYNC MODES" section above. */
|
||||||
#define MDBX_UTTERLY_NOSYNC (MDBX_NOSYNC | MDBX_MAPASYNC)
|
#define MDBX_UTTERLY_NOSYNC (MDBX_NOSYNC | MDBX_MAPASYNC)
|
||||||
|
|
||||||
/**** DATABASE FLAGS **********************************************************/
|
/**** DATABASE FLAGS **********************************************************/
|
||||||
/* use reverse string keys */
|
/* Use reverse string keys */
|
||||||
#define MDBX_REVERSEKEY 0x02u
|
#define MDBX_REVERSEKEY 0x02u
|
||||||
/* use sorted duplicates */
|
/* Use sorted duplicates */
|
||||||
#define MDBX_DUPSORT 0x04u
|
#define MDBX_DUPSORT 0x04u
|
||||||
/* numeric keys in native byte order, either uint32_t or uint64_t.
|
/* Numeric keys in native byte order, either uint32_t or uint64_t.
|
||||||
* The keys must all be of the same size. */
|
* The keys must all be of the same size. */
|
||||||
#define MDBX_INTEGERKEY 0x08u
|
#define MDBX_INTEGERKEY 0x08u
|
||||||
/* with MDBX_DUPSORT, sorted dup items have fixed size */
|
/* With MDBX_DUPSORT, sorted dup items have fixed size */
|
||||||
#define MDBX_DUPFIXED 0x10u
|
#define MDBX_DUPFIXED 0x10u
|
||||||
/* with MDBX_DUPSORT, dups are MDBX_INTEGERKEY-style integers */
|
/* With MDBX_DUPSORT, dups are MDBX_INTEGERKEY-style integers */
|
||||||
#define MDBX_INTEGERDUP 0x20u
|
#define MDBX_INTEGERDUP 0x20u
|
||||||
/* with MDBX_DUPSORT, use reverse string dups */
|
/* With MDBX_DUPSORT, use reverse string dups */
|
||||||
#define MDBX_REVERSEDUP 0x40u
|
#define MDBX_REVERSEDUP 0x40u
|
||||||
/* create DB if not already existing */
|
/* Create DB if not already existing */
|
||||||
#define MDBX_CREATE 0x40000u
|
#define MDBX_CREATE 0x40000u
|
||||||
|
|
||||||
/**** DATA UPDATE FLAGS *******************************************************/
|
/**** DATA UPDATE FLAGS *******************************************************/
|
||||||
@ -1334,7 +1361,7 @@ typedef enum MDBX_cursor_op {
|
|||||||
#define MDBX_LAST_ERRCODE MDBX_BUSY
|
#define MDBX_LAST_ERRCODE MDBX_BUSY
|
||||||
|
|
||||||
/* The mdbx_put() or mdbx_replace() was called for key,
|
/* The mdbx_put() or mdbx_replace() was called for key,
|
||||||
that has more that one associated value. */
|
* that has more that one associated value. */
|
||||||
#define MDBX_EMULTIVAL (-30421)
|
#define MDBX_EMULTIVAL (-30421)
|
||||||
|
|
||||||
/* Bad signature of a runtime object(s), this can mean:
|
/* Bad signature of a runtime object(s), this can mean:
|
||||||
@ -1441,8 +1468,8 @@ LIBMDBX_API int mdbx_env_create(MDBX_env **penv);
|
|||||||
* mdbx_env_set_geometry() are incompatible (i.e. for instance, different page
|
* mdbx_env_set_geometry() are incompatible (i.e. for instance, different page
|
||||||
* size) then mdbx_env_open() will return MDBX_INCOMPATIBLE error.
|
* size) then mdbx_env_open() will return MDBX_INCOMPATIBLE error.
|
||||||
*
|
*
|
||||||
* [in] mode The UNIX permissions to set on created files. Zero value means
|
* [in] mode The UNIX permissions to set on created files. Zero value means
|
||||||
* to open existing, but do not create.
|
* to open existing, but do not create.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -1641,10 +1668,10 @@ LIBMDBX_API int mdbx_env_sync_ex(MDBX_env *env, int force, int nonblock);
|
|||||||
LIBMDBX_API int mdbx_env_sync(MDBX_env *env);
|
LIBMDBX_API int mdbx_env_sync(MDBX_env *env);
|
||||||
LIBMDBX_API int mdbx_env_sync_poll(MDBX_env *env);
|
LIBMDBX_API int mdbx_env_sync_poll(MDBX_env *env);
|
||||||
|
|
||||||
/* Sets threshold to force flush the data buffers to disk,
|
/* Sets threshold to force flush the data buffers to disk, even of MDBX_NOSYNC,
|
||||||
* even of MDBX_NOSYNC, MDBX_NOMETASYNC and MDBX_MAPASYNC flags
|
* MDBX_NOMETASYNC and MDBX_MAPASYNC flags in the environment. The threshold
|
||||||
* in the environment. The value affects all processes which operates with given
|
* value affects all processes which operates with given environment until the
|
||||||
* DB until the last process close DB or a new value will be settled.
|
* last process close environment or a new value will be settled.
|
||||||
*
|
*
|
||||||
* Data is always written to disk when mdbx_txn_commit() is called, but the
|
* Data is always written to disk when mdbx_txn_commit() is called, but the
|
||||||
* operating system may keep it buffered. MDBX always flushes the OS buffers
|
* operating system may keep it buffered. MDBX always flushes the OS buffers
|
||||||
@ -1663,23 +1690,24 @@ LIBMDBX_API int mdbx_env_set_syncbytes(MDBX_env *env, size_t threshold);
|
|||||||
|
|
||||||
/* Sets relative period since the last unsteay commit to force flush the data
|
/* Sets relative period since the last unsteay commit to force flush the data
|
||||||
* buffers to disk, even of MDBX_NOSYNC, MDBX_NOMETASYNC and MDBX_MAPASYNC flags
|
* buffers to disk, even of MDBX_NOSYNC, MDBX_NOMETASYNC and MDBX_MAPASYNC flags
|
||||||
* in the environment. The value affects all processes which operates with given
|
* in the environment. The relative period value affects all processes which
|
||||||
* DB until the last process close DB or a new value will be settled.
|
* operates with given environment until the last process close environment or a
|
||||||
|
* new value will be settled.
|
||||||
*
|
*
|
||||||
* Data is always written to disk when mdbx_txn_commit() is called, but the
|
* Data is always written to disk when mdbx_txn_commit() is called, but the
|
||||||
* operating system may keep it buffered. MDBX always flushes the OS buffers
|
* operating system may keep it buffered. MDBX always flushes the OS buffers
|
||||||
* upon commit as well, unless the environment was opened with MDBX_NOSYNC,
|
* upon commit as well, unless the environment was opened with MDBX_NOSYNC,
|
||||||
* MDBX_MAPASYNC or in part MDBX_NOMETASYNC.
|
* MDBX_MAPASYNC or in part MDBX_NOMETASYNC.
|
||||||
*
|
*
|
||||||
* Settled period don't checked asynchronously, but only inside the functions.
|
* Settled period don't checked asynchronously, but only by the
|
||||||
* mdbx_txn_commit() and mdbx_env_sync(). Therefore, in cases where transactions
|
* mdbx_txn_commit() and mdbx_env_sync() functions. Therefore, in cases where
|
||||||
* are committed infrequently and/or irregularly, polling by mdbx_env_sync() may
|
* transactions are committed infrequently and/or irregularly, polling by
|
||||||
* be a reasonable solution to timeout enforcement.
|
* mdbx_env_sync() may be a reasonable solution to timeout enforcement.
|
||||||
*
|
*
|
||||||
* The default is 0, than mean no any timeout checked, and no additional
|
* The default is 0, than mean no any timeout checked, and no additional
|
||||||
* flush will be made.
|
* flush will be made.
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create().
|
||||||
* [in] seconds_16dot16 The period in 1/65536 of second when a synchronous
|
* [in] seconds_16dot16 The period in 1/65536 of second when a synchronous
|
||||||
* flush would be made since the last unsteay commit.
|
* flush would be made since the last unsteay commit.
|
||||||
*
|
*
|
||||||
@ -1698,7 +1726,7 @@ LIBMDBX_API int mdbx_env_set_syncperiod(MDBX_env *env,
|
|||||||
* Legacy mdbx_env_close() correspond to calling mdbx_env_close_ex() with the
|
* Legacy mdbx_env_close() correspond to calling mdbx_env_close_ex() with the
|
||||||
* argument dont_sync=false.
|
* argument dont_sync=false.
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create().
|
||||||
* [in] dont_sync A dont'sync flag, if non-zero the last checkpoint (meta-page
|
* [in] dont_sync A dont'sync flag, if non-zero the last checkpoint (meta-page
|
||||||
* update) will be kept "as is" and may be still "weak" in the
|
* update) will be kept "as is" and may be still "weak" in the
|
||||||
* NOSYNC/MAPASYNC modes. Such "weak" checkpoint will be
|
* NOSYNC/MAPASYNC modes. Such "weak" checkpoint will be
|
||||||
@ -1710,7 +1738,7 @@ LIBMDBX_API int mdbx_env_set_syncperiod(MDBX_env *env,
|
|||||||
* Some possible errors are:
|
* Some possible errors are:
|
||||||
* - MDBX_BUSY = The write transaction is running by other thread, in such
|
* - MDBX_BUSY = The write transaction is running by other thread, in such
|
||||||
* case MDBX_env instance has NOT be destroyed not released!
|
* case MDBX_env instance has NOT be destroyed not released!
|
||||||
* NOTE: if any other error code was returned then given
|
* NOTE: if any OTHER error code was returned then given
|
||||||
* MDBX_env instance has been destroyed and released.
|
* MDBX_env instance has been destroyed and released.
|
||||||
* - MDBX_PANIC = If mdbx_env_close_ex() was called in the child process
|
* - MDBX_PANIC = If mdbx_env_close_ex() was called in the child process
|
||||||
* after fork(). In this case MDBX_PANIC is a expecte,
|
* after fork(). In this case MDBX_PANIC is a expecte,
|
||||||
@ -1740,8 +1768,8 @@ LIBMDBX_API int mdbx_env_set_flags(MDBX_env *env, unsigned flags, int onoff);
|
|||||||
|
|
||||||
/* Get environment flags.
|
/* Get environment flags.
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create().
|
||||||
* [out] flags The address of an integer to store the flags
|
* [out] flags The address of an integer to store the flags.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -1765,7 +1793,7 @@ LIBMDBX_API int mdbx_env_get_path(MDBX_env *env, const char **path);
|
|||||||
* NOTE: All MDBX file descriptors have FD_CLOEXEC and
|
* NOTE: All MDBX file descriptors have FD_CLOEXEC and
|
||||||
* could't be used after exec() and or fork().
|
* could't be used after exec() and or fork().
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create().
|
||||||
* [out] fd Address of a int to contain the descriptor.
|
* [out] fd Address of a int to contain the descriptor.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
@ -1786,7 +1814,7 @@ LIBMDBX_API int mdbx_env_get_fd(MDBX_env *env, mdbx_filehandle_t *fd);
|
|||||||
* read-only opened environment.
|
* read-only opened environment.
|
||||||
*
|
*
|
||||||
* Both mdbx_env_info_ex() and legacy mdbx_env_info() could be called either
|
* Both mdbx_env_info_ex() and legacy mdbx_env_info() could be called either
|
||||||
* before and afrer mdbx_env_open(), either within the write transaction running
|
* before or after mdbx_env_open(), either within the write transaction running
|
||||||
* by current thread or not:
|
* by current thread or not:
|
||||||
*
|
*
|
||||||
* - In case mdbx_env_info_ex() or legacy mdbx_env_info() was called BEFORE
|
* - In case mdbx_env_info_ex() or legacy mdbx_env_info() was called BEFORE
|
||||||
@ -1990,8 +2018,8 @@ LIBMDBX_API intptr_t mdbx_limits_txnsize_max(intptr_t pagesize);
|
|||||||
* This function may only be called after mdbx_env_create() and before
|
* This function may only be called after mdbx_env_create() and before
|
||||||
* mdbx_env_open().
|
* mdbx_env_open().
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create().
|
||||||
* [in] readers The maximum number of reader lock table slots
|
* [in] readers The maximum number of reader lock table slots.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2001,8 +2029,8 @@ LIBMDBX_API int mdbx_env_set_maxreaders(MDBX_env *env, unsigned readers);
|
|||||||
|
|
||||||
/* Get the maximum number of threads/reader slots for the environment.
|
/* Get the maximum number of threads/reader slots for the environment.
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create().
|
||||||
* [out] readers Address of an integer to store the number of readers
|
* [out] readers Address of an integer to store the number of readers.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2021,8 +2049,8 @@ LIBMDBX_API int mdbx_env_get_maxreaders(MDBX_env *env, unsigned *readers);
|
|||||||
* expensive: 7-120 words per transaction, and every mdbx_dbi_open()
|
* expensive: 7-120 words per transaction, and every mdbx_dbi_open()
|
||||||
* does a linear search of the opened slots.
|
* does a linear search of the opened slots.
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create().
|
||||||
* [in] dbs The maximum number of databases
|
* [in] dbs The maximum number of databases.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2032,14 +2060,14 @@ LIBMDBX_API int mdbx_env_set_maxdbs(MDBX_env *env, MDBX_dbi dbs);
|
|||||||
|
|
||||||
/* Get the maximum size of keys and MDBX_DUPSORT data we can write.
|
/* Get the maximum size of keys and MDBX_DUPSORT data we can write.
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create().
|
||||||
*
|
*
|
||||||
* Returns The maximum size of a key we can write. */
|
* Returns The maximum size of a key we can write. */
|
||||||
LIBMDBX_API int mdbx_env_get_maxkeysize(MDBX_env *env);
|
LIBMDBX_API int mdbx_env_get_maxkeysize(MDBX_env *env);
|
||||||
|
|
||||||
/* Set application information associated with the MDBX_env.
|
/* Set application information associated with the MDBX_env.
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create().
|
||||||
* [in] ctx An arbitrary pointer for whatever the application needs.
|
* [in] ctx An arbitrary pointer for whatever the application needs.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success. */
|
* Returns A non-zero error value on failure and 0 on success. */
|
||||||
@ -2056,9 +2084,9 @@ LIBMDBX_API void *mdbx_env_get_userctx(MDBX_env *env);
|
|||||||
* The transaction handle may be discarded using mdbx_txn_abort()
|
* The transaction handle may be discarded using mdbx_txn_abort()
|
||||||
* or mdbx_txn_commit().
|
* or mdbx_txn_commit().
|
||||||
*
|
*
|
||||||
* NOTE: A transaction and its cursors must only be used by a single thread, and
|
* NOTE: A transaction and its cursors must only be used by a single thread,
|
||||||
* a thread may only have a single transaction at a time. If MDBX_NOTLS is in
|
* and a thread may only have a single transaction at a time. If MDBX_NOTLS is
|
||||||
* use, this does not apply to read-only transactions.
|
* in use, this does not apply to read-only transactions.
|
||||||
*
|
*
|
||||||
* NOTE: Cursors may not span transactions.
|
* NOTE: Cursors may not span transactions.
|
||||||
*
|
*
|
||||||
@ -2172,7 +2200,7 @@ LIBMDBX_API MDBX_env *mdbx_txn_env(MDBX_txn *txn);
|
|||||||
*
|
*
|
||||||
* This returns the flags associated with this transaction.
|
* This returns the flags associated with this transaction.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
*
|
*
|
||||||
* Returns A transaction flags, valid if input is an valid transaction,
|
* Returns A transaction flags, valid if input is an valid transaction,
|
||||||
* otherwise -1. */
|
* otherwise -1. */
|
||||||
@ -2184,7 +2212,7 @@ LIBMDBX_API int mdbx_txn_flags(MDBX_txn *txn);
|
|||||||
* transaction, this corresponds to the snapshot being read; concurrent readers
|
* transaction, this corresponds to the snapshot being read; concurrent readers
|
||||||
* will frequently have the same transaction ID.
|
* will frequently have the same transaction ID.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
*
|
*
|
||||||
* Returns A transaction ID, valid if input is an active transaction,
|
* Returns A transaction ID, valid if input is an active transaction,
|
||||||
* otherwise 0. */
|
* otherwise 0. */
|
||||||
@ -2198,7 +2226,7 @@ LIBMDBX_API uint64_t mdbx_txn_id(MDBX_txn *txn);
|
|||||||
* A cursor must be closed explicitly always, before or after its transaction
|
* A cursor must be closed explicitly always, before or after its transaction
|
||||||
* ends. It can be reused with mdbx_cursor_renew() before finally closing it.
|
* ends. It can be reused with mdbx_cursor_renew() before finally closing it.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2216,7 +2244,9 @@ LIBMDBX_API int mdbx_txn_commit(MDBX_txn *txn);
|
|||||||
* A cursor must be closed explicitly always, before or after its transaction
|
* A cursor must be closed explicitly always, before or after its transaction
|
||||||
* ends. It can be reused with mdbx_cursor_renew() before finally closing it.
|
* ends. It can be reused with mdbx_cursor_renew() before finally closing it.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin(). */
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
|
*
|
||||||
|
* Returns A non-zero error value on failure and 0 on success. */
|
||||||
LIBMDBX_API int mdbx_txn_abort(MDBX_txn *txn);
|
LIBMDBX_API int mdbx_txn_abort(MDBX_txn *txn);
|
||||||
|
|
||||||
/* Reset a read-only transaction.
|
/* Reset a read-only transaction.
|
||||||
@ -2237,7 +2267,9 @@ LIBMDBX_API int mdbx_txn_abort(MDBX_txn *txn);
|
|||||||
* being reused when writers commit new data, and so under heavy load the
|
* being reused when writers commit new data, and so under heavy load the
|
||||||
* database size may grow much more rapidly than otherwise.
|
* database size may grow much more rapidly than otherwise.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin() */
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
|
*
|
||||||
|
* Returns A non-zero error value on failure and 0 on success. */
|
||||||
LIBMDBX_API int mdbx_txn_reset(MDBX_txn *txn);
|
LIBMDBX_API int mdbx_txn_reset(MDBX_txn *txn);
|
||||||
|
|
||||||
/* Renew a read-only transaction.
|
/* Renew a read-only transaction.
|
||||||
@ -2246,7 +2278,7 @@ LIBMDBX_API int mdbx_txn_reset(MDBX_txn *txn);
|
|||||||
* released by mdbx_txn_reset(). It must be called before a reset transaction
|
* released by mdbx_txn_reset(). It must be called before a reset transaction
|
||||||
* may be used again.
|
* may be used again.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2286,7 +2318,7 @@ LIBMDBX_API int mdbx_canary_put(MDBX_txn *txn, const mdbx_canary *canary);
|
|||||||
/* Returns fours integers markers (aka "canary") associated with the
|
/* Returns fours integers markers (aka "canary") associated with the
|
||||||
* environment.
|
* environment.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] canary The address of an mdbx_canary structure where the information
|
* [in] canary The address of an mdbx_canary structure where the information
|
||||||
* will be copied.
|
* will be copied.
|
||||||
*
|
*
|
||||||
@ -2326,7 +2358,7 @@ typedef int(MDBX_cmp_func)(const MDBX_val *a, const MDBX_val *b);
|
|||||||
* must be called before opening the environment. Table names are
|
* must be called before opening the environment. Table names are
|
||||||
* keys in the internal unnamed database, and may be read but not written.
|
* keys in the internal unnamed database, and may be read but not written.
|
||||||
*
|
*
|
||||||
* [in] txn transaction handle returned by mdbx_txn_begin()
|
* [in] txn transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] name The name of the database to open. If only a single
|
* [in] name The name of the database to open. If only a single
|
||||||
* database is needed in the environment, this value may be NULL.
|
* database is needed in the environment, this value may be NULL.
|
||||||
* [in] flags Special options for this database. This parameter must be set
|
* [in] flags Special options for this database. This parameter must be set
|
||||||
@ -2365,7 +2397,7 @@ typedef int(MDBX_cmp_func)(const MDBX_val *a, const MDBX_val *b);
|
|||||||
* [in] keycmp Optional custom key comparison function for a database.
|
* [in] keycmp Optional custom key comparison function for a database.
|
||||||
* [in] datacmp Optional custom data comparison function for a database, takes
|
* [in] datacmp Optional custom data comparison function for a database, takes
|
||||||
* effect only if database was opened with the MDB_DUPSORT flag.
|
* effect only if database was opened with the MDB_DUPSORT flag.
|
||||||
* [out] dbi Address where the new MDBX_dbi handle will be stored
|
* [out] dbi Address where the new MDBX_dbi handle will be stored.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2385,10 +2417,10 @@ LIBMDBX_API int mdbx_dbi_open(MDBX_txn *txn, const char *name, unsigned flags,
|
|||||||
|
|
||||||
/* Retrieve statistics for a database.
|
/* Retrieve statistics for a database.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open()
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
* [out] stat The address of an MDBX_stat structure where the statistics
|
* [out] stat The address of an MDBX_stat structure where the statistics
|
||||||
* will be copied
|
* will be copied.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2398,8 +2430,8 @@ LIBMDBX_API int mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *stat,
|
|||||||
|
|
||||||
/* Retrieve the DB flags and status for a database handle.
|
/* Retrieve the DB flags and status for a database handle.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open()
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
* [out] flags Address where the flags will be returned.
|
* [out] flags Address where the flags will be returned.
|
||||||
* [out] state Address where the state will be returned.
|
* [out] state Address where the state will be returned.
|
||||||
*
|
*
|
||||||
@ -2432,16 +2464,18 @@ LIBMDBX_API int mdbx_dbi_flags(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags);
|
|||||||
* the handle value. Usually it's better to set a bigger mdbx_env_set_maxdbs(),
|
* the handle value. Usually it's better to set a bigger mdbx_env_set_maxdbs(),
|
||||||
* unless that value would be large.
|
* unless that value would be large.
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create().
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open() */
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
|
*
|
||||||
|
* Returns A non-zero error value on failure and 0 on success. */
|
||||||
LIBMDBX_API int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi);
|
LIBMDBX_API int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi);
|
||||||
|
|
||||||
/* Empty or delete and close a database.
|
/* Empty or delete and close a database.
|
||||||
*
|
*
|
||||||
* See mdbx_dbi_close() for restrictions about closing the DB handle.
|
* See mdbx_dbi_close() for restrictions about closing the DB handle.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open()
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
* [in] del 0 to empty the DB, 1 to delete it from the environment
|
* [in] del 0 to empty the DB, 1 to delete it from the environment
|
||||||
* and close the DB handle.
|
* and close the DB handle.
|
||||||
*
|
*
|
||||||
@ -2465,10 +2499,10 @@ LIBMDBX_API int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, int del);
|
|||||||
* NOTE: Values returned from the database are valid only until a
|
* NOTE: Values returned from the database are valid only until a
|
||||||
* subsequent update operation, or the end of the transaction.
|
* subsequent update operation, or the end of the transaction.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open()
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
* [in] key The key to search for in the database
|
* [in] key The key to search for in the database.
|
||||||
* [in,out] data The data corresponding to the key
|
* [in,out] data The data corresponding to the key.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2485,10 +2519,10 @@ LIBMDBX_API int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
|||||||
* 2. Updates BOTH the key and the data for pointing to the actual key-value
|
* 2. Updates BOTH the key and the data for pointing to the actual key-value
|
||||||
* pair inside the database.
|
* pair inside the database.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open()
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
* [in,out] key The key to search for in the database
|
* [in,out] key The key to search for in the database.
|
||||||
* [in,out] data The data corresponding to the key
|
* [in,out] data The data corresponding to the key.
|
||||||
* [out] values_count The optional address to return number of values
|
* [out] values_count The optional address to return number of values
|
||||||
* associated with given key, i.e.
|
* associated with given key, i.e.
|
||||||
* = 0 - in case MDBX_NOTFOUND error;
|
* = 0 - in case MDBX_NOTFOUND error;
|
||||||
@ -2515,10 +2549,10 @@ LIBMDBX_API int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
|||||||
* 3. Updates BOTH the key and the data for pointing to the actual key-value
|
* 3. Updates BOTH the key and the data for pointing to the actual key-value
|
||||||
* pair inside the database.
|
* pair inside the database.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open()
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
* [in,out] key The key to search for in the database
|
* [in,out] key The key to search for in the database.
|
||||||
* [in,out] data The data corresponding to the key
|
* [in,out] data The data corresponding to the key.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and MDBX_RESULT_TRUE (0) or
|
* Returns A non-zero error value on failure and MDBX_RESULT_TRUE (0) or
|
||||||
* MDBX_RESULT_TRUE on success (as described above).
|
* MDBX_RESULT_TRUE on success (as described above).
|
||||||
@ -2535,10 +2569,10 @@ LIBMDBX_API int mdbx_get_nearest(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
|||||||
* if duplicates are disallowed, or adding a duplicate data item if
|
* if duplicates are disallowed, or adding a duplicate data item if
|
||||||
* duplicates are allowed (MDBX_DUPSORT).
|
* duplicates are allowed (MDBX_DUPSORT).
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open()
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
* [in] key The key to store in the database
|
* [in] key The key to store in the database.
|
||||||
* [in,out] data The data to store
|
* [in,out] data The data to store.
|
||||||
* [in] flags Special options for this operation. This parameter must be
|
* [in] flags Special options for this operation. This parameter must be
|
||||||
* set to 0 or by bitwise OR'ing together one or more of the
|
* set to 0 or by bitwise OR'ing together one or more of the
|
||||||
* values described here.
|
* values described here.
|
||||||
@ -2615,8 +2649,8 @@ LIBMDBX_API int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
|||||||
* [in] key The key to store in the database.
|
* [in] key The key to store in the database.
|
||||||
* [in,out] new_data The data to store, if NULL then deletion will be
|
* [in,out] new_data The data to store, if NULL then deletion will be
|
||||||
* performed.
|
* performed.
|
||||||
* [in,out] old_data The buffer for retrieve previous value as described
|
* [in,out] old_data The buffer for retrieve previous value as describe
|
||||||
* above.
|
* above.
|
||||||
* [in] flags Special options for this operation. This parameter must
|
* [in] flags Special options for this operation. This parameter must
|
||||||
* be set to 0 or by bitwise OR'ing together one or more of
|
* be set to 0 or by bitwise OR'ing together one or more of
|
||||||
* the values described in mdbx_put() description above,
|
* the values described in mdbx_put() description above,
|
||||||
@ -2633,17 +2667,17 @@ LIBMDBX_API int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
|||||||
*
|
*
|
||||||
* This function removes key/data pairs from the database.
|
* This function removes key/data pairs from the database.
|
||||||
*
|
*
|
||||||
* The data parameter is NOT ignored regardless the database does
|
* NOTE: The data parameter is NOT ignored regardless the database does
|
||||||
* support sorted duplicate data items or not. If the data parameter
|
* support sorted duplicate data items or not. If the data parameter
|
||||||
* is non-NULL only the matching data item will be deleted.
|
* is non-NULL only the matching data item will be deleted.
|
||||||
*
|
*
|
||||||
* This function will return MDBX_NOTFOUND if the specified key/data
|
* This function will return MDBX_NOTFOUND if the specified key/data
|
||||||
* pair is not in the database.
|
* pair is not in the database.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open()
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
* [in] key The key to delete from the database
|
* [in] key The key to delete from the database.
|
||||||
* [in] data The data to delete
|
* [in] data The data to delete.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2662,9 +2696,15 @@ LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
|||||||
* A cursor must be closed explicitly always, before or after its transaction
|
* A cursor must be closed explicitly always, before or after its transaction
|
||||||
* ends. It can be reused with mdbx_cursor_renew() before finally closing it.
|
* ends. It can be reused with mdbx_cursor_renew() before finally closing it.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* NOTE: In contrast to LMDB, the MDBX required that any opened cursors can be
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open()
|
* reused and must be freed explicitly, regardless ones was opened in a
|
||||||
* [out] cursor Address where the new MDBX_cursor handle will be stored
|
* read-only or write transaction. The REASON for this is eliminates ambiguity
|
||||||
|
* which helps to avoid errors such as: use-after-free, double-free, i.e. memory
|
||||||
|
* corruption and segfaults.
|
||||||
|
*
|
||||||
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
|
* [out] cursor Address where the new MDBX_cursor handle will be stored.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2677,22 +2717,28 @@ LIBMDBX_API int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi,
|
|||||||
* The cursor handle will be freed and must not be used again after this call,
|
* The cursor handle will be freed and must not be used again after this call,
|
||||||
* but its transaction may still be live.
|
* but its transaction may still be live.
|
||||||
*
|
*
|
||||||
* [in] cursor A cursor handle returned by mdbx_cursor_open() */
|
* NOTE: In contrast to LMDB, the MDBX required that any opened cursors can be
|
||||||
|
* reused and must be freed explicitly, regardless ones was opened in a
|
||||||
|
* read-only or write transaction. The REASON for this is eliminates ambiguity
|
||||||
|
* which helps to avoid errors such as: use-after-free, double-free, i.e. memory
|
||||||
|
* corruption and segfaults.
|
||||||
|
*
|
||||||
|
* [in] cursor A cursor handle returned by mdbx_cursor_open(). */
|
||||||
LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor);
|
LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor);
|
||||||
|
|
||||||
/* Renew a cursor handle.
|
/* Renew a cursor handle.
|
||||||
*
|
*
|
||||||
* A cursor is associated with a specific transaction and database.
|
* A cursor is associated with a specific transaction and database. The cursor
|
||||||
* In contrast to LMDB, the MDBX allow any cursor to be re-used by using
|
* may be associated with a new transaction, and referencing the same database
|
||||||
|
* handle as it was created with. This may be done whether the previous
|
||||||
|
* transaction is live or dead.
|
||||||
|
*
|
||||||
|
* NOTE: In contrast to LMDB, the MDBX allow any cursor to be re-used by using
|
||||||
* mdbx_cursor_renew(), to avoid unnecessary malloc/free overhead until it freed
|
* mdbx_cursor_renew(), to avoid unnecessary malloc/free overhead until it freed
|
||||||
* by mdbx_cursor_close().
|
* by mdbx_cursor_close().
|
||||||
*
|
*
|
||||||
* The cursor may be associated with a new transaction, and referencing the
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* same database handle as it was created with.
|
* [in] cursor A cursor handle returned by mdbx_cursor_open().
|
||||||
*
|
|
||||||
* This may be done whether the previous transaction is live or dead.
|
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
|
||||||
* [in] cursor A cursor handle returned by mdbx_cursor_open()
|
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2701,12 +2747,12 @@ LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor);
|
|||||||
|
|
||||||
/* Return the cursor's transaction handle.
|
/* Return the cursor's transaction handle.
|
||||||
*
|
*
|
||||||
* [in] cursor A cursor handle returned by mdbx_cursor_open() */
|
* [in] cursor A cursor handle returned by mdbx_cursor_open(). */
|
||||||
LIBMDBX_API MDBX_txn *mdbx_cursor_txn(MDBX_cursor *cursor);
|
LIBMDBX_API MDBX_txn *mdbx_cursor_txn(MDBX_cursor *cursor);
|
||||||
|
|
||||||
/* Return the cursor's database handle.
|
/* Return the cursor's database handle.
|
||||||
*
|
*
|
||||||
* [in] cursor A cursor handle returned by mdbx_cursor_open() */
|
* [in] cursor A cursor handle returned by mdbx_cursor_open(). */
|
||||||
LIBMDBX_API MDBX_dbi mdbx_cursor_dbi(MDBX_cursor *cursor);
|
LIBMDBX_API MDBX_dbi mdbx_cursor_dbi(MDBX_cursor *cursor);
|
||||||
|
|
||||||
/* Retrieve by cursor.
|
/* Retrieve by cursor.
|
||||||
@ -2717,10 +2763,10 @@ LIBMDBX_API MDBX_dbi mdbx_cursor_dbi(MDBX_cursor *cursor);
|
|||||||
* and the address and length of the data are returned in the object to which
|
* and the address and length of the data are returned in the object to which
|
||||||
* data refers. See mdbx_get() for restrictions on using the output values.
|
* data refers. See mdbx_get() for restrictions on using the output values.
|
||||||
*
|
*
|
||||||
* [in] cursor A cursor handle returned by mdbx_cursor_open()
|
* [in] cursor A cursor handle returned by mdbx_cursor_open().
|
||||||
* [in,out] key The key for a retrieved item
|
* [in,out] key The key for a retrieved item.
|
||||||
* [in,out] data The data of a retrieved item
|
* [in,out] data The data of a retrieved item.
|
||||||
* [in] op A cursor operation MDBX_cursor_op
|
* [in] op A cursor operation MDBX_cursor_op.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2734,7 +2780,7 @@ LIBMDBX_API int mdbx_cursor_get(MDBX_cursor *cursor, MDBX_val *key,
|
|||||||
* This function stores key/data pairs into the database. The cursor is
|
* This function stores key/data pairs into the database. The cursor is
|
||||||
* positioned at the new item, or on failure usually near it.
|
* positioned at the new item, or on failure usually near it.
|
||||||
*
|
*
|
||||||
* [in] cursor A cursor handle returned by mdbx_cursor_open()
|
* [in] cursor A cursor handle returned by mdbx_cursor_open().
|
||||||
* [in] key The key operated on.
|
* [in] key The key operated on.
|
||||||
* [in] data The data operated on.
|
* [in] data The data operated on.
|
||||||
* [in] flags Options for this operation. This parameter
|
* [in] flags Options for this operation. This parameter
|
||||||
@ -2805,7 +2851,7 @@ LIBMDBX_API int mdbx_cursor_put(MDBX_cursor *cursor, MDBX_val *key,
|
|||||||
* on it. Both MDBX_NEXT and MDBX_GET_CURRENT will return the same record after
|
* on it. Both MDBX_NEXT and MDBX_GET_CURRENT will return the same record after
|
||||||
* this operation.
|
* this operation.
|
||||||
*
|
*
|
||||||
* [in] cursor A cursor handle returned by mdbx_cursor_open()
|
* [in] cursor A cursor handle returned by mdbx_cursor_open().
|
||||||
* [in] flags Options for this operation. This parameter must be set to 0
|
* [in] flags Options for this operation. This parameter must be set to 0
|
||||||
* or one of the values described here.
|
* or one of the values described here.
|
||||||
*
|
*
|
||||||
@ -2824,8 +2870,8 @@ LIBMDBX_API int mdbx_cursor_del(MDBX_cursor *cursor, unsigned flags);
|
|||||||
* This call is valid for all databases, but reasonable only for that support
|
* This call is valid for all databases, but reasonable only for that support
|
||||||
* sorted duplicate data items MDBX_DUPSORT.
|
* sorted duplicate data items MDBX_DUPSORT.
|
||||||
*
|
*
|
||||||
* [in] cursor A cursor handle returned by mdbx_cursor_open()
|
* [in] cursor A cursor handle returned by mdbx_cursor_open().
|
||||||
* [out] countp Address where the count will be stored
|
* [out] countp Address where the count will be stored.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -2836,7 +2882,7 @@ LIBMDBX_API int mdbx_cursor_count(MDBX_cursor *cursor, size_t *countp);
|
|||||||
/* Determines whether the cursor is pointed to a key-value pair or not,
|
/* Determines whether the cursor is pointed to a key-value pair or not,
|
||||||
* i.e. was not positioned or points to the end of data.
|
* i.e. was not positioned or points to the end of data.
|
||||||
*
|
*
|
||||||
* [in] cursor A cursor handle returned by mdbx_cursor_open()
|
* [in] cursor A cursor handle returned by mdbx_cursor_open().
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* - MDBX_RESULT_TRUE = no more data available or cursor not positioned;
|
* - MDBX_RESULT_TRUE = no more data available or cursor not positioned;
|
||||||
@ -2846,7 +2892,7 @@ LIBMDBX_API int mdbx_cursor_eof(MDBX_cursor *mc);
|
|||||||
|
|
||||||
/* Determines whether the cursor is pointed to the first key-value pair or not.
|
/* Determines whether the cursor is pointed to the first key-value pair or not.
|
||||||
*
|
*
|
||||||
* [in] cursor A cursor handle returned by mdbx_cursor_open()
|
* [in] cursor A cursor handle returned by mdbx_cursor_open().
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* - MDBX_RESULT_TRUE = cursor positioned to the first key-value pair.
|
* - MDBX_RESULT_TRUE = cursor positioned to the first key-value pair.
|
||||||
@ -2856,7 +2902,7 @@ LIBMDBX_API int mdbx_cursor_on_first(MDBX_cursor *mc);
|
|||||||
|
|
||||||
/* Determines whether the cursor is pointed to the last key-value pair or not.
|
/* Determines whether the cursor is pointed to the last key-value pair or not.
|
||||||
*
|
*
|
||||||
* [in] cursor A cursor handle returned by mdbx_cursor_open()
|
* [in] cursor A cursor handle returned by mdbx_cursor_open().
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* - MDBX_RESULT_TRUE = cursor positioned to the last key-value pair.
|
* - MDBX_RESULT_TRUE = cursor positioned to the last key-value pair.
|
||||||
@ -3011,10 +3057,10 @@ LIBMDBX_API int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result,
|
|||||||
* This returns a comparison as if the two data items were keys in the
|
* This returns a comparison as if the two data items were keys in the
|
||||||
* specified database.
|
* specified database.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open()
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
* [in] a The first item to compare
|
* [in] a The first item to compare.
|
||||||
* [in] b The second item to compare
|
* [in] b The second item to compare.
|
||||||
*
|
*
|
||||||
* Returns < 0 if a < b, 0 if a == b, > 0 if a > b */
|
* Returns < 0 if a < b, 0 if a == b, > 0 if a > b */
|
||||||
LIBMDBX_API int mdbx_cmp(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
|
LIBMDBX_API int mdbx_cmp(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
|
||||||
@ -3025,10 +3071,10 @@ LIBMDBX_API int mdbx_cmp(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
|
|||||||
* This returns a comparison as if the two items were data items of the
|
* This returns a comparison as if the two items were data items of the
|
||||||
* specified database. The database must have the MDBX_DUPSORT flag.
|
* specified database. The database must have the MDBX_DUPSORT flag.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open()
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
* [in] a The first item to compare
|
* [in] a The first item to compare.
|
||||||
* [in] b The second item to compare
|
* [in] b The second item to compare.
|
||||||
*
|
*
|
||||||
* Returns < 0 if a < b, 0 if a == b, > 0 if a > b */
|
* Returns < 0 if a < b, 0 if a == b, > 0 if a > b */
|
||||||
LIBMDBX_API int mdbx_dcmp(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
|
LIBMDBX_API int mdbx_dcmp(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
|
||||||
@ -3061,8 +3107,8 @@ typedef int(MDBX_reader_list_func)(void *ctx, int num, int slot, mdbx_pid_t pid,
|
|||||||
|
|
||||||
/* Enumarete the entries in the reader lock table.
|
/* Enumarete the entries in the reader lock table.
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create().
|
||||||
* [in] func A MDBX_reader_list_func function
|
* [in] func A MDBX_reader_list_func function.
|
||||||
* [in] ctx An arbitrary context pointer for the enumeration function.
|
* [in] ctx An arbitrary context pointer for the enumeration function.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success,
|
* Returns A non-zero error value on failure and 0 on success,
|
||||||
@ -3072,8 +3118,8 @@ LIBMDBX_API int mdbx_reader_list(MDBX_env *env, MDBX_reader_list_func *func,
|
|||||||
|
|
||||||
/* Check for stale entries in the reader lock table.
|
/* Check for stale entries in the reader lock table.
|
||||||
*
|
*
|
||||||
* [in] env An environment handle returned by mdbx_env_create()
|
* [in] env An environment handle returned by mdbx_env_create().
|
||||||
* [out] dead Number of stale slots that were cleared
|
* [out] dead Number of stale slots that were cleared.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success,
|
* Returns A non-zero error value on failure and 0 on success,
|
||||||
* or MDBX_RESULT_TRUE (-1) if a dead reader(s) found or mutex was recovered. */
|
* or MDBX_RESULT_TRUE (-1) if a dead reader(s) found or mutex was recovered. */
|
||||||
@ -3084,14 +3130,14 @@ LIBMDBX_API int mdbx_reader_check(MDBX_env *env, int *dead);
|
|||||||
* Returns an information for estimate how much given read-only
|
* Returns an information for estimate how much given read-only
|
||||||
* transaction is lagging relative the to actual head.
|
* transaction is lagging relative the to actual head.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [out] percent Percentage of page allocation in the database.
|
* [out] percent Percentage of page allocation in the database.
|
||||||
*
|
*
|
||||||
* Returns Number of transactions committed after the given was started for
|
* Returns Number of transactions committed after the given was started for
|
||||||
* read, or negative value on failure. */
|
* read, or negative value on failure. */
|
||||||
LIBMDBX_API int mdbx_txn_straggler(MDBX_txn *txn, int *percent);
|
LIBMDBX_API int mdbx_txn_straggler(MDBX_txn *txn, int *percent);
|
||||||
|
|
||||||
/* A callback function to resolve issues with a laggard readers.
|
/* A lack-of-space callback function to resolve issues with a laggard readers.
|
||||||
*
|
*
|
||||||
* Read transactions prevent reuse of pages freed by newer write transactions,
|
* Read transactions prevent reuse of pages freed by newer write transactions,
|
||||||
* thus the database can grow quickly. This callback will be called when there
|
* thus the database can grow quickly. This callback will be called when there
|
||||||
@ -3310,10 +3356,10 @@ LIBMDBX_API int mdbx_set_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
|||||||
* and the address and length of the data are returned in the object to which
|
* and the address and length of the data are returned in the object to which
|
||||||
* data refers. See mdbx_get() for restrictions on using the output values.
|
* data refers. See mdbx_get() for restrictions on using the output values.
|
||||||
*
|
*
|
||||||
* [in] cursor A cursor handle returned by mdbx_cursor_open()
|
* [in] cursor A cursor handle returned by mdbx_cursor_open().
|
||||||
* [in,out] key The key for a retrieved item
|
* [in,out] key The key for a retrieved item.
|
||||||
* [in,out] data The data of a retrieved item
|
* [in,out] data The data of a retrieved item.
|
||||||
* [in] op A cursor operation MDBX_cursor_op
|
* [in] op A cursor operation MDBX_cursor_op.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -3340,10 +3386,10 @@ LIBMDBX_API int mdbx_cursor_get_attr(MDBX_cursor *mc, MDBX_val *key,
|
|||||||
* NOTE: Values returned from the database are valid only until a
|
* NOTE: Values returned from the database are valid only until a
|
||||||
* subsequent update operation, or the end of the transaction.
|
* subsequent update operation, or the end of the transaction.
|
||||||
*
|
*
|
||||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
* [in] txn A transaction handle returned by mdbx_txn_begin().
|
||||||
* [in] dbi A database handle returned by mdbx_dbi_open()
|
* [in] dbi A database handle returned by mdbx_dbi_open().
|
||||||
* [in] key The key to search for in the database
|
* [in] key The key to search for in the database.
|
||||||
* [in,out] data The data corresponding to the key
|
* [in,out] data The data corresponding to the key.
|
||||||
*
|
*
|
||||||
* Returns A non-zero error value on failure and 0 on success, some
|
* Returns A non-zero error value on failure and 0 on success, some
|
||||||
* possible errors are:
|
* possible errors are:
|
||||||
@ -3353,8 +3399,8 @@ LIBMDBX_API int mdbx_get_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
|||||||
MDBX_val *data, mdbx_attr_t *attrptr);
|
MDBX_val *data, mdbx_attr_t *attrptr);
|
||||||
#endif /* MDBX_NEXENTA_ATTRS */
|
#endif /* MDBX_NEXENTA_ATTRS */
|
||||||
|
|
||||||
/******************************************************************************/
|
/*******************************************************************************
|
||||||
/* LY: temporary workaround for Elbrus's memcmp() bug. */
|
* LY: temporary workaround for Elbrus's memcmp() bug. */
|
||||||
#ifndef __GLIBC_PREREQ
|
#ifndef __GLIBC_PREREQ
|
||||||
#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
|
#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
|
||||||
#define __GLIBC_PREREQ(maj, min) \
|
#define __GLIBC_PREREQ(maj, min) \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user