mirror of
https://github.com/isar/libmdbx.git
synced 2025-12-15 04:32:21 +08:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1e17fd6a4 | ||
|
|
b6e605b8da | ||
|
|
2f983b281d | ||
|
|
efdcbd8c35 | ||
|
|
634efbe34b | ||
|
|
17d3e7190c | ||
|
|
fdc248384e | ||
|
|
38369bd24b | ||
|
|
22d8b0b2e1 | ||
|
|
515adb674b | ||
|
|
f99df1ca35 | ||
|
|
ab4c9c9db0 | ||
|
|
b68ed8600c | ||
|
|
9384d0efa6 | ||
|
|
4214436d4b | ||
|
|
ffafd5be10 | ||
|
|
e86bd88751 | ||
|
|
eb4090c534 | ||
|
|
bea1349dd4 | ||
|
|
d0ddc8569b | ||
|
|
f1edd1579a | ||
|
|
47cc2b1c10 | ||
|
|
d127c28e83 | ||
|
|
159d676429 | ||
|
|
f4a9018690 | ||
|
|
f8eb423d36 | ||
|
|
797ae9d1db | ||
|
|
f08c7ccac0 | ||
|
|
864be54f01 | ||
|
|
571b50622e | ||
|
|
36a86bbc6e | ||
|
|
ae708aab13 | ||
|
|
02fc5fe158 | ||
|
|
45f159ddd3 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -16,6 +16,7 @@ Win32/
|
||||
build-*
|
||||
cmake-build-*
|
||||
core
|
||||
example
|
||||
libmdbx.creator.user
|
||||
mdbx-dll.VC.VC.opendb
|
||||
mdbx-dll.VC.db
|
||||
@@ -25,7 +26,7 @@ mdbx_copy
|
||||
mdbx_dump
|
||||
mdbx_load
|
||||
mdbx_stat
|
||||
ootest/test
|
||||
mdbx_test
|
||||
test.log
|
||||
test/test.vcxproj.user
|
||||
test/tmp.db
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
cmake_minimum_required(VERSION 2.8.7)
|
||||
|
||||
set(TARGET mdbx)
|
||||
project(${TARGET})
|
||||
|
||||
# FIXME/TODO: Same as https://github.com/leo-yuriev/libfpta
|
||||
set(MDBX_VERSION_MAJOR 0)
|
||||
set(MDBX_VERSION_MINOR 0)
|
||||
set(MDBX_VERSION_PATCH 0)
|
||||
set(MDBX_VERSION_STRING ${MDBX_VERSION_MAJOR}.${MDBX_VERSION_MINOR}.${MDBX_VERSION_PATCH})
|
||||
message(WARNING "
|
||||
***************************************************************
|
||||
MDBX is under active development, database format and API
|
||||
aren't stable at least until 2018Q3. New version won't be
|
||||
backwards compatible. Main focus of the rework is to provide
|
||||
clear and robust API and new features.
|
||||
***************************************************************
|
||||
")
|
||||
|
||||
add_definitions(-DMDBX_VERSION_MAJOR=${MDBX_VERSION_MAJOR})
|
||||
add_definitions(-DMDBX_VERSION_MINOR=${MDBX_VERSION_MINOR})
|
||||
add_definitions(-DMDBX_VERSION_PATCH=${MDBX_VERSION_PATCH})
|
||||
set(MDBX_VERSION_MAJOR 0)
|
||||
set(MDBX_VERSION_MINOR 1)
|
||||
set(MDBX_VERSION_RELEASE 3)
|
||||
set(MDBX_VERSION_REVISION 1)
|
||||
|
||||
set(MDBX_VERSION_STRING ${MDBX_VERSION_MAJOR}.${MDBX_VERSION_MINOR}.${MDBX_VERSION_RELEASE})
|
||||
|
||||
enable_language(C)
|
||||
enable_language(CXX)
|
||||
@@ -34,7 +39,6 @@ else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-constant-logical-operand")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections")
|
||||
|
||||
20
Makefile
20
Makefile
@@ -23,11 +23,7 @@ suffix ?=
|
||||
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
ifeq ($(shell (export LC_ALL=C; ($(CC) --version 2>&1; $(CC) -v 2>&1) | grep -q -i 'e2k' && echo yes)),yes)
|
||||
CFLAGS ?= -O3 -g3 -Wall -Werror -Wextra -ffunction-sections -fPIC -fvisibility=hidden
|
||||
else
|
||||
CFLAGS ?= -O2 -g3 -Wall -Werror -Wextra -ffunction-sections -fPIC -fvisibility=hidden
|
||||
endif
|
||||
|
||||
XCFLAGS ?= -DNDEBUG=1 -DMDBX_DEBUG=0 -DLIBMDBX_EXPORTS=1
|
||||
CFLAGS += -D_GNU_SOURCE=1 -std=gnu11 -pthread $(XCFLAGS)
|
||||
@@ -37,7 +33,7 @@ TESTLOG ?= $(shell [ -d /dev/shm ] && echo /dev/shm || echo /tmp)/mdbx-test.log
|
||||
|
||||
# LY: '--no-as-needed,-lrt' for ability to built with modern glibc, but then run with the old
|
||||
LDFLAGS ?= -Wl,--gc-sections,-z,relro,-O,--no-as-needed,-lrt
|
||||
EXE_LDFLAGS ?= $(LDFLAGS) -static
|
||||
EXE_LDFLAGS ?= -pthread -lrt
|
||||
|
||||
# LY: just for benchmarking
|
||||
IOARENA ?= $(shell \
|
||||
@@ -63,7 +59,7 @@ TEST_OBJ := $(patsubst %.cc,%.o,$(TEST_SRC))
|
||||
|
||||
.PHONY: mdbx all install clean check coverage
|
||||
|
||||
all: $(LIBRARIES) $(TOOLS) test/test example
|
||||
all: $(LIBRARIES) $(TOOLS) mdbx_test example
|
||||
|
||||
mdbx: libmdbx.a libmdbx.so
|
||||
|
||||
@@ -83,16 +79,16 @@ install: $(LIBRARIES) $(TOOLS) $(HEADERS)
|
||||
&& cp -t $(SANDBOX)$(mandir)/man1 $(MANPAGES)
|
||||
|
||||
clean:
|
||||
rm -rf $(TOOLS) test/test @* *.[ao] *.[ls]o *~ tmp.db/* *.gcov *.log *.err src/*.o test/*.o
|
||||
rm -rf $(TOOLS) mdbx_test @* *.[ao] *.[ls]o *~ tmp.db/* *.gcov *.log *.err src/*.o test/*.o
|
||||
|
||||
check: all
|
||||
rm -f $(TESTDB) $(TESTLOG) && (set -o pipefail; test/test --pathname=$(TESTDB) --dont-cleanup-after basic | tee -a $(TESTLOG) | tail -n 42) && ./mdbx_chk -vvn $(TESTDB)
|
||||
rm -f $(TESTDB) $(TESTLOG) && (set -o pipefail; ./mdbx_test --pathname=$(TESTDB) --dont-cleanup-after basic | tee -a $(TESTLOG) | tail -n 42) && ./mdbx_chk -vvn $(TESTDB)
|
||||
|
||||
check-singleprocess: all
|
||||
rm -f $(TESTDB) $(TESTLOG) && (set -o pipefail; test/test --pathname=$(TESTDB) --dont-cleanup-after --hill | tee -a $(TESTLOG) | tail -n 42) && ./mdbx_chk -vvn $(TESTDB)
|
||||
rm -f $(TESTDB) $(TESTLOG) && (set -o pipefail; ./mdbx_test --pathname=$(TESTDB) --dont-cleanup-after --hill | tee -a $(TESTLOG) | tail -n 42) && ./mdbx_chk -vvn $(TESTDB)
|
||||
|
||||
check-fault: all
|
||||
rm -f $(TESTDB) $(TESTLOG) && (set -o pipefail; test/test --pathname=$(TESTDB) --inject-writefault=42 --dump-config --dont-cleanup-after basic | tee -a $(TESTLOG) | tail -n 42) && ./mdbx_chk -vvn $(TESTDB)
|
||||
rm -f $(TESTDB) $(TESTLOG) && (set -o pipefail; ./mdbx_test --pathname=$(TESTDB) --inject-writefault=42 --dump-config --dont-cleanup-after basic | tee -a $(TESTLOG) | tail -n 42) && ./mdbx_chk -vvn $(TESTDB)
|
||||
|
||||
define core-rule
|
||||
$(patsubst %.c,%.o,$(1)): $(1) $(CORE_INC) mdbx.h Makefile
|
||||
@@ -117,8 +113,8 @@ libmdbx.so: $(CORE_OBJ)
|
||||
mdbx_%: src/tools/mdbx_%.c libmdbx.a
|
||||
$(CC) $(CFLAGS) $^ $(EXE_LDFLAGS) -o $@
|
||||
|
||||
test/test: $(TEST_OBJ) libmdbx.a
|
||||
$(CXX) $(CXXFLAGS) $^ $(EXE_LDFLAGS) -o $@
|
||||
mdbx_test: $(TEST_OBJ) libmdbx.so
|
||||
$(CXX) $(CXXFLAGS) $(TEST_OBJ) -Wl,-rpath . -L . -l mdbx $(EXE_LDFLAGS) -o $@
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
75
README-RU.md
75
README-RU.md
@@ -12,19 +12,30 @@ and [by Yandex](https://translate.yandex.ru/translate?url=https%3A%2F%2Fgithub.c
|
||||
|
||||
### Project Status
|
||||
|
||||
**Now MDBX is under _active development_** and until 2018Q2 is expected a big
|
||||
change both of API and database format. Unfortunately those update will lead to
|
||||
loss of compatibility with previous versions.
|
||||
|
||||
The aim of this revolution in providing a clearer robust API and adding new
|
||||
features, including the database properties.
|
||||
**Сейчас MDBX _активно перерабатывается_** и к середине 2018
|
||||
ожидается большое изменение как API, так и формата базы данных.
|
||||
К сожалению, обновление приведет к потере совместимости с
|
||||
предыдущими версиями.
|
||||
|
||||
Цель этой революции - обеспечение более четкого надежного
|
||||
API и добавление новых функции, а также наделение базы данных
|
||||
новыми свойствами.
|
||||
|
||||
В настоящее время MDBX предназначена для Linux, а также
|
||||
поддерживает Windows (начиная с Windows Server 2008) в качестве
|
||||
дополнительной платформы. Поддержка других ОС может быть
|
||||
обеспечена на коммерческой основе. Однако такие
|
||||
усовершенствования (т. е. pull-requests) могут быть приняты в
|
||||
мейнстрим только в том случае, если будет доступен
|
||||
соответствующий публичный и бесплатный сервис непрерывной
|
||||
интеграции (aka Continuous Integration).
|
||||
|
||||
## Содержание
|
||||
|
||||
- [Обзор](#Обзор)
|
||||
- [Сравнение с другими СУБД](#Сравнение-с-другими-СУБД)
|
||||
- [История & Acknowledgements](#История)
|
||||
- [История & Acknowledgments](#История)
|
||||
- [Основные свойства](#Основные-свойства)
|
||||
- [Сравнение производительности](#Сравнение-производительности)
|
||||
- [Интегральная производительность](#Интегральная-производительность)
|
||||
@@ -43,7 +54,7 @@ features, including the database properties.
|
||||
|
||||
_libmdbx_ - это встраиваемый key-value движок хранения со специфическим
|
||||
набором свойств и возможностей, ориентированный на создание уникальных
|
||||
легковесных решений с предельной производительностью.
|
||||
легковесных решений с предельной производительностью под Linux и Windows.
|
||||
|
||||
_libmdbx_ позволяет множеству процессов совместно читать и обновлять
|
||||
несколько key-value таблиц с соблюдением [ACID](https://ru.wikipedia.org/wiki/ACID),
|
||||
@@ -51,8 +62,8 @@ _libmdbx_ позволяет множеству процессов совмес
|
||||
|
||||
_libmdbx_ обеспечивает
|
||||
[serializability](https://en.wikipedia.org/wiki/Serializability)
|
||||
изменений и согласованность данных после аварий. При этом транзакции
|
||||
изменяющие данные никак не мешают операциям чтения и выполняются строго
|
||||
изменений и согласованность данных после аварий. При этом транзакции,
|
||||
изменяющие данные, никак не мешают операциям чтения и выполняются строго
|
||||
последовательно с использованием единственного
|
||||
[мьютекса](https://en.wikipedia.org/wiki/Mutual_exclusion).
|
||||
|
||||
@@ -90,7 +101,7 @@ Tables](https://github.com/leo-yuriev/libfpta), aka ["Позитивные
|
||||
Technologies](https://www.ptsecurity.ru).
|
||||
|
||||
|
||||
#### Acknowledgements
|
||||
#### Acknowledgments
|
||||
|
||||
Howard Chu (Symas Corporation) - the author of LMDB,
|
||||
from which originated the MDBX in 2015.
|
||||
@@ -102,7 +113,7 @@ which was used for begin development of LMDB.
|
||||
Основные свойства
|
||||
=================
|
||||
|
||||
_libmdbx_ наследует все ключевые возможности и особенности от
|
||||
_libmdbx_ наследует все ключевые возможности и особенности
|
||||
своего прародителя [LMDB](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database),
|
||||
но с устранением ряда описываемых далее проблем и архитектурных недочетов.
|
||||
|
||||
@@ -118,7 +129,7 @@ _libmdbx_ наследует все ключевые возможности и
|
||||
[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),
|
||||
@@ -182,7 +193,7 @@ github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015).
|
||||
1. Такое сравнение не совсем правомочно, его следует делать с движками
|
||||
ориентированными на хранение данных в памяти ([Tarantool](https://tarantool.io/), [Redis](https://redis.io/)).
|
||||
|
||||
2. Превосходство libmdbx становится еще более подавляющем, что мешает
|
||||
2. Превосходство libmdbx становится еще более подавляющим, что мешает
|
||||
восприятию информации.
|
||||
|
||||

|
||||
@@ -206,7 +217,7 @@ github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015).
|
||||
|
||||
- Логарифмическая шкала справа и желтые интервальные отрезки
|
||||
соответствуют времени выполнения транзакций. При этом каждый отрезок
|
||||
показывает минимальное и максимальное время затраченное на выполнение
|
||||
показывает минимальное и максимальное время, затраченное на выполнение
|
||||
транзакций, а крестиком отмечено среднеквадратичное значение.
|
||||
|
||||
Выполняется **10.000 транзакций в режиме синхронной фиксации данных** на
|
||||
@@ -232,7 +243,7 @@ github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015).
|
||||
|
||||
- Логарифмическая шкала справа и желтые интервальные отрезки
|
||||
соответствуют времени выполнения транзакций. При этом каждый отрезок
|
||||
показывает минимальное и максимальное время затраченное на выполнение
|
||||
показывает минимальное и максимальное время, затраченное на выполнение
|
||||
транзакций, а крестиком отмечено среднеквадратичное значение.
|
||||
|
||||
Выполняется **100.000 транзакций в режиме отложенной фиксации данных**
|
||||
@@ -263,7 +274,7 @@ _libmdbx_ при этом не ведет WAL, а передает весь ко
|
||||
|
||||
- Логарифмическая шкала справа и желтые интервальные отрезки
|
||||
соответствуют времени выполнения транзакций. При этом каждый отрезок
|
||||
показывает минимальное и максимальное время затраченное на выполнение
|
||||
показывает минимальное и максимальное время, затраченное на выполнение
|
||||
транзакций, а крестиком отмечено среднеквадратичное значение.
|
||||
|
||||
Выполняется **1.000.000 транзакций в режиме асинхронной фиксации
|
||||
@@ -272,7 +283,7 @@ _libmdbx_ при этом не ведет WAL, а передает весь ко
|
||||
консистентны на момент завершения одной из транзакций, но допускается
|
||||
потеря изменений из значительного количества последних транзакций. Во
|
||||
всех движках при этом включался режим предполагающий минимальную
|
||||
нагрузку на диск по-записи, и соответственно минимальную гарантию
|
||||
нагрузку на диск по записи, и соответственно минимальную гарантию
|
||||
сохранности данных. В _libmdbx_ при этом используется режим асинхронной
|
||||
записи измененных страниц на диск посредством ядра ОС и системного
|
||||
вызова [msync(MS_ASYNC)](https://linux.die.net/man/2/msync).
|
||||
@@ -337,7 +348,7 @@ _libmdbx_ при этом не ведет WAL, а передает весь ко
|
||||
> _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)
|
||||
@@ -353,7 +364,7 @@ _libmdbx_ при этом не ведет WAL, а передает весь ко
|
||||
> значительного копирования данных в памяти и массы других затратных операций.
|
||||
> Поэтому обусловленное этим недостатком падение производительности становится
|
||||
> заметным только при отказе от фиксации изменений на диске.
|
||||
> Соответственно, корректнее сказать что _libmdbx_ позволяет
|
||||
> Соответственно, корректнее сказать, что _libmdbx_ позволяет
|
||||
> получить персистентность ценой минимального падения производительности.
|
||||
> Если же нет необходимости оперативно сохранять данные, то логичнее
|
||||
> использовать `std::map`.
|
||||
@@ -446,7 +457,7 @@ _libmdbx_ при этом не ведет WAL, а передает весь ко
|
||||
|
||||
Однако, при аварийном отключении питания или сбое в ядре ОС, на диске
|
||||
может быть сохранена только часть измененных страниц БД. При этом с большой
|
||||
вероятностью может оказаться так, что будут сохранены мета-страницы со
|
||||
вероятностью может оказаться, что будут сохранены мета-страницы со
|
||||
ссылками на страницы с новыми версиями данных, но не сами новые данные.
|
||||
В этом случае БД будет безвозвратна разрушена, даже если до аварии
|
||||
производилась полная синхронизация данных (посредством
|
||||
@@ -460,11 +471,11 @@ _libmdbx_ при этом не ведет WAL, а передает весь ко
|
||||
с переносом изменений после фиксации данных.
|
||||
|
||||
* При завершении транзакций, в зависимости от состояния
|
||||
синхронности данных между диском и оперативной память,
|
||||
синхронности данных между диском и оперативной памятью,
|
||||
_libmdbx_ помечает точки фиксации либо как сильные (strong),
|
||||
либо как слабые (weak). Так например, в режиме
|
||||
`WRITEMAP+MAPSYNC` завершаемые транзакции помечаются как
|
||||
слабые, а при явной синхронизации данных как сильные.
|
||||
слабые, а при явной синхронизации данных - как сильные.
|
||||
|
||||
* В _libmdbx_ поддерживается не две, а три отдельные мета-страницы.
|
||||
Это позволяет выполнять фиксацию транзакций с формированием как
|
||||
@@ -478,20 +489,20 @@ _libmdbx_ при этом не ведет WAL, а передает весь ко
|
||||
сильной фиксации. Этим обеспечивается гарантия сохранности БД.
|
||||
|
||||
Такая гарантия надежности не дается бесплатно. Для
|
||||
сохранности данных, страницы формирующие крайний снимок с
|
||||
сохранности данных, страницы, формирующие крайний снимок с
|
||||
сильной фиксацией, не должны повторно использоваться
|
||||
(перезаписываться) до формирования следующей сильной точки
|
||||
фиксации. Таким образом, крайняя точка фиксации создает
|
||||
описанный выше эффект "долгого чтения". Разница же здесь в том,
|
||||
что при исчерпании свободных страниц ситуация будет
|
||||
автоматически исправлена, посредством записи изменений на диск
|
||||
и формированием новой сильной точки фиксации.
|
||||
и формирования новой сильной точки фиксации.
|
||||
|
||||
Таким образом, в режиме безопасной асинхронной фиксации _libmdbx_ будет
|
||||
всегда использовать новые страницы до исчерпания места в БД или до явного
|
||||
формирования сильной точки фиксации посредством `mdbx_env_sync()`.
|
||||
При этом суммарный трафик записи на диск будет примерно такой-же,
|
||||
как если бы отдельно фиксировалась каждая транзакций.
|
||||
При этом суммарный трафик записи на диск будет примерно такой же,
|
||||
как если бы отдельно фиксировалась каждая транзакция.
|
||||
|
||||
В текущей версии _libmdbx_ вам предоставляется выбор между безопасным
|
||||
режимом (по умолчанию) асинхронной фиксации, и режимом `UTTERLY_NOSYNC` когда
|
||||
@@ -524,9 +535,9 @@ _libmdbx_ при этом не ведет WAL, а передает весь ко
|
||||
|
||||
Посредством `mdbx_env_set_oomfunc()` может быть установлен
|
||||
внешний обработчик (callback), который будет вызван при
|
||||
исчерпания свободных страниц из-за долгой операцией чтения.
|
||||
исчерпании свободных страниц из-за долгой операцией чтения.
|
||||
Обработчику будет передан PID и pthread_id виновника.
|
||||
В свою очередь обработчик может предпринять одно из действий:
|
||||
В свою очередь обработчик может предпринять одно из действий:
|
||||
|
||||
* нейтрализовать виновника (отправить сигнал kill #9), если
|
||||
долгое чтение выполняется сторонним процессом;
|
||||
@@ -534,7 +545,7 @@ _libmdbx_ при этом не ведет WAL, а передает весь ко
|
||||
* отменить или перезапустить проблемную операцию чтения, если
|
||||
операция выполняется одним из потоков текущего процесса;
|
||||
|
||||
* подождать некоторое время, в расчете что проблемная операция
|
||||
* подождать некоторое время, в расчете на то, что проблемная операция
|
||||
чтения будет штатно завершена;
|
||||
|
||||
* прервать текущую операцию изменения данных с возвратом кода
|
||||
@@ -601,7 +612,7 @@ _libmdbx_ при этом не ведет WAL, а передает весь ко
|
||||
19. Возможность посредством `mdbx_is_dirty()` определить находятся ли
|
||||
некоторый ключ или данные в "грязной" странице БД. Таким образом,
|
||||
избегая лишнего копирования данных перед выполнением модифицирующих
|
||||
операций (значения в размещенные "грязных" страницах могут быть
|
||||
операций (значения, размещенные в "грязных" страницах, могут быть
|
||||
перезаписаны при изменениях, иначе они будут неизменны).
|
||||
|
||||
20. Корректное обновление текущей записи, в том числе сортированного
|
||||
@@ -621,7 +632,7 @@ _libmdbx_ при этом не ведет WAL, а передает весь ко
|
||||
>
|
||||
> - обращение к уже освобожденной памяти;
|
||||
> - попытки повторного освобождения памяти;
|
||||
> - memory corruption and segfaults.
|
||||
> - повреждение памяти и ошибки сегментации.
|
||||
|
||||
22. Дополнительный код ошибки `MDBX_EMULTIVAL`, который возвращается из
|
||||
`mdbx_put()` и `mdbx_replace()` при попытке выполнить неоднозначное
|
||||
@@ -655,7 +666,7 @@ _libmdbx_ при этом не ведет WAL, а передает весь ко
|
||||
цикле обновления данных и записи на диск. Фактически _libmdbx_ выполняет
|
||||
постоянную компактификацию данных, но не затрачивая на это
|
||||
дополнительных ресурсов, а только освобождая их. При освобождении места
|
||||
в БД и установки соответствующих параметров геометрии базы данных, также будет
|
||||
в БД и установке соответствующих параметров геометрии базы данных, также будет
|
||||
уменьшаться размер файла на диске, в том числе в **Windows**.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
52
README.md
52
README.md
@@ -7,17 +7,33 @@ libmdbx
|
||||
[](https://ci.appveyor.com/project/leo-yuriev/libmdbx/branch/master)
|
||||
[](https://scan.coverity.com/projects/reopen-libmdbx)
|
||||
|
||||
### Project Status
|
||||
## Project Status for now
|
||||
|
||||
**MDBX is under _active development_**, database format and API aren't stable
|
||||
at least until 2018Q2. New version won't be backwards compatible.
|
||||
Main focus of the rework is to provide clear and robust API and new features.
|
||||
- The stable versions ([_stable/0.0_](https://github.com/leo-yuriev/libmdbx/tree/stable/0.0) and [_stable/0.1_](https://github.com/leo-yuriev/libmdbx/tree/stable/0.1) branches) of _MDBX_ are frozen, i.e. no new features or API changes, but only bug fixes.
|
||||
- The next version ([_devel_](https://github.com/leo-yuriev/libmdbx/tree/devel) branch) **is under active non-public development**, i.e. current API and set of features are extreme volatile.
|
||||
- The immediate goal of development is formation of the stable API and the stable internal database format, which allows realise all PLANNED FEATURES:
|
||||
1. Integrity check by [Merkle tree](https://en.wikipedia.org/wiki/Merkle_tree);
|
||||
2. Support for [raw block devices](https://en.wikipedia.org/wiki/Raw_device);
|
||||
3. Separate place (HDD) for large data items;
|
||||
4. Using "[Roaring bitmaps](http://roaringbitmap.org/about/)" inside garbage collector;
|
||||
5. Non-sequential reclaiming, like PostgreSQL's [Vacuum](https://www.postgresql.org/docs/9.1/static/sql-vacuum.html);
|
||||
6. [Asynchronous lazy data flushing](https://sites.fas.harvard.edu/~cs265/papers/kathuria-2008.pdf) to disk(s);
|
||||
7. etc...
|
||||
|
||||
-----
|
||||
|
||||
Nowadays MDBX intended for Linux, and support Windows (since
|
||||
Windows Server 2008) as a complementary platform. Support for
|
||||
other OS could be implemented on commercial basis. However such
|
||||
enhancements (i.e. pull requests) could be accepted in
|
||||
mainstream only when corresponding public and free Continuous
|
||||
Integration service will be available.
|
||||
|
||||
## Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Comparison with other DBs](#comparison-with-other-dbs)
|
||||
- [History & Acknowledgements](#history)
|
||||
- [History & Acknowledgments](#history)
|
||||
- [Main features](#main-features)
|
||||
- [Performance comparison](#performance-comparison)
|
||||
- [Integral performance](#integral-performance)
|
||||
@@ -34,7 +50,7 @@ Main focus of the rework is to provide clear and robust API and new features.
|
||||
|
||||
## Overview
|
||||
|
||||
_libmdbx_ is an embedded lightweight key-value database engine oriented for performance.
|
||||
_libmdbx_ is an embedded lightweight key-value database engine oriented for performance under Linux and Windows.
|
||||
|
||||
_libmdbx_ allows multiple processes to read and update several key-value tables concurrently,
|
||||
while being [ACID](https://en.wikipedia.org/wiki/ACID)-compliant, with minimal overhead and operation cost of Olog(N).
|
||||
@@ -57,7 +73,7 @@ Because _libmdbx_ is currently overhauled, I think it's better to just link
|
||||
|
||||
### History
|
||||
|
||||
_libmdbx_ design is based on [Lightning Memory-Mapped Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
|
||||
The _libmdbx_ design is based on [Lightning Memory-Mapped 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 year later it
|
||||
received separate development effort and in autumn 2015 was isolated to separate project, which was
|
||||
[presented at Highload++ 2015 conference](http://www.highload.ru/2015/abstracts/1831.html).
|
||||
@@ -65,7 +81,7 @@ received separate development effort and in autumn 2015 was isolated to separate
|
||||
Since early 2017 _libmdbx_ is used in [Fast Positive Tables](https://github.com/leo-yuriev/libfpta),
|
||||
by [Positive Technologies](https://www.ptsecurity.com).
|
||||
|
||||
#### Acknowledgements
|
||||
#### Acknowledgments
|
||||
|
||||
Howard Chu (Symas Corporation) - the author of LMDB,
|
||||
from which originated the MDBX in 2015.
|
||||
@@ -261,7 +277,7 @@ scanning data directory.
|
||||
#### Long-time read transactions problem
|
||||
|
||||
Garbage collection problem exists in all databases one way or another (e.g. VACUUM in PostgreSQL).
|
||||
But in _libmbdx_ and LMDB it's even more important because of high performance and deliberate
|
||||
But in _libmdbx_ and LMDB it's even more important because of high performance and deliberate
|
||||
simplification of internals with emphasis on performance.
|
||||
|
||||
* Altering data during long read operation may exhaust available space on persistent storage.
|
||||
@@ -297,7 +313,7 @@ _libmdbx_ addresses the problem, details below. Illustrations to this problem ca
|
||||
In `WRITEMAP+MAPSYNC` mode dirty pages are written to persistent storage by kernel. This means that in case of application
|
||||
crash OS kernel will write all dirty data to disk and nothing will be lost. But in case of hardware malfunction or OS kernel
|
||||
fatal error only some dirty data might be synced to disk, and there is high probability that pages with metadata saved,
|
||||
will point to non-saved, hence non-existent, data pages. In such situation DB is completely corrupted and can't be
|
||||
will point to non-saved, hence non-existent, data pages. In such situation, DB is completely corrupted and can't be
|
||||
repaired even if there was full sync before the crash via `mdbx_env_sync().
|
||||
|
||||
_libmdbx_ addresses this by fully reimplementing write path of data:
|
||||
@@ -320,7 +336,7 @@ synchronization point. So last steady synchronization point creates "long-time r
|
||||
of memory exhaustion the problem will be immediately addressed by flushing changes to persistent storage and forming new steady
|
||||
synchronization point.
|
||||
|
||||
So in async-write mode _libmdbx_ will always use new pages until memory is exhausted or `mdbx_env_sync()`is invoked. Total
|
||||
So in async-write mode _libmdbx_ will always use new pages until memory is exhausted or `mdbx_env_sync()` is invoked. Total
|
||||
disk usage will be almost the same as in sync-write mode.
|
||||
|
||||
Current _libmdbx_ gives a choice of safe async-write mode (default) and `UTTERLY_NOSYNC` mode which may result in full DB
|
||||
@@ -336,7 +352,7 @@ Improvements over LMDB
|
||||
1. `LIFO RECLAIM` mode:
|
||||
|
||||
The newest pages are picked for reuse instead of the oldest.
|
||||
This allows to minimize reclaim loop and make it execution time independent from total page count.
|
||||
This allows to minimize reclaim loop and make it execution time independent of total page count.
|
||||
|
||||
This results in OS kernel cache mechanisms working with maximum efficiency.
|
||||
In case of using disk controllers or storages with
|
||||
@@ -348,7 +364,7 @@ Improvements over LMDB
|
||||
`mdbx_env_set_oomfunc()` allows to set a callback, which will be called
|
||||
in the event of memory exhausting during long-time read transaction.
|
||||
Callback will be invoked with PID and pthread_id of offending thread as parameters.
|
||||
Callback can do any of this things to remedy the problem:
|
||||
Callback can do any of these things to remedy the problem:
|
||||
|
||||
* wait for read transaction to finish normally;
|
||||
|
||||
@@ -392,7 +408,7 @@ Improvements over LMDB
|
||||
15. Ability to close DB in "dirty" state (without data flush and creation of steady synchronization point)
|
||||
via `mdbx_env_close_ex()`.
|
||||
|
||||
16. Ability to get addition info, including number of the oldest snapshot of DB, which is used by one of the readers.
|
||||
16. Ability to get additional info, including number of the oldest snapshot of DB, which is used by one of the readers.
|
||||
Implemented via `mdbx_env_info()`.
|
||||
|
||||
17. `mdbx_del()` doesn't ignore additional argument (specifier) `data`
|
||||
@@ -401,7 +417,7 @@ Improvements over LMDB
|
||||
|
||||
18. Ability to open dbi-table with simultaneous setup of comparators for keys and values, via `mdbx_dbi_open_ex()`.
|
||||
|
||||
19. Ability to find out if key or value are in dirty page. This may be useful to make a decision to avoid
|
||||
19. Ability to find out if key or value is in dirty page. This may be useful to make a decision to avoid
|
||||
excessive CoW before updates. Implemented via `mdbx_is_dirty()`.
|
||||
|
||||
20. Correct update of current record in `MDBX_CURRENT` mode of `mdbx_cursor_put()`, including sorted duplicated.
|
||||
@@ -432,12 +448,12 @@ Improvements over LMDB
|
||||
27. Advanced dynamic control over DB size, including ability to choose page size via `mdbx_env_set_geometry()`,
|
||||
including on Windows.
|
||||
|
||||
28. Three meta-pages instead two, this allows to guarantee consistently update weak sync-points without risking to
|
||||
28. Three meta-pages instead of two, this allows to guarantee consistently update weak sync-points without risking to
|
||||
corrupt last steady sync-point.
|
||||
|
||||
29. Automatic reclaim of freed pages to specific reserved space in the end of database file. This lowers amount of pages,
|
||||
29. Automatic reclaim of freed pages to specific reserved space at the end of database file. This lowers amount of pages,
|
||||
loaded to memory, used in update/flush loop. In fact _libmdbx_ constantly performs compactification of data,
|
||||
but doesn't use addition resources for that. Space reclaim of DB and setup of database geometry parameters also decreases
|
||||
but doesn't use additional resources for that. Space reclaim of DB and setup of database geometry parameters also decreases
|
||||
size of the database on disk, including on Windows.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
2
TODO.md
2
TODO.md
@@ -70,7 +70,7 @@
|
||||
- [x] Привести в порядок volatile.
|
||||
- [x] контроль meta.mapsize.
|
||||
- [x] переработка формата: заголовки страниц, meta, clk...
|
||||
- [x] зачистка Doxygen и бесполезных коментариев.
|
||||
- [x] зачистка Doxygen и бесполезных комментариев.
|
||||
- [x] Добавить поле типа контрольной суммы.
|
||||
- [x] Добавить поле/флаг размера pgno_t.
|
||||
- [x] Поменять сигнатуры.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: 0.1.2.{build}
|
||||
version: 0.1.5.{build}
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
|
||||
26
src/bits.h
26
src/bits.h
@@ -23,11 +23,6 @@
|
||||
# undef NDEBUG
|
||||
#endif
|
||||
|
||||
/* Features under development */
|
||||
#ifndef MDBX_DEVEL
|
||||
# define MDBX_DEVEL 0
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Should be defined before any includes */
|
||||
@@ -45,6 +40,9 @@
|
||||
#if _MSC_VER > 1800
|
||||
# pragma warning(disable : 4464) /* relative include path contains '..' */
|
||||
#endif
|
||||
#if _MSC_VER > 1913
|
||||
# pragma warning(disable : 5045) /* Compiler will insert Spectre mitigation... */
|
||||
#endif
|
||||
#pragma warning(disable : 4710) /* 'xyz': function not inlined */
|
||||
#pragma warning(disable : 4711) /* function 'xyz' selected for automatic inline expansion */
|
||||
#pragma warning(disable : 4201) /* nonstandard extension used : nameless struct / union */
|
||||
@@ -141,9 +139,9 @@
|
||||
#define MDBX_MAGIC UINT64_C(/* 56-bit prime */ 0x59659DBDEF4C11)
|
||||
|
||||
/* The version number for a database's datafile format. */
|
||||
#define MDBX_DATA_VERSION ((MDBX_DEVEL) ? 255 : 2)
|
||||
#define MDBX_DATA_VERSION 2
|
||||
/* The version number for a database's lockfile format. */
|
||||
#define MDBX_LOCK_VERSION ((MDBX_DEVEL) ? 255 : 2)
|
||||
#define MDBX_LOCK_VERSION 2
|
||||
|
||||
/* handle for the DB used to track free pages. */
|
||||
#define FREE_DBI 0
|
||||
@@ -168,9 +166,7 @@ typedef uint32_t pgno_t;
|
||||
/* A transaction ID. */
|
||||
typedef uint64_t txnid_t;
|
||||
#define PRIaTXN PRIi64
|
||||
#if MDBX_DEVEL
|
||||
#define MIN_TXNID (UINT64_MAX - UINT32_MAX)
|
||||
#elif MDBX_DEBUG
|
||||
#if MDBX_DEBUG
|
||||
#define MIN_TXNID UINT64_C(0x100000000)
|
||||
#else
|
||||
#define MIN_TXNID UINT64_C(1)
|
||||
@@ -948,13 +944,13 @@ static __inline void mdbx_jitter4testing(bool tiny) {
|
||||
/* Internal prototypes and inlines */
|
||||
|
||||
int mdbx_reader_check0(MDBX_env *env, int rlocked, int *dead);
|
||||
void mdbx_rthc_dtor(void *rthc);
|
||||
void mdbx_rthc_lock(void);
|
||||
void mdbx_rthc_unlock(void);
|
||||
int mdbx_rthc_alloc(mdbx_thread_key_t *key, MDBX_reader *begin,
|
||||
MDBX_reader *end);
|
||||
void mdbx_rthc_remove(mdbx_thread_key_t key);
|
||||
void mdbx_rthc_cleanup(void);
|
||||
void mdbx_rthc_remove(const mdbx_thread_key_t key);
|
||||
|
||||
void mdbx_rthc_global_init(void);
|
||||
void mdbx_rthc_global_dtor(void);
|
||||
void mdbx_rthc_thread_dtor(void *ptr);
|
||||
|
||||
static __inline bool mdbx_is_power2(size_t x) { return (x & (x - 1)) == 0; }
|
||||
|
||||
|
||||
@@ -32,18 +32,12 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* rthc */
|
||||
|
||||
static pthread_mutex_t mdbx_rthc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void mdbx_rthc_lock(void) {
|
||||
mdbx_ensure(NULL, pthread_mutex_lock(&mdbx_rthc_mutex) == 0);
|
||||
static __cold __attribute__((constructor)) void mdbx_global_constructor(void) {
|
||||
mdbx_rthc_global_init();
|
||||
}
|
||||
|
||||
void mdbx_rthc_unlock(void) {
|
||||
mdbx_ensure(NULL, pthread_mutex_unlock(&mdbx_rthc_mutex) == 0);
|
||||
}
|
||||
|
||||
void __attribute__((destructor)) mdbx_global_destructor(void) {
|
||||
mdbx_rthc_cleanup();
|
||||
static __cold __attribute__((destructor)) void mdbx_global_destructor(void) {
|
||||
mdbx_rthc_global_dtor();
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
@@ -27,31 +27,24 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* rthc */
|
||||
|
||||
static CRITICAL_SECTION rthc_critical_section;
|
||||
|
||||
static void NTAPI tls_callback(PVOID module, DWORD reason, PVOID reserved) {
|
||||
(void)module;
|
||||
(void)reserved;
|
||||
switch (reason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
InitializeCriticalSection(&rthc_critical_section);
|
||||
mdbx_rthc_global_init();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
DeleteCriticalSection(&rthc_critical_section);
|
||||
mdbx_rthc_global_dtor();
|
||||
break;
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
mdbx_rthc_cleanup();
|
||||
mdbx_rthc_thread_dtor(module);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void mdbx_rthc_lock(void) { EnterCriticalSection(&rthc_critical_section); }
|
||||
|
||||
void mdbx_rthc_unlock(void) { LeaveCriticalSection(&rthc_critical_section); }
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
/* clang-format off */
|
||||
#if defined(_MSC_VER)
|
||||
@@ -169,7 +162,10 @@ int mdbx_rdt_lock(MDBX_env *env) {
|
||||
/* transite from S-? (used) to S-E (locked), e.g. exclusive lock upper-part */
|
||||
if (flock(env->me_lfd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER))
|
||||
return MDBX_SUCCESS;
|
||||
return GetLastError();
|
||||
|
||||
int rc = GetLastError();
|
||||
ReleaseSRWLockShared(&env->me_remap_guard);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void mdbx_rdt_unlock(MDBX_env *env) {
|
||||
@@ -550,10 +546,12 @@ int mdbx_rpid_clear(MDBX_env *env) {
|
||||
* or otherwise the errcode. */
|
||||
int mdbx_rpid_check(MDBX_env *env, mdbx_pid_t pid) {
|
||||
(void)env;
|
||||
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
|
||||
HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid);
|
||||
int rc;
|
||||
if (hProcess) {
|
||||
if (likely(hProcess)) {
|
||||
rc = WaitForSingleObject(hProcess, 0);
|
||||
if (unlikely(rc == WAIT_FAILED))
|
||||
rc = GetLastError();
|
||||
CloseHandle(hProcess);
|
||||
} else {
|
||||
rc = GetLastError();
|
||||
|
||||
742
src/mdbx.c
742
src/mdbx.c
File diff suppressed because it is too large
Load Diff
33
src/osal.c
33
src/osal.c
@@ -700,39 +700,6 @@ int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length) {
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
int mdbx_thread_key_create(mdbx_thread_key_t *key) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
*key = TlsAlloc();
|
||||
return (*key != TLS_OUT_OF_INDEXES) ? MDBX_SUCCESS : GetLastError();
|
||||
#else
|
||||
return pthread_key_create(key, mdbx_rthc_dtor);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mdbx_thread_key_delete(mdbx_thread_key_t key) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
mdbx_ensure(NULL, TlsFree(key));
|
||||
#else
|
||||
mdbx_ensure(NULL, pthread_key_delete(key) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void *mdbx_thread_rthc_get(mdbx_thread_key_t key) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
return TlsGetValue(key);
|
||||
#else
|
||||
return pthread_getspecific(key);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mdbx_thread_rthc_set(mdbx_thread_key_t key, const void *value) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
mdbx_ensure(NULL, TlsSetValue(key, (void *)value));
|
||||
#else
|
||||
mdbx_ensure(NULL, pthread_setspecific(key, value) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
int mdbx_thread_create(mdbx_thread_t *thread,
|
||||
THREAD_RESULT(THREAD_CALL *start_routine)(void *),
|
||||
void *arg) {
|
||||
|
||||
@@ -469,10 +469,6 @@ int mdbx_thread_create(mdbx_thread_t *thread,
|
||||
THREAD_RESULT(THREAD_CALL *start_routine)(void *),
|
||||
void *arg);
|
||||
int mdbx_thread_join(mdbx_thread_t thread);
|
||||
int mdbx_thread_key_create(mdbx_thread_key_t *key);
|
||||
void mdbx_thread_key_delete(mdbx_thread_key_t key);
|
||||
void *mdbx_thread_rthc_get(mdbx_thread_key_t key);
|
||||
void mdbx_thread_rthc_set(mdbx_thread_key_t key, const void *value);
|
||||
|
||||
int mdbx_filesync(mdbx_filehandle_t fd, bool fullsync);
|
||||
int mdbx_filesize_sync(mdbx_filehandle_t fd);
|
||||
|
||||
@@ -837,8 +837,8 @@ int main(int argc, char *argv[]) {
|
||||
#endif /* !WINDOWS */
|
||||
|
||||
envname = argv[optind];
|
||||
print("Running mdbx_chk for 'read-%s' in %s mode...\n", envname,
|
||||
(envflags & MDBX_RDONLY) ? "read" : "write");
|
||||
print("Running mdbx_chk for %s in 'read-%s' mode...\n", envname,
|
||||
(envflags & MDBX_RDONLY) ? "only" : "write");
|
||||
fflush(NULL);
|
||||
|
||||
rc = mdbx_env_create(&env);
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#error "API version mismatch!"
|
||||
#endif
|
||||
|
||||
#define MDBX_VERSION_RELEASE 0
|
||||
#define MDBX_VERSION_REVISION 0
|
||||
#define MDBX_VERSION_RELEASE 5
|
||||
#define MDBX_VERSION_REVISION 1
|
||||
|
||||
/*LIBMDBX_EXPORTS*/ const mdbx_version_info mdbx_version = {
|
||||
MDBX_VERSION_MAJOR,
|
||||
|
||||
Reference in New Issue
Block a user