From 109be210b413af2c440bf38c165221d366a67773 Mon Sep 17 00:00:00 2001 From: Leo Yuriev Date: Fri, 21 Jul 2017 01:59:05 +0300 Subject: [PATCH] mdbx: refine README. Change-Id: I91192a5ac1464677432956a0dfd7038bac9b021f --- .gitignore | 1 + README.md | 313 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 183 insertions(+), 131 deletions(-) diff --git a/.gitignore b/.gitignore index 0222b199..117141cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *[~#] *.[ao] *.bak +.le.ini core core.* *.exe diff --git a/README.md b/README.md index c7cf6431..7201448d 100644 --- a/README.md +++ b/README.md @@ -14,21 +14,29 @@ and [by Yandex](https://translate.yandex.ru/translate?url=https%3A%2F%2Fgithub.c ## Кратко _libmdbx_ - это встраиваемый key-value движок хранения со специфическим -набором возможностей, которые при правильном применении позволяют -создавать уникальные решения с чемпионской производительностью, идеально -сочетаясь с технологией -[MRAM](https://en.wikipedia.org/wiki/Magnetoresistive_random-access_memory). +набором свойств и возможностей, ориентированный на создание уникальных +легковесных решений с предельной производительностью. + +_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_ умеет обновлять совместно используемый набор данных, никак не -мешая при этом параллельным операциям чтения, не применяя атомарных -операций к самим данным, и обеспечивая согласованность при аварийной -остановке в любой момент. Поэтому _libmdbx_ позволяя строить системы с -линейным масштабированием производительности чтения/поиска по ядрам CPU -и амортизационной стоимостью любых операций Olog(N). ### История -_libmdbx_ является потомком "Lightning Memory-Mapped Database", +_libmdbx_ является развитием "Lightning Memory-Mapped Database", известной под аббревиатурой [LMDB](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database). Изначально доработка производилась в составе проекта @@ -50,13 +58,13 @@ Technologies](https://www.ptsecurity.ru). _libmdbx_ наследует все ключевые возможности и особенности от своего прародителя [LMDB](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database), -с устранением описанных далее проблем и архитектурных недочетов. +но с устранением ряда описываемых далее проблем и архитектурных недочетов. 1. Данные хранятся в упорядоченном отображении (ordered map), ключи всегда отсортированы, поддерживается выборка диапазонов (range lookups). 2. Данные отображается в память каждого работающего с БД процесса. - К данным и ключам обеспечивается прямой доступ без необходимости их + К данным и ключам обеспечивается прямой доступ в памяти без необходимости их копирования. 3. Транзакции согласно @@ -71,6 +79,10 @@ _libmdbx_ наследует все ключевые возможности и без [атомарных операций](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. Эффективное хранение дубликатов (ключей с несколькими значениями), без дублирования ключей, с сортировкой значений, в @@ -79,7 +91,8 @@ _libmdbx_ наследует все ключевые возможности и 6. Эффективная поддержка коротких ключей фиксированной длины, в том числе целочисленных. 7. Амортизационная стоимость любой операции Olog(N), - [WAF](https://en.wikipedia.org/wiki/Write_amplification) (Write Amplification Factor) и RAF (Read Amplification Factor) также 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) и журнала транзакций, после сбоев не требуется восстановление. Не требуется компактификация @@ -92,9 +105,9 @@ _libmdbx_ наследует все ключевые возможности и Сравнение производительности ============================ -Все данные получены многократным прогоном тестов на ноутбуке Lenovo -Carbon-2, i7-4600U 2.1 ГГц, 8 Гб ОЗУ, с SSD-диском SAMSUNG -MZNTD512HAGL-000L1 (DXT23L0Q) 512 Гб. +Все представленные ниже данные получены многократным прогоном тестов на +ноутбуке Lenovo Carbon-2, i7-4600U 2.1 ГГц, 8 Гб ОЗУ, с SSD-диском +SAMSUNG MZNTD512HAGL-000L1 (DXT23L0Q) 512 Гб. Исходный код бенчмарка [_IOArena_](https://github.com/pmwkaa/ioarena) и сценарии тестирования [доступны на @@ -105,7 +118,7 @@ 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-мя процессорами; @@ -121,7 +134,7 @@ github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015). *Бенчмарк в режиме асинхронной записи не включен по двум причинам:* 1. Такое сравнение не совсем правомочно, его следует делать с движками - ориентированными на хранение данных в памяти (Tarantool, Redis). + ориентированными на хранение данных в памяти ([Tarantool](https://tarantool.io/), [Redis](https://redis.io/)). 2. Превосходство libmdbx становится еще более подавляющем, что мешает восприятию информации. @@ -133,7 +146,7 @@ github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015). Для каждого движка показана суммарная производительность при одновременном выполнении запросов чтения/поиска в 1-2-4-8 потоков на -машине с 4-мя процессорами. +машине с 4-мя физическими процессорами. -------------------------------------------------------------------------------- @@ -141,12 +154,12 @@ github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015). ![Comparison #3: Sync-write mode](https://raw.githubusercontent.com/wiki/ReOpen/libmdbx/img/perf-slide-3.png) - Линейная шкала слева и темные прямоугольники соответствуют количеству - транзакций в секунду, усредненному за все время теста. + транзакций в секунду, усредненному за всё время теста. - Логарифмическая шкала справа и желтые интервальные отрезки соответствуют времени выполнения транзакций. При этом каждый отрезок - показывает минимальное и максимальное время затраченной на выполнения - транзакций, а крестик показывает среднеквадратичное значение. + показывает минимальное и максимальное время затраченное на выполнение + транзакций, а крестиком отмечено среднеквадратичное значение. Выполняется **10.000 транзакций в режиме синхронной фиксации данных** на диске. При этом требуется гарантия, что при аварийном выключении питания @@ -155,23 +168,40 @@ github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015). режиме при фиксации каждой транзакции выполняется системный вызов [fdatasync](https://linux.die.net/man/2/fdatasync). -В каждой транзакции выполняется CRUD-операция (две вставки, одной -чтение, одно обновление, одно удаление). Бенчмарк стартует на пустой -базе и в результате выполняемых действий при завершении в базе -насчитывается 10.000 небольших key-value записей. +В каждой транзакции выполняется комбинированная CRUD-операция (две +вставки, одно чтение, одно обновление, одно удаление). Бенчмарк стартует +на пустой базе, а при завершении, в результате выполняемых действий, в +базе насчитывается 10.000 небольших key-value записей. -------------------------------------------------------------------------------- ### Отложенная фиксация ![Comparison #4: Lazy-write mode](https://raw.githubusercontent.com/wiki/ReOpen/libmdbx/img/perf-slide-4.png) - - Линейная шкала слева и темные прямоугольники соответствуют количеству транзакций в секунду, усредненному за все время теста. - - Логарифмическая шкала справа и желтые интервальные отрезки соответствуют времени выполнения транзакций. При этом каждый отрезок показывает минимальное и максимальное время затраченной на выполнения транзакций, а крестик показывает среднеквадратичное значение. + - Линейная шкала слева и темные прямоугольники соответствуют количеству + транзакций в секунду, усредненному за всё время теста. -Выполняется **100.000 транзакций в режиме отложенной фиксации данных** на диске. При этом требуется гарантия, что при аварийном выключении питания (или другом подобном сбое) все данные будут консистентны на момент завершения одной из транзакций, но допускается потеря изменений из некоторого количества последних транзакций, что для многих движков предполагает включение [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) (write-ahead logging) либо журнала транзакций, который в свою очередь опирается на гарантию упорядоченности данных в журналируемой файловой системе. _libmdbx_ при этом не ведет WAL, а передает весь контроль файловой системе и ядру ОС. + - Логарифмическая шкала справа и желтые интервальные отрезки + соответствуют времени выполнения транзакций. При этом каждый отрезок + показывает минимальное и максимальное время затраченное на выполнение + транзакций, а крестиком отмечено среднеквадратичное значение. -В каждой транзакции выполняется CRUD-операция (две вставки, одной чтение, одно обновление, одно удаление). -Бенчмарк стартует на пустой базе и в результате выполняемых действий при завершении в базе насчитывается 100.000 небольших key-value записей. +Выполняется **100.000 транзакций в режиме отложенной фиксации данных** +на диске. При этом требуется гарантия, что при аварийном выключении +питания (или другом подобном сбое) все данные будут консистентны на +момент завершения одной из транзакций, но допускается потеря изменений +из некоторого количества последних транзакций, что для многих движков +предполагает включение +[WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) (write-ahead +logging) либо журнала транзакций, который в свою очередь опирается на +гарантию упорядоченности данных в журналируемой файловой системе. +_libmdbx_ при этом не ведет WAL, а передает весь контроль файловой +системе и ядру ОС. + +В каждой транзакции выполняется комбинированная CRUD-операция (две +вставки, одно чтение, одно обновление, одно удаление). Бенчмарк стартует +на пустой базе, а при завершении, в результате выполняемых действий, в +базе насчитывается 100.000 небольших key-value записей. -------------------------------------------------------------------------------- @@ -179,28 +209,28 @@ github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015). ![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). +потеря изменений из значительного количества последних транзакций. Во +всех движках при этом включался режим предполагающий минимальную +нагрузку на диск по-записи, и соответственно минимальную гарантию +сохранности данных. В _libmdbx_ при этом используется режим асинхронной +записи измененных страниц на диск посредством ядра ОС и системного +вызова [msync(MS_ASYNC)](https://linux.die.net/man/2/msync). -В каждой транзакции выполняется CRUD-операция (две вставки, одной -чтение, одно обновление, одно удаление). Бенчмарк стартует на пустой -базе и в результате выполняемых действий при завершении в базе -насчитывается 1.000.000 небольших key-value записей. +В каждой транзакции выполняется комбинированная CRUD-операция (две +вставки, одно чтение, одно обновление, одно удаление). Бенчмарк стартует +на пустой базе, а при завершении, в результате выполняемых действий, в +базе насчитывается 10.000 небольших key-value записей. -------------------------------------------------------------------------------- @@ -213,19 +243,19 @@ github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015). - суммарное количество операций ввода-вывода (IOPS), как записи, так и чтения. - - суммарное затраченное время процессора, как в режиме пользователя, + - суммарное затраченное время процессора, как в режиме пользовательских процессов, так и в режиме ядра ОС. - - максимальный объем места на диске. который требовался во время работы - теста. + - использованное место на диске при завершении теста, после закрытия БД из тестирующего процесса, + но без ожидания всех внутренних операций обслуживания (компактификации LSM и т.п.). -Движок _ForestDB_ был исключен при окончательном формировании диаграммы, -так как многократно превысил потребление каждого из ресурсов (потратил -процессорное время на генерацию IOPS для заполнения диска). Что не -позволяло наглядно сравнить показатели остальных движков на одной -диаграмме. +Движок _ForestDB_ был исключен при оформлении результатов, так как +относительно конкурентов многократно превысил потребление каждого из +ресурсов (потратил процессорное время на генерацию IOPS для заполнения +диска), что не позволяло наглядно сравнить показатели остальных движков +на одной диаграмме. -Все данные собирались посредством системного вывова +Все данные собирались посредством системного вызова [getrusage()](http://man7.org/linux/man-pages/man2/getrusage.2.html) и сканированием директорий с данными. @@ -235,17 +265,27 @@ github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015). 1. Единовременно может выполняться не более одной транзакция изменения данных (один писатель). Зато все изменения всегда последовательны, не может быть - конфликтов или ошибок при откате транзакций. + конфликтов или логических ошибок при откате транзакций. 2. Отсутствие [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) обуславливает относительно большой [WAF](https://en.wikipedia.org/wiki/Write_amplification) (Write Amplification Factor). Поэтому фиксация изменений на диске может быть - дорогой и является главным ограничителем для производительности по - записи. В качестве компромисса предлагается несколько режимов ленивой - и/или периодической фиксации. В том числе режим `MAPASYNC`, при котором - изменения происходят только в памяти и асинхронно фиксируются на диске - ядром ОС. + достаточно дорогой и являться главным ограничением производительности + при интенсивном изменении данных. + > В качестве компромисса _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) выполняется на @@ -255,16 +295,26 @@ github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015). страниц, что расходует [пропускную способность оперативной памяти](https://en.wikipedia.org/wiki/Memory_bandwidth) и является основным ограничителем производительности в режиме `MAPASYNC`. + > Этот недостаток неустраним, тем не менее следует дать некоторые пояснения. + > Дело в том, что фиксация изменений на диске потребует гораздо более + > значительного копирования данных в памяти и массы других затратных операций. + > Поэтому обусловленное этим недостатком падение производительности становится + > заметным только при отказе от фиксации изменений на диске. + > Соответственно, корректнее сказать что _libmdbx_ позволяет + > получить персистентность ценой минимального падения производительности. + > Если же нет необходимости оперативно сохранять данные, то логичнее + > использовать `std::map`. 4. В _LMDB_ существует проблема долгих чтений (приостановленных читателей), которая приводит к деградации производительности и переполнению БД. - В _libmdbx_ предложены средства для предотвращения, выхода из проблемной - ситуации и устранения её последствий. Подробности ниже. + > В _libmdbx_ предложены средства для предотвращения, быстрого выхода из + > некомфортной ситуации и устранения её последствий. Подробности ниже. 5. В _LMDB_ есть вероятность разрушения БД в режиме `WRITEMAP+MAPASYNC`. В _libmdbx_ для `WRITEMAP+MAPASYNC` гарантируется как сохранность базы, - так и согласованность данных. При этом также, в качестве альтернативы, - предложен режим `UTTERLY_NOSYNC`. Подробности ниже. + так и согласованность данных. + > Дополнительно, в качестве альтернативы, предложен режим `UTTERLY_NOSYNC`. + > Подробности ниже. #### Проблема долгих чтений @@ -299,60 +349,55 @@ github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015). деградацию производительности. Операции чтения выполняются в контексте снимка данных (версии -БД), который был актуальным на момент старта транзакции чтения. -Такой читаемый снимок поддерживается неизменным до завершения -операции. В свою очередь, это не позволяет повторно -использовать страницы БД в последующих версиях (снимках БД). +БД), который был актуальным на момент старта транзакции чтения. Такой +читаемый снимок поддерживается неизменным до завершения операции. В свою +очередь, это не позволяет повторно использовать страницы БД в +последующих версиях (снимках БД). -Другими словами, если обновление данных выполняется на фоне -долгой операции чтения, то вместо повторного использования -"старых" ненужных страниц будут выделяться новые, так как -"старые" страницы составляют снимок БД, который еще -используется долгой операцией чтения. +Другими словами, если обновление данных выполняется на фоне долгой +операции чтения, то вместо повторного использования "старых" ненужных +страниц будут выделяться новые, так как "старые" страницы составляют +снимок БД, который еще используется долгой операцией чтения. -В результате, при интенсивном изменении данных и достаточно -длительной операции чтения, в БД могут быть исчерпаны свободные -страницы, что не позволит создавать новые снимки/версии БД. -Такая ситуация будет сохраняться до завершения операции чтения, -которая использует старый снимок данных и препятствует -повторному использованию страниц БД. +В результате, при интенсивном изменении данных и достаточно длительной +операции чтения, в БД могут быть исчерпаны свободные страницы, что не +позволит создавать новые снимки/версии БД. Такая ситуация будет +сохраняться до завершения операции чтения, которая использует старый +снимок данных и препятствует повторному использованию страниц БД. -Однако, на этом проблемы не заканчиваются. После описанной -ситуации, все дополнительные страницы, которые были выделены -пока переработка старых была невозможна, будут участвовать в -цикле выделения/освобождения до конца жизни экземпляра БД. В -оригинальной _LMDB_ этот цикл использования страниц работает по -принципу [FIFO](https://ru.wikipedia.org/wiki/FIFO). Поэтому -увеличение количества циркулирующий страниц, с точки зрения -механизмов кэширования и/или обратной записи, выглядит как -увеличение рабочего набор данных. Проще говоря, однократное -попадание в ситуацию "уснувшего читателя" приводит к -устойчивому эффекту вымывания I/O кэша при всех последующих -изменениях данных. +Однако, на этом проблемы не заканчиваются. После описанной ситуации, все +дополнительные страницы, которые были выделены пока переработка старых +была невозможна, будут участвовать в цикле выделения/освобождения до +конца жизни экземпляра БД. В оригинальной _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_. +Для устранения описанных проблемы в _libmdbx_ сделаны существенные +доработки, подробности ниже. Иллюстрации к проблеме "долгих чтений" +можно найти в [слайдах презентации](http://www.slideshare.net/leoyuriev/lmdb). + +Там же приведен пример количественной оценки прироста производительности +за счет эффективной работы [BBWC](https://en.wikipedia.org/wiki/BBWC) +при включении `LIFO RECLAIM` в _libmdbx_. #### Вероятность разрушения БД в режиме `WRITEMAP+MAPASYNC` -При работе в режиме `WRITEMAP+MAPSYNC` запись измененных -страниц выполняется ядром ОС, что имеет ряд преимуществ. Так -например, при крахе приложения, ядро ОС сохранит все изменения. +При работе в режиме `WRITEMAP+MAPSYNC` запись измененных страниц +выполняется ядром ОС, что имеет ряд преимуществ. Так например, при крахе +приложения, ядро ОС сохранит все изменения. -Однако, при аварийном отключении питания или сбое в ядре ОС, на -диске будет сохранена только часть измененных страниц БД. При -этом с большой вероятностью может оказаться так, что будут -сохранены мета-страницы со ссылками на страницы с новыми -версиями данных, но не сами новые данные. В этом случае БД -будет безвозвратна разрушена, даже если до аварии производилась -полная синхронизация данных (посредством `mdbx_env_sync()`). +Однако, при аварийном отключении питания или сбое в ядре ОС, на диске +будет сохранена только часть измененных страниц БД. При этом с большой +вероятностью может оказаться так, что будут сохранены мета-страницы со +ссылками на страницы с новыми версиями данных, но не сами новые данные. +В этом случае БД будет безвозвратна разрушена, даже если до аварии +производилась полная синхронизация данных (посредством +`mdbx_env_sync()`). В _libmdbx_ эта проблема устранена, подробности ниже. @@ -380,11 +425,11 @@ RECLAIM` в _libmdbx_. Посредством `mdbx_env_set_oomfunc()` может быть установлен внешний обработчик (callback), который будет вызван при исчерпания свободных страниц из-за долгой операцией чтения. - Обработчику будет передан PID и pthread_id. В свою очередь - обработчик может предпринять одно из действий: + Обработчику будет передан PID и pthread_id виновника. + В свою очередь обработчик может предпринять одно из действий: - * отправить сигнал kill (#9), если долгое чтение выполняется - сторонним процессом; + * нейтрализовать виновника (отправить сигнал kill #9), если + долгое чтение выполняется сторонним процессом; * отменить или перезапустить проблемную операцию чтения, если операция выполняется одним из потоков текущего процесса; @@ -423,6 +468,14 @@ RECLAIM` в _libmdbx_. `WRITEMAP+MAPSYNC` завершаемые транзакции помечаются как слабые, а при явной синхронизации данных как сильные. + * В _libmdbx_ поддерживается не две, а три отдельные мета-страницы. + Это позволяет выполнять фиксацию транзакций с формированием как + сильной, так и слабой точки фиксации, без потери двух предыдущих + точек фиксации (из которых одна может быть сильной, а вторая слабой). + В результате, _libmdbx_ позволяет в произвольном порядке чередовать + сильные и слабые точки фиксации без нарушения соответствующих + гарантий в случае неожиданной системной аварии во время фиксации. + * При открытии БД выполняется автоматический откат к последней сильной фиксации. Этим обеспечивается гарантия сохранности БД. @@ -463,12 +516,12 @@ RECLAIM` в _libmdbx_. 10. Возможность явно запросить обновление существующей записи, без создания новой посредством флажка `MDBX_CURRENT` для `mdbx_put()`. -11. Возможность обновить или удалить запись с получением предыдущего -значения данных посредством `mdbx_replace()`. +11. Возможность посредством `mdbx_replace()` обновить или удалить запись +с получением предыдущего значения данных, а также адресно изменить +конкретное multi-значение. -12. Поддержка ключей и значений нулевой длины. Включая сортированные -дубликаты, в том числе вне зависимости от порядка их добавления или -обновления. +12. Поддержка ключей и значений нулевой длины, включая сортированные +дубликаты. 13. Исправленный вариант `mdbx_cursor_count()`, возвращающий корректное количество дубликатов для всех типов таблиц и любого положения курсора. @@ -492,13 +545,14 @@ RECLAIM` в _libmdbx_. компараторов для ключей и данных, посредством `mdbx_dbi_open_ex()`. 19. Возможность посредством `mdbx_is_dirty()` определить находятся ли -некоторый ключ или данные в "грязной" странице БД. Таким образом избегаю -лишнего копирования данных перед выполнением модифицирующих операций -(значения в размещенные "грязных" страницах могут быть перезаписаны при -изменениях, иначе они будут неизменны). +некоторый ключ или данные в "грязной" странице БД. Таким образом, +избегая лишнего копирования данных перед выполнением модифицирующих +операций (значения в размещенные "грязных" страницах могут быть +перезаписаны при изменениях, иначе они будут неизменны). 20. Корректное обновление текущей записи, в том числе сортированного -дубликата, при использовании режима `MDBX_CURRENT` в `mdbx_cursor_put()`. +дубликата, при использовании режима `MDBX_CURRENT` в +`mdbx_cursor_put()`. 21. Все курсоры, как в транзакциях только для чтения, так и в пишущих, могут быть переиспользованы посредством `mdbx_cursor_renew()` и ДОЛЖНЫ @@ -535,12 +589,9 @@ mdbx_txn_abort() или mdbx_txn_reset(). Что позволяет избави 26. Генерация последовательностей посредством `mdbx_dbi_sequence()`. -27. Обновление данных с одновременным получением старых значений, -а также адресное изменение конкретного multi-значения посредством `mdbx_replace()`. +27. Расширенное динамическое управление размером БД, включая выбор +размера страницы посредством `mdbx_env_set_geometry()`. -28. Расширенное динамическое управление размером БД, включая выбор размера страницы -посредством `mdbx_env_set_geometry()`. - -29. Три мета-страницы вместо двух, что позволяет гарантированно консистентно -обновлять слабые контрольные точки фиксации без риска повредить крайнюю сильную -точку фиксации. +28. Три мета-страницы вместо двух, что позволяет гарантированно +консистентно обновлять слабые контрольные точки фиксации без риска +повредить крайнюю сильную точку фиксации.