2017-01-09 02:48:00 +08:00
libmdbx
======================================
Extended LMDB, aka "Расширенная LMDB".
*The Future will Positive. Всё будет хорошо.*
2017-02-18 03:18:12 +08:00
[![Build Status ](https://travis-ci.org/ReOpen/libmdbx.svg?branch=devel )](https://travis-ci.org/ReOpen/libmdbx)
2017-03-29 06:11:33 +08:00
[![Build status ](https://ci.appveyor.com/api/projects/status/v21jlh5kfmk85r7t/branch/devel?svg=true )](https://ci.appveyor.com/project/leo-yuriev/libmdbx/branch/devel)
2017-06-12 20:41:36 +08:00
[![Coverity Scan Status ](https://scan.coverity.com/projects/12915/badge.svg )](https://scan.coverity.com/projects/reopen-libmdbx)
2017-01-09 02:48:00 +08:00
2017-05-15 18:03:09 +08:00
English version [by Google ](https://translate.googleusercontent.com/translate_c?act=url&ie=UTF8&sl=ru&tl=en&u=https://github.com/ReOpen/libmdbx/tree/devel )
and [by Yandex ](https://translate.yandex.ru/translate?url=https%3A%2F%2Fgithub.com%2FReOpen%2Flibmdbx%2Ftree%2Fdevel&lang=ru-en ).
2017-01-09 02:48:00 +08:00
2017-01-09 06:19:24 +08:00
2017-01-18 21:40:56 +08:00
## Кратко
2017-02-08 22:52:05 +08:00
_libmdbx_ - это встраиваемый key-value движок хранения с о специфическим
набором возможностей, которые при правильном применении позволяют
создавать уникальные решения с чемпионской производительностью, идеально
2017-07-04 17:07:05 +08:00
сочетаясь с технологией
[MRAM ](https://en.wikipedia.org/wiki/Magnetoresistive_random-access_memory ).
2017-02-08 22:52:05 +08:00
2017-07-04 17:07:05 +08:00
_libmdbx_ умеет обновлять совместно используемый набор данных, никак не
мешая при этом параллельным операциям чтения, не применяя атомарных
операций к самим данным, и обеспечивая согласованность при аварийной
остановке в любой момент. Поэтому _libmdbx_ позволяя строить системы с
линейным масштабированием производительности чтения/поиска по ядрам CPU
и амортизационной стоимостью любых операций Olog(N).
2017-01-18 21:40:56 +08:00
### История
2017-02-08 22:52:05 +08:00
2017-01-18 21:40:56 +08:00
_libmdbx_ является потомком "Lightning Memory-Mapped Database",
известной под аббревиатурой
[LMDB ](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database ).
Изначально доработка производилась в составе проекта
2017-02-08 22:52:05 +08:00
[ReOpenLDAP ](https://github.com/ReOpen/ReOpenLDAP ). Примерно за год
работы внесенные изменения приобрели самостоятельную ценность. Осенью
2015 доработанный движок был выделен в отдельный проект, который был
[представлен на конференции Highload++
2015](http://www.highload.ru/2015/abstracts/1831.html).
2017-01-18 21:40:56 +08:00
2017-07-04 17:07:05 +08:00
В начале 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).
2017-01-18 21:40:56 +08:00
Характеристики и ключевые особенности
=====================================
_libmdbx_ наследует все ключевые возможности и особенности от
своего прародителя [LMDB ](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database ),
с устранением описанных далее проблем и архитектурных недочетов.
1. Данные хранятся в упорядоченном отображении (ordered map), ключи всегда
отсортированы, поддерживается выборка диапазонов (range lookups).
2. Данные отображается в память каждого работающего с БД процесса.
2017-07-04 17:07:05 +08:00
К данным и ключам обеспечивается прямой доступ без необходимости их
копирования.
2017-01-18 21:40:56 +08:00
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 ).
Изменения строго последовательны и не блокируются чтением,
2017-05-24 06:42:10 +08:00
конфликты между транзакциями не возможны.
2017-04-12 03:24:31 +08:00
При этом гарантируется чтение только зафиксированных данных, см [relaxing serializability ](https://en.wikipedia.org/wiki/Serializability ).
2017-01-18 21:40:56 +08:00
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. Эффективное хранение дубликатов (ключей с несколькими
значениями), без дублирования ключей, с сортировкой значений, в
том числе целочисленных (для вторичных индексов).
2017-07-04 17:07:05 +08:00
6. Эффективная поддержка коротких ключей фиксированной длины, в том числе целочисленных.
2017-01-18 21:40:56 +08:00
7. Амортизационная стоимость любой операции Olog(N),
2017-07-04 17:07:05 +08:00
[WAF ](https://en.wikipedia.org/wiki/Write_amplification ) (Write Amplification Factor) и RAF (Read Amplification Factor) также Olog(N).
2017-01-18 21:40:56 +08:00
8. Нет [WAL ](https://en.wikipedia.org/wiki/Write-ahead_logging ) и журнала
транзакций, после сбоев не требуется восстановление. Н е требуется компактификация
или какое-либо периодическое обслуживание. Поддерживается резервное копирование
"по горячему", на работающей БД без приостановки изменения данных.
9. Отсутствует какое-либо внутреннее управление памятью или кэшированием. Всё
2017-07-04 17:07:05 +08:00
необходимое штатно выполняет ядро О С !
Сравнение производительности
============================
В с е данные получены многократным прогоном тестов на ноутбуке 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).
--------------------------------------------------------------------------------
### Интегральная производительность
![Comparison #1: Integral Performance ](https://raw.githubusercontent.com/wiki/ReOpen/libmdbx/img/perf-slide-1.png )
Показана соотнесенная сумма показателей производительности в трёх
бенчмарках:
- Чтение/Поиск на машине с 4-мя процессорами;
- Транзакции с [CRUD ](https://ru.wikipedia.org/wiki/CRUD )-операциями
(вставка, чтение, обновление, удаление) в режиме **синхронной фиксации**
данных (fdatasync при завершении каждой транзакции или аналог);
- Транзакции с [CRUD ](https://ru.wikipedia.org/wiki/CRUD )-операциями
(вставка, чтение, обновление, удаление) в режиме **отложенной фиксации**
данных (отложенная запись посредством файловой систем или аналог);
*Бенчмарк в режиме асинхронной записи не включен по двум причинам:*
1. Такое сравнение не совсем правомочно, е г о следует делать с движками
ориентированными на хранение данных в памяти (Tarantool, Redis).
2. Превосходство libmdbx становится еще более подавляющем, что мешает
восприятию информации.
--------------------------------------------------------------------------------
### Масштабируемость чтения
![Comparison #2: Read Scalability ](https://raw.githubusercontent.com/wiki/ReOpen/libmdbx/img/perf-slide-2.png )
Для каждого движка показана суммарная производительность при
одновременном выполнении запросов чтения/поиска в 1-2-4-8 потоков на
машине с 4-мя процессорами.
--------------------------------------------------------------------------------
### Синхронная фиксация
![Comparison #3: Sync-write mode ](https://raw.githubusercontent.com/wiki/ReOpen/libmdbx/img/perf-slide-3.png )
- Линейная шкала слева и темные прямоугольники соответствуют количеству
транзакций в секунду, усредненному за все время теста.
- Логарифмическая шкала справа и желтые интервальные отрезки
соответствуют времени выполнения транзакций. При этом каждый отрезок
показывает минимальное и максимальное время затраченной на выполнения
транзакций, а крестик показывает среднеквадратичное значение.
Выполняется **10.000 транзакций в режиме синхронной фиксации данных** на
диске. При этом требуется гарантия, что при аварийном выключении питания
(или другом подобном с б о е ) все данные будут консистентны и полностью
соответствовать последней завершенной транзакции. В _libmdbx_ в этом
режиме при фиксации каждой транзакции выполняется системный вызов
[fdatasync ](https://linux.die.net/man/2/fdatasync ).
В каждой транзакции выполняется CRUD-операция (две вставки, одной
чтение, одно обновление, одно удаление). Бенчмарк стартует на пустой
базе и в результате выполняемых действий при завершении в базе
насчитывается 10.000 небольших key-value записей.
--------------------------------------------------------------------------------
2017-01-09 06:19:24 +08:00
2017-07-04 17:07:05 +08:00
### Отложенная фиксация
![Comparison #4: Lazy-write mode ](https://raw.githubusercontent.com/wiki/ReOpen/libmdbx/img/perf-slide-4.png )
2017-01-09 06:19:24 +08:00
2017-07-04 17:07:05 +08:00
- Линейная шкала слева и темные прямоугольники соответствуют количеству транзакций в секунду, усредненному за все время теста.
- Логарифмическая шкала справа и желтые интервальные отрезки соответствуют времени выполнения транзакций. При этом каждый отрезок показывает минимальное и максимальное время затраченной на выполнения транзакций, а крестик показывает среднеквадратичное значение.
Выполняется **100.000 транзакций в режиме отложенной фиксации данных** на диске. При этом требуется гарантия, что при аварийном выключении питания (или другом подобном с б о е ) все данные будут консистентны на момент завершения одной из транзакций, но допускается потеря изменений из некоторого количества последних транзакций, что для многих движков предполагает включение [WAL ](https://en.wikipedia.org/wiki/Write-ahead_logging ) (write-ahead logging) либо журнала транзакций, который в свою очередь опирается на гарантию упорядоченности данных в журналируемой файловой системе. _libmdbx_ при этом не ведет WAL, а передает весь контроль файловой системе и ядру О С .
В каждой транзакции выполняется CRUD-операция (две вставки, одной чтение, одно обновление, одно удаление).
Бенчмарк стартует на пустой базе и в результате выполняемых действий при завершении в базе насчитывается 100.000 небольших key-value записей.
--------------------------------------------------------------------------------
### Асинхронная фиксация
![Comparison #5: Async-write mode ](https://raw.githubusercontent.com/wiki/ReOpen/libmdbx/img/perf-slide-5.png )
- Линейная шкала слева и темные прямоугольники соответствуют количеству
транзакций в секунду, усредненному за все время теста.
- Логарифмическая шкала справа и желтые интервальные отрезки
соответствуют времени выполнения транзакций. При этом каждый отрезок
показывает минимальное и максимальное время затраченной на выполнения
транзакций, а крестик показывает среднеквадратичное значение.
Выполняется **1.000.000 транзакций в режиме асинхронной фиксации
данных** на диске. При этом требуется гарантия, что при аварийном
выключении питания (или другом подобном с б о е ) все данные будут
консистентны на момент завершения одной из транзакций, но допускается
потеря изменений из любого количества последних транзакций. В о всех
движках при этом включался режим предполагающий минимальную нагрузку
записи на диск, и соответственно минимальную гарантию сохранности
данных. В _libmdbx_ при этом используется режим асинхронной записи
измененных страниц на диск силами ядра О С посредством системрго вызова
[msync(MS_ASYNC) ](https://linux.die.net/man/2/msync ).
В каждой транзакции выполняется CRUD-операция (две вставки, одной
чтение, одно обновление, одно удаление). Бенчмарк стартует на пустой
базе и в результате выполняемых действий при завершении в базе
насчитывается 1.000.000 небольших key-value записей.
--------------------------------------------------------------------------------
### Стоимость как потребление ресурсов
![Comparison #6: Cost comparison ](https://raw.githubusercontent.com/wiki/ReOpen/libmdbx/img/perf-slide-6.png )
Показана соотнесенная сумма использованных ресурсов в ходе бенчмарка в
режиме отложенной фиксации:
- суммарное количество операций ввода-вывода (IOPS), как записи, так и
чтения.
- суммарное затраченное время процессора, как в режиме пользователя,
так и в режиме ядра О С .
- максимальный объем места на диске. который требовался во время работы
теста.
Движок _ForestDB_ был исключен при окончательном формировании диаграммы,
так как многократно превысил потребление каждого из ресурсов (потратил
процессорное время на генерацию IOPS для заполнения диска). Что не
позволяло наглядно сравнить показатели остальных движков на одной
диаграмме.
В с е данные собирались посредством системного вывова
[getrusage() ](http://man7.org/linux/man-pages/man2/getrusage.2.html ) и
сканированием директорий с данными.
--------------------------------------------------------------------------------
## Недостатки и Компромиссы
2017-01-09 06:19:24 +08:00
1. Единовременно может выполняться не более одной транзакция изменения данных
(один писатель). Зато все изменения всегда последовательны, не может быть
конфликтов или ошибок при откате транзакций.
2. Отсутствие [WAL ](https://en.wikipedia.org/wiki/Write-ahead_logging )
обуславливает относительно большой
2017-07-04 17:07:05 +08:00
[WAF ](https://en.wikipedia.org/wiki/Write_amplification ) (Write
Amplification Factor). Поэтому фиксация изменений на диске может быть
дорогой и является главным ограничителем для производительности по
записи. В качестве компромисса предлагается несколько режимов ленивой
и/или периодической фиксации. В том числе режим `MAPASYNC` , при котором
изменения происходят только в памяти и асинхронно фиксируются на диске
ядром О С .
2017-01-09 06:19:24 +08:00
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 ) выполняется на
2017-07-04 17:07:05 +08:00
уровне страниц в [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` .
2017-01-09 06:19:24 +08:00
2017-01-18 21:40:56 +08:00
4. В _LMDB_ существует проблема долгих чтений (приостановленных читателей),
которая приводит к деградации производительности и переполнению БД.
В _libmdbx_ предложены средства для предотвращения, выхода из проблемной
ситуации и устранения её последствий. Подробности ниже.
2017-01-09 06:19:24 +08:00
2017-01-18 21:40:56 +08:00
5. В _LMDB_ есть вероятность разрушения БД в режиме `WRITEMAP+MAPASYNC` .
В _libmdbx_ для `WRITEMAP+MAPASYNC` гарантируется как сохранность базы,
так и согласованность данных. При этом также, в качестве альтернативы,
предложен режим `UTTERLY_NOSYNC` . Подробности ниже.
2017-01-09 02:48:00 +08:00
2017-01-09 06:19:24 +08:00
#### Проблема долгих чтений
2017-07-04 17:07:05 +08:00
*Следует отметить*, что проблема "сборки мусора" так или иначе
существует во всех СУБД (Vacuum в PostgreSQL). Однако в случае _libmdbx_
и LMDB она проявляется более остро, прежде всего из-за высокой
производительности, а также из-за намеренного прощения внутренних
механизмов ради производительности.
2017-01-18 21:40:56 +08:00
Понимание проблемы требует некоторых пояснений, которые
изложены ниже, но могут быть сложны для быстрого восприятия.
Поэтому, тезисно:
2017-01-09 06:19:24 +08:00
2017-01-18 21:40:56 +08:00
* Изменение данных на фоне долгой операции чтения может
приводить к исчерпанию места в БД.
2017-01-09 02:48:00 +08:00
2017-01-18 21:40:56 +08:00
* После чего любая попытка обновить данные будет приводить к
ошибке `MAP_FULL` до завершения долгой операции чтения.
2017-01-09 02:48:00 +08:00
2017-01-18 21:40:56 +08:00
* Характерными примерами долгих чтений являются горячее
резервное копирования и отладка клиентского приложения при
активной транзакции чтения.
2017-01-09 02:48:00 +08:00
2017-01-18 21:40:56 +08:00
* В оригинальной _LMDB_ после этого будет наблюдаться
устойчивая деградация производительности всех механизмов
обратной записи на диск (в I/O контроллере, в гипервизоре,
в ядре О С ).
2017-01-09 02:48:00 +08:00
2017-01-18 21:40:56 +08:00
* В _libmdbx_ предусмотрен механизм аварийного прерывания таких
операций, а также режим `LIFO RECLAIM` устраняющий последующую
деградацию производительности.
2017-01-09 02:48:00 +08:00
2017-01-18 21:40:56 +08:00
Операции чтения выполняются в контексте снимка данных (версии
БД), который был актуальным на момент старта транзакции чтения.
Такой читаемый снимок поддерживается неизменным до завершения
операции. В свою очередь, это не позволяет повторно
использовать страницы БД в последующих версиях (снимках БД).
2017-01-09 02:48:00 +08:00
2017-01-18 21:40:56 +08:00
Другими словами, если обновление данных выполняется на фоне
долгой операции чтения, то вместо повторного использования
"старых" ненужных страниц будут выделяться новые, так как
"старые" страницы составляют снимок БД, который еще
2017-01-09 06:19:24 +08:00
используется долгой операцией чтения.
2017-01-18 21:40:56 +08:00
В результате, при интенсивном изменении данных и достаточно
длительной операции чтения, в БД могут быть исчерпаны свободные
страницы, что не позволит создавать новые снимки/версии БД.
Такая ситуация будет сохраняться до завершения операции чтения,
которая использует старый снимок данных и препятствует
повторному использованию страниц БД.
Однако, на этом проблемы не заканчиваются. После описанной
ситуации, все дополнительные страницы, которые были выделены
пока переработка старых была невозможна, будут участвовать в
цикле выделения/освобождения до конца жизни экземпляра БД. В
оригинальной _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+MAPASYNC`
При работе в режиме `WRITEMAP+MAPSYNC` запись измененных
страниц выполняется ядром О С , что имеет ряд преимуществ. Так
например, при крахе приложения, ядро О С сохранит все изменения.
Однако, при аварийном отключении питания или с б о е в ядре О С , на
диске будет сохранена только часть измененных страниц БД. При
этом с большой вероятностью может оказаться так, что будут
сохранены мета-страницы с о ссылками на страницы с новыми
версиями данных, но не сами новые данные. В этом случае БД
будет безвозвратна разрушена, даже если до аварии производилась
2017-02-22 01:16:54 +08:00
полная синхронизация данных (посредством `mdbx_env_sync()` ).
2017-01-18 21:40:56 +08:00
В _libmdbx_ эта проблема устранена, подробности ниже.
2017-07-04 17:07:05 +08:00
--------------------------------------------------------------------------------
2017-01-18 21:40:56 +08:00
2017-07-04 17:07:05 +08:00
Дополнительные "фичи" _libmdbx_ относительно LMDB
=================================================
2017-01-09 02:48:00 +08:00
2017-01-09 06:19:24 +08:00
1. Режим `LIFO RECLAIM` .
2017-01-18 21:40:56 +08:00
Для повторного использования выбираются не самые старые, а
самые новые страницы из доступных. З а счет этого цикл
использования страниц всегда имеет минимальную длину и не
зависит от общего числа выделенных страниц.
2017-01-09 02:48:00 +08:00
2017-01-18 21:40:56 +08:00
В результате механизмы кэширования и обратной записи работают с
максимально возможной эффективностью. В случае использования
контроллера дисков или системы хранения с
[BBWC ](https://en.wikipedia.org/wiki/BBWC ) возможно
многократное увеличение производительности по записи
(обновлению данных).
2017-01-09 06:19:24 +08:00
2. Обработчик `OOM-KICK` .
2017-01-18 21:40:56 +08:00
Посредством `mdbx_env_set_oomfunc()` может быть установлен
внешний обработчик (callback), который будет вызван при
исчерпания свободных страниц из-за долгой операцией чтения.
Обработчику будет передан PID и pthread_id. В свою очередь
обработчик может предпринять одно из действий:
* отправить сигнал kill (#9), если долгое чтение выполняется
сторонним процессом;
* отменить или перезапустить проблемную операцию чтения, если
операция выполняется одним из потоков текущего процесса;
* подождать некоторое время, в расчете что проблемная операция
чтения будет штатно завершена;
* перервать текущую операцию изменения данных с возвратом кода
ошибки.
3. Гарантия сохранности БД в режиме `WRITEMAP+MAPSYNC` .
При работе в режиме `WRITEMAP+MAPSYNC` запись измененных
страниц выполняется ядром О С , что имеет ряд преимуществ. Так
например, при крахе приложения, ядро О С сохранит все изменения.
Однако, при аварийном отключении питания или с б о е в ядре О С , на
диске будет сохранена только часть измененных страниц БД. При
этом с большой вероятностью может оказаться так, что будут
сохранены мета-страницы с о ссылками на страницы с новыми
версиями данных, но не сами новые данные. В этом случае БД
будет безвозвратна разрушена, даже если до аварии производилась
2017-02-22 01:16:54 +08:00
полная синхронизация данных (посредством `mdbx_env_sync()` ).
2017-01-18 21:40:56 +08:00
В _libmdbx_ эта проблема устранена путем полной переработки
пути записи данных:
* В режиме `WRITEMAP+MAPSYNC` _libmdbx_ не обновляет
мета-страницы непосредственно, а поддерживает их теневые копии
с переносом изменений после фиксации данных.
* При завершении транзакций, в зависимости от состояния
синхронности данных между диском и оперативной память,
_libmdbx_ помечает точки фиксации либо как сильные (strong),
либо как слабые (weak). Так например, в режиме
`WRITEMAP+MAPSYNC` завершаемые транзакции помечаются как
слабые, а при явной синхронизации данных как сильные.
* При открытии БД выполняется автоматический откат к последней
сильной фиксации. Этим обеспечивается гарантия сохранности БД.
К сожалению, такая гарантия надежности не дается бесплатно. Для
сохранности данных, страницы формирующие крайний снимок с
сильной фиксацией, не должны повторно использоваться
(перезаписываться) до формирования следующей сильной точки
фиксации. Таким образом, крайняя точка фиксации создает
описанный выше эффект "долгого чтения". Разница же здесь в том,
что при исчерпании свободных страниц ситуация будет
автоматически исправлена, посредством записи изменений на диск
и формированием новой сильной точки фиксации.
В последующих версиях _libmdbx_ будут предусмотрены средства
для асинхронной записи данных на диск с автоматическим
формированием сильных точек фиксации.
4. Возможность автоматического формирования контрольных точек
2017-02-08 22:52:05 +08:00
(с б р о с а данных на диск) при накоплении заданного объёма изменений,
устанавливаемого функцией `mdbx_env_set_syncbytes()` .
2017-01-09 02:48:00 +08:00
2017-01-18 21:40:56 +08:00
5. Возможность получить отставание текущей транзакции чтения от
2017-02-08 22:52:05 +08:00
последней версии данных в БД посредством `mdbx_txn_straggler()` .
2017-01-09 02:48:00 +08:00
2017-02-08 22:52:05 +08:00
6. Утилита mdbx_chk для проверки БД и функция `mdbx_env_pgwalk()` для
обхода всех страниц БД.
2017-01-09 02:48:00 +08:00
2017-02-08 22:52:05 +08:00
7. Управление отладкой и получение отладочных сообщений посредством
`mdbx_setup_debug()` .
2017-01-09 02:48:00 +08:00
2017-01-18 21:40:56 +08:00
8. Возможность связать с каждой завершаемой транзакцией до 3
2017-02-08 22:52:05 +08:00
дополнительных маркеров посредством `mdbx_canary_put()` , и прочитать их
в транзакции чтения посредством `mdbx_canary_get()` .
2017-01-09 02:48:00 +08:00
2017-02-08 22:52:05 +08:00
9. Возможность узнать есть ли за текущей позицией курсора строка данных
посредством `mdbx_cursor_eof()` .
2017-01-09 02:48:00 +08:00
2017-02-08 22:52:05 +08:00
10. Возможность явно запросить обновление существующей записи, без
2017-05-24 06:42:10 +08:00
создания новой посредством флажка `MDBX_CURRENT` для `mdbx_put()` .
2017-01-09 02:48:00 +08:00
2017-02-08 22:52:05 +08:00
11. Возможность обновить или удалить запись с получением предыдущего
значения данных посредством `mdbx_replace()` .
2017-01-09 02:48:00 +08:00
2017-02-08 22:52:05 +08:00
12. Поддержка ключей и значений нулевой длины. Включая сортированные
дубликаты, в том числе вне зависимости от порядка их добавления или
обновления.
2017-01-09 02:48:00 +08:00
2017-02-08 22:52:05 +08:00
13. Исправленный вариант `mdbx_cursor_count()` , возвращающий корректное
количество дубликатов для всех типов таблиц и любого положения курсора.
2017-01-09 02:48:00 +08:00
2017-01-09 06:19:24 +08:00
14. Возможность открыть БД в эксклюзивном режиме посредством
`mdbx_env_open_ex()` , например в целях её проверки.
2017-01-09 02:48:00 +08:00
2017-02-08 22:52:05 +08:00
15. Возможность закрыть БД в "грязном" состоянии (без с б р о с а данных и
формирования сильной точки фиксации) посредством `mdbx_env_close_ex()` .
16. Возможность получить посредством `mdbx_env_info()` дополнительную
информацию, включая номер самой старой версии БД (снимка данных),
который используется одним из читателей.
17. Функция `mdbx_del()` не игнорирует дополнительный (уточняющий)
2017-05-24 06:42:10 +08:00
аргумент `data` для таблиц без дубликатов (без флажка `MDBX_DUPSORT` ), а
2017-02-08 22:52:05 +08:00
при е г о ненулевом значении всегда использует е г о для сверки с удаляемой
записью.
18. Возможность открыть dbi-таблицу, одновременно с установкой
компараторов для ключей и данных, посредством `mdbx_dbi_open_ex()` .
19. Возможность посредством `mdbx_is_dirty()` определить находятся ли
некоторый ключ или данные в "грязной" странице БД. Таким образом избегаю
лишнего копирования данных перед выполнением модифицирующих операций
(значения в размещенные "грязных" страницах могут быть перезаписаны при
изменениях, иначе они будут неизменны).
20. Корректное обновление текущей записи, в том числе сортированного
2017-05-24 06:42:10 +08:00
дубликата, при использовании режима `MDBX_CURRENT` в `mdbx_cursor_put()` .
2017-02-08 22:52:05 +08:00
21. В с е курсоры, как в транзакциях только для чтения, так и в пишущих,
могут быть переиспользованы посредством `mdbx_cursor_renew()` и ДОЛЖНЫ
ОСВОБОЖДАТЬСЯ ЯВНО.
>
> ## _В А ЖН О _, Обратите внимание!
>
> Это единственное изменение в API, которое значимо меняет
> семантику управления курсорами и может приводить к утечкам
> памяти. Следует отметить, что это изменение вынужденно.
> Так устраняется неоднозначность с массой тяжких последствий:
>
> - обращение к уже освобожденной памяти;
> - попытки повторного освобождения памяти;
> - memory corruption and segfaults.
22. Дополнительный код ошибки `MDBX_EMULTIVAL` , который возвращается из
`mdbx_put()` и `mdbx_replace()` при попытке выполнять неоднозначное
обновление или удаления одного из нескольких значений с одним ключом,
т.е . когда невозможно однозначно идентифицировать одно целевое значение
из нескольких.
23. Возможность посредством `mdbx_get_ex()` получить значение по
заданному ключу, одновременно с количеством дубликатов.
2017-02-18 03:02:07 +08:00
24. Наличие функций mdbx_cursor_on_first() и mdbx_cursor_on_last(),
которые позволяют быстро выяснить стоит ли курсор на первой/последней
позиции.
25. При завершении читающих транзакций, открытые в них DBI-хендлы не
закрываются и не теряются при завершении таких транзакций посредством
2017-02-22 01:16:54 +08:00
mdbx_txn_abort() или mdbx_txn_reset(). Что позволяет избавится от ряда
2017-02-18 03:02:07 +08:00
сложно обнаруживаемых ошибок.
2017-07-04 17:07:05 +08:00
26. Генерация последовательностей посредством `mdbx_dbi_sequence()` .
27. Обновление данных с одновременным получением старых значений,
а также адресное изменение конкретного multi-значения посредством `mdbx_replace()` .
28. Расширенное динамическое управление размером БД, включая выбор размера страницы
посредством `mdbx_env_set_geometry()` .
29. Три мета-страницы вместо двух, что позволяет гарантированно консистентно
обновлять слабые контрольные точки фиксации без риска повредить крайнюю сильную
точку фиксации.