mirror of
https://github.com/isar/libmdbx.git
synced 2025-12-16 17:12:23 +08:00
Compare commits
71 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 | ||
|
|
6758348046 | ||
|
|
09ab6dd777 | ||
|
|
61a2c56784 | ||
|
|
6a074cb85a | ||
|
|
dbc87a8a5e | ||
|
|
3a42b76fb8 | ||
|
|
c52a57dac5 | ||
|
|
5ce40269b3 | ||
|
|
3d320253cd | ||
|
|
86274513f9 | ||
|
|
f5571e4027 | ||
|
|
62ae928b40 | ||
|
|
a282965aa0 | ||
|
|
3c5cc40c77 | ||
|
|
475da5bcfe | ||
|
|
679fb56787 | ||
|
|
dd6cb30820 | ||
|
|
8d748a845b | ||
|
|
5872174db6 | ||
|
|
52283d8c44 | ||
|
|
838856f688 | ||
|
|
0aa07cc09b | ||
|
|
e8dd15088a | ||
|
|
d0e1c02a8a | ||
|
|
b2213c86fe | ||
|
|
9ccd551ebc | ||
|
|
a2ec7f2be1 | ||
|
|
d63c2484fe | ||
|
|
638ed91e3e | ||
|
|
64613c9061 | ||
|
|
c05d179035 | ||
|
|
195b53374e | ||
|
|
f521b6615e | ||
|
|
9bbc62f5a0 | ||
|
|
8c96b1e73b | ||
|
|
436b4870e8 | ||
|
|
483c4abb3f |
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")
|
||||
|
||||
71
Makefile
71
Makefile
@@ -23,23 +23,17 @@ suffix ?=
|
||||
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
XCFLAGS ?= -DNDEBUG=1 -DMDBX_DEBUG=0 -DLIBMDBX_EXPORTS=1
|
||||
CFLAGS ?= -O2 -g3 -Wall -Werror -Wextra -ffunction-sections -fPIC -fvisibility=hidden
|
||||
|
||||
XCFLAGS ?= -DNDEBUG=1 -DMDBX_DEBUG=0 -DLIBMDBX_EXPORTS=1
|
||||
CFLAGS += -D_GNU_SOURCE=1 -std=gnu11 -pthread $(XCFLAGS)
|
||||
|
||||
# temporary workaround for lcc's bug
|
||||
TARGET_ARCH_e2k = $(shell (export LC_ALL=C; ($(CC) --version 2>&1; $(CC) -v 2>&1) | grep -q -i 'e2k' && echo yes || echo no))
|
||||
ifeq ($(TARGET_ARCH_e2k),yes)
|
||||
TARGET_ARCH := e2k
|
||||
CFLAGS += -mtune=native -Wno-alignment-reduction-ignored
|
||||
endif
|
||||
|
||||
CXXFLAGS = -std=c++11 $(filter-out -std=gnu11,$(CFLAGS))
|
||||
TESTDB ?= $(shell [ -d /dev/shm ] && echo /dev/shm || echo /tmp)/mdbx-check.db
|
||||
TESTLOG ?= $(shell [ -d /dev/shm ] && echo /dev/shm || echo /tmp)/mdbx-check.log
|
||||
TESTDB ?= $(shell [ -d /dev/shm ] && echo /dev/shm || echo /tmp)/mdbx-test.db
|
||||
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 ?= -pthread -lrt
|
||||
|
||||
# LY: just for benchmarking
|
||||
IOARENA ?= $(shell \
|
||||
@@ -65,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
|
||||
|
||||
@@ -85,10 +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; ./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; ./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
|
||||
@@ -111,10 +111,12 @@ libmdbx.so: $(CORE_OBJ)
|
||||
$(CC) $(CFLAGS) -save-temps $^ -pthread -shared $(LDFLAGS) -o $@
|
||||
|
||||
mdbx_%: src/tools/mdbx_%.c libmdbx.a
|
||||
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||
$(CC) $(CFLAGS) $^ $(EXE_LDFLAGS) -o $@
|
||||
|
||||
test/test: $(TEST_OBJ) libmdbx.a
|
||||
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
|
||||
mdbx_test: $(TEST_OBJ) libmdbx.so
|
||||
$(CXX) $(CXXFLAGS) $(TEST_OBJ) -Wl,-rpath . -L . -l mdbx $(EXE_LDFLAGS) -o $@
|
||||
|
||||
###############################################################################
|
||||
|
||||
ifneq ($(wildcard $(IOARENA)),)
|
||||
|
||||
@@ -163,6 +165,8 @@ bench-quartet: bench-mdbx_$(NN).txt bench-lmdb_$(NN).txt bench-rocksdb_$(NN).txt
|
||||
|
||||
endif
|
||||
|
||||
###############################################################################
|
||||
|
||||
ci-rule = ( CC=$$(which $1); if [ -n "$$CC" ]; then \
|
||||
echo -n "probe by $2 ($$(readlink -f $$(which $$CC))): " && \
|
||||
$(MAKE) clean >$1.log 2>$1.err && \
|
||||
@@ -178,3 +182,36 @@ ci:
|
||||
@$(call ci-rule,gcc,GCC)
|
||||
@$(call ci-rule,clang,clang LLVM)
|
||||
@$(call ci-rule,icc,Intel C)
|
||||
|
||||
###############################################################################
|
||||
|
||||
CROSS_LIST = alpha-linux-gnu-gcc mips-linux-gnu-gcc \
|
||||
powerpc64-linux-gnu-gcc powerpc-linux-gnu-gcc \
|
||||
arm-linux-gnueabihf-gcc aarch64-linux-gnu-gcc
|
||||
|
||||
# hppa-linux-gnu-gcc - don't supported by current qemu release
|
||||
# s390x-linux-gnu-gcc - qemu troubles (hang/abort)
|
||||
# sh4-linux-gnu-gcc - qemu troubles (pread syscall, etc)
|
||||
# mips64-linux-gnuabi64-gcc - qemu troubles (pread syscall, etc)
|
||||
# sparc64-linux-gnu-gcc - qemu troubles (fcntl for F_SETLK/F_GETLK)
|
||||
CROSS_LIST_NOQEMU = hppa-linux-gnu-gcc s390x-linux-gnu-gcc \
|
||||
sh4-linux-gnu-gcc mips64-linux-gnuabi64-gcc sparc64-linux-gnu-gcc
|
||||
|
||||
cross-gcc:
|
||||
@echo "CORRESPONDING CROSS-COMPILERs ARE REQUIRED."
|
||||
@echo "FOR INSTANCE: apt install g++-aarch64-linux-gnu g++-alpha-linux-gnu g++-arm-linux-gnueabihf g++-hppa-linux-gnu g++-mips-linux-gnu g++-mips64-linux-gnuabi64 g++-powerpc-linux-gnu g++-powerpc64-linux-gnu g++-s390x-linux-gnu g++-sh4-linux-gnu"
|
||||
@for CC in $(CROSS_LIST_NOQEMU) $(CROSS_LIST); do \
|
||||
echo "===================== $$CC"; \
|
||||
$(MAKE) clean && CC=$$CC CXX=$$(echo $$CC | sed 's/-gcc/-g++/') EXE_LDFLAGS=-static $(MAKE) all || exit $$?; \
|
||||
done
|
||||
|
||||
#
|
||||
# Unfortunately qemu don't provide robust support for futexes.
|
||||
# Therefore it is impossible to run full multi-process tests.
|
||||
cross-qemu:
|
||||
@echo "CORRESPONDING CROSS-COMPILERs AND QEMUs ARE REQUIRED."
|
||||
@echo "FOR INSTANCE: apt install binfmt-support qemu-user-static qemu-user qemu-system-arm qemu-system-mips qemu-system-misc qemu-system-ppc qemu-system-sparc g++-aarch64-linux-gnu g++-alpha-linux-gnu g++-arm-linux-gnueabihf g++-hppa-linux-gnu g++-mips-linux-gnu g++-mips64-linux-gnuabi64 g++-powerpc-linux-gnu g++-powerpc64-linux-gnu g++-s390x-linux-gnu g++-sh4-linux-gnu"
|
||||
@for CC in $(CROSS_LIST); do \
|
||||
echo "===================== $$CC + qemu"; \
|
||||
$(MAKE) clean && CC=$$CC CXX=$$(echo $$CC | sed 's/-gcc/-g++/') EXE_LDFLAGS=-static $(MAKE) check-singleprocess || exit $$?; \
|
||||
done
|
||||
|
||||
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**.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
60
README.md
60
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.
|
||||
@@ -233,7 +249,7 @@ scanning data directory.
|
||||
Because of this syncing data to disk might be quite resource intensive and be main performance bottleneck
|
||||
during intensive write workload.
|
||||
> As compromise _libmdbx_ allows several modes of lazy and/or periodic syncing, including `MAPASYNC` mode, which modificate
|
||||
> data in memory and asynchronously syncs data to disc, moment to sync is picked by OS.
|
||||
> data in memory and asynchronously syncs data to disk, moment to sync is picked by OS.
|
||||
>
|
||||
> Although this should be used with care, synchronous transactions in a DB with transaction journal will require 2 IOPS
|
||||
> minimum (probably 3-4 in practice) because of filesystem overhead, overhead depends on filesystem, not on record
|
||||
@@ -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,10 +352,10 @@ 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 disc controllers or storages with
|
||||
In case of using disk controllers or storages with
|
||||
[BBWC](https://en.wikipedia.org/wiki/Disk_buffer#Write_acceleration) this may greatly improve
|
||||
write performance.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -378,7 +394,7 @@ Improvements over LMDB
|
||||
|
||||
9. Check if there is a row with data after current cursor position via `mdbx_cursor_eof()`.
|
||||
|
||||
10. Ability to explicitly request update of current record without creating new record. Implemented as `MDBX_CURRENT` flag
|
||||
10. Ability to explicitly request update of present record without creating new record. Implemented as `MDBX_CURRENT` flag
|
||||
for `mdbx_put()`.
|
||||
|
||||
11. Ability to update or delete record and get previous value via `mdbx_replace()` Also can update specific multi-value.
|
||||
@@ -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.
|
||||
@@ -419,7 +435,7 @@ Improvements over LMDB
|
||||
22. Additional error code `MDBX_EMULTIVAL`, which is returned by `mdbx_put()` and
|
||||
`mdbx_replace()` in case is ambiguous update or delete.
|
||||
|
||||
23. Ability to get value by key and duplicates count by `mdbx_get_ex()`
|
||||
23. Ability to get value by key and duplicates count by `mdbx_get_ex()`.
|
||||
|
||||
24. Functions `mdbx_cursor_on_first() and mdbx_cursor_on_last(), which allows to know if cursor is currently on first or
|
||||
last position respectively.
|
||||
@@ -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.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
4
TODO.md
4
TODO.md
@@ -21,7 +21,7 @@
|
||||
Тесты
|
||||
=====
|
||||
- [ ] Тестирование поддержки lockless-режима.
|
||||
- [ ] Додумать имя и размещение тестовой БД по-умолчанию.
|
||||
- [x] Додумать имя и размещение тестовой БД по-умолчанию.
|
||||
- [ ] Реализовать cleanup в тесте.
|
||||
- [ ] usage для теста.
|
||||
- [ ] Логирование в файл, плюс более полный progress bar.
|
||||
@@ -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:
|
||||
|
||||
45
mdbx.h
45
mdbx.h
@@ -982,6 +982,15 @@ LIBMDBX_API int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
|
||||
* [in] txn A transaction handle returned by mdbx_txn_begin() */
|
||||
LIBMDBX_API MDBX_env *mdbx_txn_env(MDBX_txn *txn);
|
||||
|
||||
/* Return the transaction's flags.
|
||||
*
|
||||
* This returns the flags associated with this transaction.
|
||||
*
|
||||
* [in] txn A transaction handle returned by mdbx_txn_begin()
|
||||
*
|
||||
* Returns A transaction flags, valid if input is an active transaction. */
|
||||
LIBMDBX_API int mdbx_txn_flags(MDBX_txn *txn);
|
||||
|
||||
/* Return the transaction's ID.
|
||||
*
|
||||
* This returns the identifier associated with this transaction. For a
|
||||
@@ -1818,6 +1827,42 @@ LIBMDBX_API int mdbx_cursor_get_attr(MDBX_cursor *mc, MDBX_val *key,
|
||||
LIBMDBX_API int mdbx_get_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
MDBX_val *data, mdbx_attr_t *attrptr);
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* LY: temporary workaround for Elbrus's memcmp() bug. */
|
||||
#ifndef __GLIBC_PREREQ
|
||||
#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
|
||||
#define __GLIBC_PREREQ(maj, min) \
|
||||
((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
|
||||
#else
|
||||
#define __GLIBC_PREREQ(maj, min) (0)
|
||||
#endif
|
||||
#endif /* __GLIBC_PREREQ */
|
||||
#if defined(__e2k__) && !__GLIBC_PREREQ(2, 24)
|
||||
LIBMDBX_API int mdbx_e2k_memcmp_bug_workaround(const void *s1, const void *s2,
|
||||
size_t n);
|
||||
LIBMDBX_API int mdbx_e2k_strcmp_bug_workaround(const char *s1, const char *s2);
|
||||
LIBMDBX_API int mdbx_e2k_strncmp_bug_workaround(const char *s1, const char *s2,
|
||||
size_t n);
|
||||
LIBMDBX_API size_t mdbx_e2k_strlen_bug_workaround(const char *s);
|
||||
LIBMDBX_API size_t mdbx_e2k_strnlen_bug_workaround(const char *s,
|
||||
size_t maxlen);
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#undef memcmp
|
||||
#define memcmp mdbx_e2k_memcmp_bug_workaround
|
||||
#undef bcmp
|
||||
#define bcmp mdbx_e2k_memcmp_bug_workaround
|
||||
#undef strcmp
|
||||
#define strcmp mdbx_e2k_strcmp_bug_workaround
|
||||
#undef strncmp
|
||||
#define strncmp mdbx_e2k_strncmp_bug_workaround
|
||||
#undef strlen
|
||||
#define strlen mdbx_e2k_strlen_bug_workaround
|
||||
#undef strnlen
|
||||
#define strnlen mdbx_e2k_strnlen_bug_workaround
|
||||
|
||||
#endif /* Elbrus's memcmp() bug. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
126
src/bits.h
126
src/bits.h
@@ -23,11 +23,6 @@
|
||||
# undef NDEBUG
|
||||
#endif
|
||||
|
||||
/* Features under development */
|
||||
#ifndef MDBX_DEVEL
|
||||
# define MDBX_DEVEL 1
|
||||
#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 */
|
||||
@@ -55,6 +53,7 @@
|
||||
#pragma warning(disable : 4310) /* cast truncates constant value */
|
||||
#pragma warning(disable : 4820) /* bytes padding added after data member for aligment */
|
||||
#pragma warning(disable : 4548) /* expression before comma has no effect; expected expression with side - effect */
|
||||
#pragma warning(disable : 4366) /* the result of the unary '&' operator may be unaligned */
|
||||
#endif /* _MSC_VER (warnings) */
|
||||
|
||||
#include "../mdbx.h"
|
||||
@@ -89,26 +88,29 @@
|
||||
#endif /* __SANITIZE_THREAD__ */
|
||||
|
||||
#if __has_warning("-Wconstant-logical-operand")
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic ignored "-Wconstant-logical-operand"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wconstant-logical-operand"
|
||||
#else
|
||||
#pragma warning disable "constant-logical-operand"
|
||||
#endif
|
||||
# if defined(__clang__)
|
||||
# pragma clang diagnostic ignored "-Wconstant-logical-operand"
|
||||
# elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic ignored "-Wconstant-logical-operand"
|
||||
# else
|
||||
# pragma warning disable "constant-logical-operand"
|
||||
# endif
|
||||
#endif /* -Wconstant-logical-operand */
|
||||
|
||||
#if __has_warning("-Walignment-reduction-ignored") || defined(__e2k__) || defined(__ICC)
|
||||
#if defined(__ICC)
|
||||
#pragma warning(disable: 3453 1366)
|
||||
#elif defined(__clang__)
|
||||
#pragma clang diagnostic ignored "-Walignment-reduction-ignored"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Walignment-reduction-ignored"
|
||||
#else
|
||||
#pragma warning disable "alignment-reduction-ignored"
|
||||
#endif
|
||||
#endif /* -Wno-constant-logical-operand */
|
||||
#if defined(__LCC__) && (__LCC__ <= 121)
|
||||
/* bug #2798 */
|
||||
# pragma diag_suppress alignment_reduction_ignored
|
||||
#elif defined(__ICC)
|
||||
# pragma warning(disable: 3453 1366)
|
||||
#elif __has_warning("-Walignment-reduction-ignored")
|
||||
# if defined(__clang__)
|
||||
# pragma clang diagnostic ignored "-Walignment-reduction-ignored"
|
||||
# elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic ignored "-Walignment-reduction-ignored"
|
||||
# else
|
||||
# pragma warning disable "alignment-reduction-ignored"
|
||||
# endif
|
||||
#endif /* -Walignment-reduction-ignored */
|
||||
|
||||
#include "./osal.h"
|
||||
|
||||
@@ -137,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
|
||||
@@ -164,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)
|
||||
@@ -249,7 +249,7 @@ typedef struct MDBX_reader {
|
||||
uint8_t pad[MDBX_CACHELINE_SIZE -
|
||||
(sizeof(txnid_t) + sizeof(mdbx_pid_t) + sizeof(mdbx_tid_t)) %
|
||||
MDBX_CACHELINE_SIZE];
|
||||
} __cache_aligned MDBX_reader;
|
||||
} MDBX_reader;
|
||||
|
||||
/* Information about a single database in the environment. */
|
||||
typedef struct MDBX_db {
|
||||
@@ -407,47 +407,53 @@ typedef struct MDBX_lockinfo {
|
||||
/* Flags which environment was opened. */
|
||||
volatile uint32_t mti_envmode;
|
||||
|
||||
union {
|
||||
#ifdef MDBX_OSAL_LOCK
|
||||
/* Mutex protecting write access to this table. */
|
||||
union {
|
||||
MDBX_OSAL_LOCK mti_wmutex;
|
||||
uint8_t pad_mti_wmutex[MDBX_OSAL_LOCK_SIZE % sizeof(size_t)];
|
||||
};
|
||||
#endif
|
||||
uint64_t align_wmutex;
|
||||
};
|
||||
#define MDBX_lockinfo_SIZE_A \
|
||||
(8 /* mti_magic_and_version */ + 4 /* mti_os_and_format */ + \
|
||||
4 /* mti_envmode */ + MDBX_OSAL_LOCK_SIZE /* mti_wmutex */ + \
|
||||
MDBX_OSAL_LOCK_SIZE % sizeof(size_t) /* pad_mti_wmutex */)
|
||||
|
||||
union {
|
||||
/* The number of slots that have been used in the reader table.
|
||||
* This always records the maximum count, it is not decremented
|
||||
* when readers release their slots. */
|
||||
volatile unsigned __cache_aligned mti_numreaders;
|
||||
uint64_t align_numreaders;
|
||||
};
|
||||
/* cache-line alignment */
|
||||
uint8_t
|
||||
pad_a[MDBX_CACHELINE_SIZE - MDBX_lockinfo_SIZE_A % MDBX_CACHELINE_SIZE];
|
||||
|
||||
/* The number of slots that have been used in the reader table.
|
||||
* This always records the maximum count, it is not decremented
|
||||
* when readers release their slots. */
|
||||
volatile unsigned mti_numreaders;
|
||||
|
||||
union {
|
||||
#ifdef MDBX_OSAL_LOCK
|
||||
/* Mutex protecting access to this table. */
|
||||
/* Mutex protecting readers registration access to this table. */
|
||||
union {
|
||||
MDBX_OSAL_LOCK mti_rmutex;
|
||||
uint8_t pad_mti_rmutex[MDBX_OSAL_LOCK_SIZE % sizeof(size_t)];
|
||||
};
|
||||
#endif
|
||||
uint64_t align_rmutex;
|
||||
};
|
||||
|
||||
union {
|
||||
volatile txnid_t mti_oldest;
|
||||
uint64_t align_oldest;
|
||||
};
|
||||
volatile txnid_t mti_oldest;
|
||||
volatile uint32_t mti_readers_refresh_flag;
|
||||
|
||||
union {
|
||||
volatile uint32_t mti_readers_refresh_flag;
|
||||
uint64_t align_reader_finished_flag;
|
||||
};
|
||||
#define MDBX_lockinfo_SIZE_B \
|
||||
(sizeof(unsigned) /* mti_numreaders */ + \
|
||||
MDBX_OSAL_LOCK_SIZE /* mti_rmutex */ + sizeof(txnid_t) /* mti_oldest */ + \
|
||||
sizeof(uint32_t) /* mti_readers_refresh_flag */ + \
|
||||
MDBX_OSAL_LOCK_SIZE % sizeof(size_t) /* pad_mti_rmutex */)
|
||||
|
||||
uint8_t pad_align[MDBX_CACHELINE_SIZE - sizeof(uint64_t) * 7];
|
||||
/* cache-line alignment */
|
||||
uint8_t
|
||||
pad_b[MDBX_CACHELINE_SIZE - MDBX_lockinfo_SIZE_B % MDBX_CACHELINE_SIZE];
|
||||
|
||||
MDBX_reader mti_readers[1];
|
||||
|
||||
MDBX_reader __cache_aligned mti_readers[1];
|
||||
} MDBX_lockinfo;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif /* MSVC: Enable aligment */
|
||||
|
||||
#define MDBX_LOCKINFO_WHOLE_SIZE \
|
||||
((sizeof(MDBX_lockinfo) + MDBX_CACHELINE_SIZE - 1) & \
|
||||
@@ -938,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; }
|
||||
|
||||
|
||||
10
src/defs.h
10
src/defs.h
@@ -192,16 +192,6 @@
|
||||
# endif
|
||||
#endif /* __prefetch */
|
||||
|
||||
#ifndef __aligned
|
||||
# if defined(__GNUC__) || __has_attribute(aligned)
|
||||
# define __aligned(N) __attribute__((aligned(N)))
|
||||
# elif defined(_MSC_VER)
|
||||
# define __aligned(N) __declspec(align(N))
|
||||
# else
|
||||
# define __aligned(N)
|
||||
# endif
|
||||
#endif /* __aligned */
|
||||
|
||||
#ifndef __noreturn
|
||||
# if defined(__GNUC__) || __has_attribute(noreturn)
|
||||
# define __noreturn __attribute__((noreturn))
|
||||
|
||||
@@ -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();
|
||||
|
||||
923
src/mdbx.c
923
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) {
|
||||
|
||||
186
src/osal.h
186
src/osal.h
@@ -103,24 +103,47 @@ typedef struct {
|
||||
typedef pthread_mutex_t mdbx_fastmutex_t;
|
||||
#endif /* Platform */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
/* clang-format off */
|
||||
#if defined(HAVE_SYS_STAT_H) || __has_include(<sys/stat.h>)
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if defined(HAVE_SYS_TYPES_H) || __has_include(<sys/types.h>)
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#if defined(HAVE_SYS_FILE_H) || __has_include(<sys/file.h>)
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
/* clang-format on */
|
||||
|
||||
#ifndef SSIZE_MAX
|
||||
#define SSIZE_MAX INTPTR_MAX
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_FILE_H
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
#if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \
|
||||
defined(i486) || defined(__i486) || defined(__i486__) || \
|
||||
defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) || \
|
||||
defined(__i686) || defined(__i686__) || defined(_M_IX86) || \
|
||||
defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || \
|
||||
defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) || \
|
||||
defined(__amd64__) || defined(__amd64) || defined(_M_X64) || \
|
||||
defined(_M_AMD64) || defined(__IA32__) || defined(__INTEL__)
|
||||
#ifndef __ia32__
|
||||
/* LY: define neutral __ia32__ for x86 and x86-64 archs */
|
||||
#define __ia32__ 1
|
||||
#endif /* __ia32__ */
|
||||
#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) || \
|
||||
defined(__amd64) || defined(_M_X64))
|
||||
/* LY: define trusty __amd64__ for all AMD64/x86-64 arch */
|
||||
#define __amd64__ 1
|
||||
#endif /* __amd64__ */
|
||||
#endif /* all x86 */
|
||||
|
||||
#if !defined(UNALIGNED_OK)
|
||||
#if defined(__i386) || defined(__x86_64__) || defined(_M_IX86) || \
|
||||
defined(_M_X64) || defined(i386) || defined(_X86_) || defined(__i386__) || \
|
||||
defined(_X86_64_)
|
||||
#if (defined(__ia32__) || defined(__e2k__) || \
|
||||
defined(__ARM_FEATURE_UNALIGNED)) && \
|
||||
!defined(__ALIGNED__)
|
||||
#define UNALIGNED_OK 1
|
||||
#else
|
||||
#define UNALIGNED_OK 0
|
||||
@@ -135,26 +158,15 @@ typedef pthread_mutex_t mdbx_fastmutex_t;
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Compiler's includes for builtins/intrinsics */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#if _MSC_FULL_VER < 190024215
|
||||
#if _MSC_FULL_VER < 180040629 && defined(_M_IX86)
|
||||
#error Please use Visual Studio 2015 (MSC 19.0) or newer for 32-bit target.
|
||||
#else
|
||||
#pragma message( \
|
||||
"It is recommended to use Visual Studio 2015 (MSC 19.0) or newer.")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
||||
#include <intrin.h>
|
||||
|
||||
#elif __GNUC_PREREQ(4, 4) || defined(__clang__)
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#include <cpuid.h>
|
||||
#if defined(__ia32__) || defined(__e2k__)
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
#elif defined(__INTEL_COMPILER)
|
||||
#include <intrin.h>
|
||||
#endif /* __ia32__ */
|
||||
#if defined(__ia32__)
|
||||
#include <cpuid.h>
|
||||
#endif /* __ia32__ */
|
||||
#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
|
||||
#include <mbarrier.h>
|
||||
#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) && \
|
||||
@@ -173,8 +185,10 @@ typedef pthread_mutex_t mdbx_fastmutex_t;
|
||||
#pragma gcc_extensions
|
||||
#elif defined(__SNC__)
|
||||
/* Sony PS3 - troubles ? */
|
||||
#elif defined(__hppa__) || defined(__hppa)
|
||||
#include <machine/inline.h>
|
||||
#else
|
||||
#error Unknown C compiler, please use GNU C 5.x or newer
|
||||
#error Unsupported C compiler, please use GNU C 4.4 or newer
|
||||
#endif /* Compiler */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
@@ -183,45 +197,70 @@ typedef pthread_mutex_t mdbx_fastmutex_t;
|
||||
#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || \
|
||||
!defined(__ORDER_BIG_ENDIAN__)
|
||||
|
||||
#if defined(HAVE_ENDIAN_H)
|
||||
/* *INDENT-OFF* */
|
||||
/* clang-format off */
|
||||
#if defined(__GLIBC__) || defined(__GNU_LIBRARY__) || defined(__ANDROID__) || \
|
||||
defined(HAVE_ENDIAN_H) || __has_include(<endian.h>)
|
||||
#include <endian.h>
|
||||
#elif defined(HAVE_SYS_PARAM_H)
|
||||
#include <sys/param.h> /* for endianness */
|
||||
#elif defined(HAVE_NETINET_IN_H) && defined(HAVE_RESOLV_H)
|
||||
#include <netinet/in.h>
|
||||
#include <resolv.h> /* defines BYTE_ORDER on HPUX and Solaris */
|
||||
#endif
|
||||
#elif defined(__APPLE__) || defined(__MACH__) || defined(__OpenBSD__) || \
|
||||
defined(HAVE_MACHINE_ENDIAN_H) || __has_include(<machine/endian.h>)
|
||||
#include <machine/endian.h>
|
||||
#elif defined(HAVE_SYS_ISA_DEFS_H) || __has_include(<sys/isa_defs.h>)
|
||||
#include <sys/isa_defs.h>
|
||||
#elif (defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_ENDIAN_H)) || \
|
||||
(__has_include(<sys/types.h>) && __has_include(<sys/endian.h>))
|
||||
#include <sys/endian.h>
|
||||
#include <sys/types.h>
|
||||
#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
|
||||
defined(__NETBSD__) || defined(__NetBSD__) || \
|
||||
defined(HAVE_SYS_PARAM_H) || __has_include(<sys/param.h>)
|
||||
#include <sys/param.h>
|
||||
#endif /* OS */
|
||||
/* *INDENT-ON* */
|
||||
/* clang-format on */
|
||||
|
||||
#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
|
||||
#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN
|
||||
#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN
|
||||
#define __BYTE_ORDER__ __BYTE_ORDER
|
||||
#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
|
||||
#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN
|
||||
#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN
|
||||
#define __BYTE_ORDER__ _BYTE_ORDER
|
||||
#else
|
||||
#define __ORDER_LITTLE_ENDIAN__ 1234
|
||||
#define __ORDER_BIG_ENDIAN__ 4321
|
||||
#if defined(__LITTLE_ENDIAN__) || defined(_LITTLE_ENDIAN) || \
|
||||
|
||||
#if defined(__LITTLE_ENDIAN__) || \
|
||||
(defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) || \
|
||||
defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
|
||||
defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) || \
|
||||
defined(__i386) || defined(__x86_64__) || defined(_M_IX86) || \
|
||||
defined(_M_X64) || defined(i386) || defined(_X86_) || defined(__i386__) || \
|
||||
defined(_X86_64_) || defined(_M_ARM) || defined(_M_ARM64) || \
|
||||
defined(__e2k__)
|
||||
defined(_M_ARM) || defined(_M_ARM64) || defined(__e2k__) || \
|
||||
defined(__elbrus_4c__) || defined(__elbrus_8c__) || defined(__bfin__) || \
|
||||
defined(__BFIN__) || defined(__ia64__) || defined(_IA64) || \
|
||||
defined(__IA64__) || defined(__ia64) || defined(_M_IA64) || \
|
||||
defined(__itanium__) || defined(__ia32__) || defined(__CYGWIN__) || \
|
||||
defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) || \
|
||||
defined(__WINDOWS__)
|
||||
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
|
||||
#elif defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) || defined(__ARMEB__) || \
|
||||
defined(__THUMBEB__) || defined(__AARCH64EB__) || defined(__MIPSEB__) || \
|
||||
defined(_MIPSEB) || defined(__MIPSEB) || defined(_M_IA64)
|
||||
|
||||
#elif defined(__BIG_ENDIAN__) || \
|
||||
(defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) || \
|
||||
defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
|
||||
defined(__MIPSEB__) || defined(_MIPSEB) || defined(__MIPSEB) || \
|
||||
defined(__m68k__) || defined(M68000) || defined(__hppa__) || \
|
||||
defined(__hppa) || defined(__HPPA__) || defined(__sparc__) || \
|
||||
defined(__sparc) || defined(__370__) || defined(__THW_370__) || \
|
||||
defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__)
|
||||
#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
|
||||
|
||||
#else
|
||||
#error __BYTE_ORDER__ should be defined.
|
||||
#endif
|
||||
#endif /* Arch */
|
||||
|
||||
#endif
|
||||
#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
|
||||
|
||||
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ && \
|
||||
__BYTE_ORDER__ != __ORDER_BIG_ENDIAN__
|
||||
#error Unsupported byte order.
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Memory/Compiler barriers, cache coherence */
|
||||
|
||||
@@ -286,17 +325,14 @@ static __inline void mdbx_memory_barrier(void) {
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Cache coherence and invalidation */
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(_M_AMD64) || \
|
||||
defined(_M_IX86) || defined(__i386) || defined(__amd64) || \
|
||||
defined(i386) || defined(__x86_64) || defined(_AMD64_) || defined(_M_X64)
|
||||
#define MDBX_CACHE_IS_COHERENT 1
|
||||
#elif defined(__hppa) || defined(__hppa__)
|
||||
#define MDBX_CACHE_IS_COHERENT 1
|
||||
#endif
|
||||
|
||||
#ifndef MDBX_CACHE_IS_COHERENT
|
||||
#if defined(__ia32__) || defined(__e2k__) || defined(__hppa) || \
|
||||
defined(__hppa__)
|
||||
#define MDBX_CACHE_IS_COHERENT 1
|
||||
#else
|
||||
#define MDBX_CACHE_IS_COHERENT 0
|
||||
#endif
|
||||
#endif /* MDBX_CACHE_IS_COHERENT */
|
||||
|
||||
#ifndef MDBX_CACHELINE_SIZE
|
||||
#if defined(SYSTEM_CACHE_ALIGNMENT_SIZE)
|
||||
@@ -308,29 +344,29 @@ static __inline void mdbx_memory_barrier(void) {
|
||||
#endif
|
||||
#endif /* MDBX_CACHELINE_SIZE */
|
||||
|
||||
#ifndef __cache_aligned
|
||||
#define __cache_aligned __aligned(MDBX_CACHELINE_SIZE)
|
||||
#endif
|
||||
|
||||
#if MDBX_CACHE_IS_COHERENT
|
||||
#define mdbx_coherent_barrier() mdbx_compiler_barrier()
|
||||
#else
|
||||
#define mdbx_coherent_barrier() mdbx_memory_barrier()
|
||||
#endif
|
||||
|
||||
#if defined(__mips) && defined(__linux)
|
||||
#if defined(__mips) || defined(__mips__) || defined(__mips64) || \
|
||||
defined(__mips64) || defined(_M_MRX000) || defined(_MIPS_)
|
||||
/* Only MIPS has explicit cache control */
|
||||
#include <asm/cachectl.h>
|
||||
#include <sys/cachectl.h>
|
||||
#endif
|
||||
|
||||
static __inline void mdbx_invalidate_cache(void *addr, size_t nbytes) {
|
||||
mdbx_coherent_barrier();
|
||||
#if defined(__mips) && defined(__linux)
|
||||
#if defined(__mips) || defined(__mips__) || defined(__mips64) || \
|
||||
defined(__mips64) || defined(_M_MRX000) || defined(_MIPS_)
|
||||
#if defined(DCACHE)
|
||||
/* MIPS has cache coherency issues.
|
||||
* Note: for any nbytes >= on-chip cache size, entire is flushed. */
|
||||
cacheflush(addr, nbytes, DCACHE);
|
||||
#elif defined(_M_MRX000) || defined(_MIPS_)
|
||||
#else
|
||||
#error "Sorry, cacheflush() for MIPS not implemented"
|
||||
#endif /* __mips__ */
|
||||
#else
|
||||
/* LY: assume no relevant mmap/dcache issues. */
|
||||
(void)addr;
|
||||
@@ -433,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);
|
||||
@@ -504,7 +536,13 @@ void mdbx_osal_jitter(bool tiny);
|
||||
#else
|
||||
#define MDBX_OSAL_LOCK pthread_mutex_t
|
||||
#define MDBX_OSAL_LOCK_SIGN UINT32_C(0x8017)
|
||||
#endif
|
||||
#endif /* MDBX_OSAL_LOCK */
|
||||
|
||||
#ifdef MDBX_OSAL_LOCK
|
||||
#define MDBX_OSAL_LOCK_SIZE sizeof(MDBX_OSAL_LOCK)
|
||||
#else
|
||||
#define MDBX_OSAL_LOCK_SIZE 0
|
||||
#endif /* MDBX_OSAL_LOCK_SIZE */
|
||||
|
||||
int mdbx_lck_init(MDBX_env *env);
|
||||
|
||||
@@ -516,8 +554,8 @@ void mdbx_lck_destroy(MDBX_env *env);
|
||||
int mdbx_rdt_lock(MDBX_env *env);
|
||||
void mdbx_rdt_unlock(MDBX_env *env);
|
||||
|
||||
int mdbx_txn_lock(MDBX_env *env, bool dontwait);
|
||||
void mdbx_txn_unlock(MDBX_env *env);
|
||||
LIBMDBX_API int mdbx_txn_lock(MDBX_env *env, bool dontwait);
|
||||
LIBMDBX_API void mdbx_txn_unlock(MDBX_env *env);
|
||||
|
||||
int mdbx_rpid_set(MDBX_env *env);
|
||||
int mdbx_rpid_clear(MDBX_env *env);
|
||||
|
||||
@@ -77,7 +77,7 @@ int exclusive = 2;
|
||||
int envflags = MDBX_RDONLY;
|
||||
|
||||
MDBX_env *env;
|
||||
MDBX_txn *txn, *locktxn;
|
||||
MDBX_txn *txn;
|
||||
MDBX_envinfo envinfo;
|
||||
MDBX_stat envstat;
|
||||
size_t maxkeysize, userdb_count, skipped_subdb;
|
||||
@@ -763,6 +763,7 @@ int main(int argc, char *argv[]) {
|
||||
char *envname;
|
||||
int problems_maindb = 0, problems_freedb = 0, problems_meta = 0;
|
||||
int dont_traversal = 0;
|
||||
bool locked = false;
|
||||
|
||||
double elapsed;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
@@ -836,8 +837,8 @@ int main(int argc, char *argv[]) {
|
||||
#endif /* !WINDOWS */
|
||||
|
||||
envname = argv[optind];
|
||||
print("Running mdbx_chk for '%s' in %s mode...\n", envname,
|
||||
(envflags & MDBX_RDONLY) ? "read-only" : "write-lock");
|
||||
print("Running mdbx_chk for %s in 'read-%s' mode...\n", envname,
|
||||
(envflags & MDBX_RDONLY) ? "only" : "write");
|
||||
fflush(NULL);
|
||||
|
||||
rc = mdbx_env_create(&env);
|
||||
@@ -862,13 +863,19 @@ int main(int argc, char *argv[]) {
|
||||
if (verbose)
|
||||
print(" - %s mode\n", exclusive ? "monopolistic" : "cooperative");
|
||||
|
||||
if (!(envflags & MDBX_RDONLY)) {
|
||||
rc = mdbx_txn_begin(env, NULL, 0, &locktxn);
|
||||
if (rc) {
|
||||
error("mdbx_txn_begin(lock-write) failed, error %d %s\n", rc,
|
||||
mdbx_strerror(rc));
|
||||
if ((envflags & MDBX_RDONLY) == 0) {
|
||||
rc = mdbx_txn_lock(env, false);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
error("mdbx_txn_lock failed, error %d %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
locked = true;
|
||||
}
|
||||
|
||||
rc = mdbx_txn_begin(env, NULL, MDBX_RDONLY, &txn);
|
||||
if (rc) {
|
||||
error("mdbx_txn_begin() failed, error %d %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
rc = mdbx_env_get_maxkeysize(env);
|
||||
@@ -879,13 +886,6 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
maxkeysize = rc;
|
||||
|
||||
rc = mdbx_txn_begin(env, NULL, MDBX_RDONLY, &txn);
|
||||
if (rc) {
|
||||
error("mdbx_txn_begin(read-only) failed, error %d %s\n", rc,
|
||||
mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
rc = mdbx_env_info(env, &envinfo, sizeof(envinfo));
|
||||
if (rc) {
|
||||
error("mdbx_env_info failed, error %d %s\n", rc, mdbx_strerror(rc));
|
||||
@@ -950,14 +950,14 @@ int main(int argc, char *argv[]) {
|
||||
if (verbose)
|
||||
print(" - performs full check recent-txn-id with meta-pages\n");
|
||||
problems_meta += check_meta_head(true);
|
||||
} else if (locktxn) {
|
||||
} else if (locked) {
|
||||
if (verbose)
|
||||
print(" - performs lite check recent-txn-id with meta-pages (not a "
|
||||
"monopolistic mode)\n");
|
||||
problems_meta += check_meta_head(false);
|
||||
} else if (verbose) {
|
||||
print(" - skip check recent-txn-id with meta-pages (monopolistic or "
|
||||
"write-lock mode only)\n");
|
||||
"read-write mode only)\n");
|
||||
}
|
||||
|
||||
if (!dont_traversal) {
|
||||
@@ -1079,7 +1079,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
if (problems_maindb == 0 && problems_freedb == 0) {
|
||||
if (!dont_traversal && (exclusive || locktxn)) {
|
||||
if (!dont_traversal && (exclusive || (envflags & MDBX_RDONLY) == 0)) {
|
||||
if (walk.pgcount != lastpgno - freedb_pages) {
|
||||
error("used pages mismatch (%" PRIu64 " != %" PRIu64 ")\n",
|
||||
walk.pgcount, lastpgno - freedb_pages);
|
||||
@@ -1090,7 +1090,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
} else if (verbose) {
|
||||
print(" - skip check used and gc pages (btree-traversal with "
|
||||
"monopolistic or write-lock mode only)\n");
|
||||
"monopolistic or read-write mode only)\n");
|
||||
}
|
||||
|
||||
if (!process_db(MAIN_DBI, NULL, handle_maindb, true)) {
|
||||
@@ -1102,8 +1102,8 @@ int main(int argc, char *argv[]) {
|
||||
bailout:
|
||||
if (txn)
|
||||
mdbx_txn_abort(txn);
|
||||
if (locktxn)
|
||||
mdbx_txn_abort(locktxn);
|
||||
if (locked)
|
||||
mdbx_txn_unlock(env);
|
||||
if (env)
|
||||
mdbx_env_close(env);
|
||||
fflush(NULL);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -76,14 +76,6 @@
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
#include "../mdbx.h"
|
||||
#include "../src/defs.h"
|
||||
#include "../src/osal.h"
|
||||
|
||||
@@ -278,8 +278,6 @@ void dump(const char *title) {
|
||||
logging::local_suffix indent(title);
|
||||
|
||||
for (auto i = global::actors.begin(); i != global::actors.end(); ++i) {
|
||||
const std::string tableid =
|
||||
i->space_id ? "MAINDB" : ("SUB#" + std::to_string(i->space_id));
|
||||
log_info("#%u, testcase %s, space_id/table %u\n", i->actor_id,
|
||||
testcase2str(i->testcase), i->space_id);
|
||||
indent.push();
|
||||
@@ -326,6 +324,11 @@ void dump(const char *title) {
|
||||
else
|
||||
log_info("no-delay\n");
|
||||
|
||||
if (i->params.inject_writefaultn)
|
||||
log_info("inject-writefault on %u ops\n", i->params.inject_writefaultn);
|
||||
else
|
||||
log_info("no-inject-writefault\n");
|
||||
|
||||
log_info("limits: readers %u, tables %u\n", i->params.max_readers,
|
||||
i->params.max_tables);
|
||||
|
||||
|
||||
@@ -218,6 +218,7 @@ struct actor_params_pod {
|
||||
|
||||
unsigned delaystart;
|
||||
unsigned waitfor_nops;
|
||||
unsigned inject_writefaultn;
|
||||
|
||||
unsigned max_readers;
|
||||
unsigned max_tables;
|
||||
@@ -244,7 +245,7 @@ void dump(const char *title = "config-dump: ");
|
||||
struct actor_params : public config::actor_params_pod {
|
||||
std::string pathname_log;
|
||||
std::string pathname_db;
|
||||
void set_defaults(void);
|
||||
void set_defaults(const std::string &tmpdir);
|
||||
};
|
||||
|
||||
struct actor_config : public config::actor_config_pod {
|
||||
|
||||
@@ -285,3 +285,5 @@ void log_trouble(const char *where, const char *what, int errnum) {
|
||||
bool log_enabled(const logging::loglevel priority) {
|
||||
return (priority >= logging::level);
|
||||
}
|
||||
|
||||
void log_flush(void) { fflushall(); }
|
||||
|
||||
@@ -81,6 +81,7 @@ void __printf_args(1, 2) log_warning(const char *msg, ...);
|
||||
void __printf_args(1, 2) log_error(const char *msg, ...);
|
||||
|
||||
void log_trouble(const char *where, const char *what, int errnum);
|
||||
void log_flush(void);
|
||||
bool log_enabled(const logging::loglevel priority);
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
17
test/main.cc
17
test/main.cc
@@ -22,21 +22,16 @@ void __noreturn usage(void) {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void actor_params::set_defaults(void) {
|
||||
void actor_params::set_defaults(const std::string &tmpdir) {
|
||||
pathname_log = "";
|
||||
loglevel =
|
||||
#ifdef NDEBUG
|
||||
logging::notice;
|
||||
logging::info;
|
||||
#else
|
||||
logging::trace;
|
||||
#endif
|
||||
|
||||
pathname_db =
|
||||
#ifdef __linux__
|
||||
"/dev/shm/test_tmpdb.mdbx";
|
||||
#else
|
||||
"test_tmpdb.mdbx";
|
||||
#endif
|
||||
pathname_db = tmpdir + "mdbx-test.db";
|
||||
mode_flags = MDBX_NOSUBDIR | MDBX_WRITEMAP | MDBX_MAPASYNC | MDBX_NORDAHEAD |
|
||||
MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_LIFORECLAIM;
|
||||
table_flags = MDBX_DUPSORT;
|
||||
@@ -65,6 +60,7 @@ void actor_params::set_defaults(void) {
|
||||
|
||||
delaystart = 0;
|
||||
waitfor_nops = 0;
|
||||
inject_writefaultn = 0;
|
||||
|
||||
drop_table = false;
|
||||
|
||||
@@ -135,7 +131,7 @@ int main(int argc, char *const argv[]) {
|
||||
: EXIT_FAILURE;
|
||||
|
||||
actor_params params;
|
||||
params.set_defaults();
|
||||
params.set_defaults(osal_tempdir());
|
||||
global::config::dump_config = true;
|
||||
logging::setup((logging::loglevel)params.loglevel, "main");
|
||||
unsigned last_space_id = 0;
|
||||
@@ -219,6 +215,9 @@ int main(int argc, char *const argv[]) {
|
||||
if (config::parse_option(argc, argv, narg, "wait4ops", params.waitfor_nops,
|
||||
config::decimal))
|
||||
continue;
|
||||
if (config::parse_option(argc, argv, narg, "inject-writefault",
|
||||
params.inject_writefaultn, config::decimal))
|
||||
continue;
|
||||
if (config::parse_option(argc, argv, narg, "drop", params.drop_table))
|
||||
continue;
|
||||
if (config::parse_option(argc, argv, narg, "dump-config",
|
||||
|
||||
@@ -272,3 +272,22 @@ void osal_udelay(unsigned us) {
|
||||
}
|
||||
|
||||
bool osal_istty(int fd) { return isatty(fd) == 1; }
|
||||
|
||||
std::string osal_tempdir(void) {
|
||||
const char *tempdir = getenv("TMPDIR");
|
||||
if (!tempdir)
|
||||
tempdir = getenv("TMP");
|
||||
if (!tempdir)
|
||||
tempdir = getenv("TEMPDIR");
|
||||
if (!tempdir)
|
||||
tempdir = getenv("TEMP");
|
||||
if (tempdir) {
|
||||
std::string dir(tempdir);
|
||||
if (!dir.empty() && dir.at(dir.length() - 1) != '/')
|
||||
dir.append("/");
|
||||
return dir;
|
||||
}
|
||||
if (access("/dev/shm/", R_OK | W_OK | X_OK) == 0)
|
||||
return "/dev/shm/";
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -305,3 +305,9 @@ void osal_udelay(unsigned us) {
|
||||
}
|
||||
|
||||
bool osal_istty(int fd) { return _isatty(fd) != 0; }
|
||||
|
||||
std::string osal_tempdir(void) {
|
||||
char buf[MAX_PATH + 1];
|
||||
DWORD len = GetTempPathA(sizeof(buf), buf);
|
||||
return std::string(buf, len);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ int osal_delay(unsigned seconds);
|
||||
void osal_udelay(unsigned us);
|
||||
void osal_yield(void);
|
||||
bool osal_istty(int fd);
|
||||
std::string osal_tempdir(void);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifndef STDIN_FILENO
|
||||
|
||||
24
test/test.cc
24
test/test.cc
@@ -123,7 +123,7 @@ void testcase::db_prepare() {
|
||||
if (config.params.loglevel <= logging::verbose)
|
||||
mdbx_dbg_opts |= MDBX_DBG_PRINT;
|
||||
int rc = mdbx_setup_debug(mdbx_dbg_opts, mdbx_logger);
|
||||
log_info("set mdbx debug-opts: 0x%02x", rc);
|
||||
log_trace("set mdbx debug-opts: 0x%02x", rc);
|
||||
|
||||
MDBX_env *env = nullptr;
|
||||
rc = mdbx_env_create(&env);
|
||||
@@ -204,6 +204,7 @@ void testcase::txn_end(bool abort) {
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
failure_perror("mdbx_txn_abort()", rc);
|
||||
} else {
|
||||
txn_inject_writefault(txn);
|
||||
int rc = mdbx_txn_commit(txn);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
failure_perror("mdbx_txn_commit()", rc);
|
||||
@@ -218,6 +219,27 @@ void testcase::txn_restart(bool abort, bool readonly, unsigned flags) {
|
||||
txn_begin(readonly, flags);
|
||||
}
|
||||
|
||||
void testcase::txn_inject_writefault(void) {
|
||||
if (txn_guard)
|
||||
txn_inject_writefault(txn_guard.get());
|
||||
}
|
||||
|
||||
void testcase::txn_inject_writefault(MDBX_txn *txn) {
|
||||
if (config.params.inject_writefaultn && txn) {
|
||||
if (config.params.inject_writefaultn <= nops_completed &&
|
||||
(mdbx_txn_flags(txn) & MDBX_RDONLY) == 0) {
|
||||
log_info("== txn_inject_writefault(): got %u nops or more, inject FAULT",
|
||||
config.params.inject_writefaultn);
|
||||
log_flush();
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
|
||||
TerminateProcess(GetCurrentProcess(), 42);
|
||||
#else
|
||||
raise(SIGKILL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool testcase::wait4start() {
|
||||
if (config.wait4id) {
|
||||
log_trace(">> wait4start(%u)", config.wait4id);
|
||||
|
||||
@@ -107,6 +107,8 @@ protected:
|
||||
void txn_begin(bool readonly, unsigned flags = 0);
|
||||
void txn_end(bool abort);
|
||||
void txn_restart(bool abort, bool readonly, unsigned flags = 0);
|
||||
void txn_inject_writefault(void);
|
||||
void txn_inject_writefault(MDBX_txn *txn);
|
||||
void fetch_canary();
|
||||
void update_canary(uint64_t increment);
|
||||
void kick_progress(bool active) const;
|
||||
|
||||
134
test/utils.cc
134
test/utils.cc
@@ -14,44 +14,10 @@
|
||||
|
||||
#include "test.h"
|
||||
#include <float.h>
|
||||
#ifdef HAVE_IEEE754_H
|
||||
#if defined(HAVE_IEEE754_H) || __has_include(<ieee754.h>)
|
||||
#include <ieee754.h>
|
||||
#endif
|
||||
|
||||
/* Compiler's includes for builtins/intrinsics */
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
||||
#include <intrin.h>
|
||||
#elif __GNUC_PREREQ(4, 4) || defined(__clang__)
|
||||
#if defined(__ia32__) || defined(__e2k__)
|
||||
#include <x86intrin.h>
|
||||
#endif /* __ia32__ */
|
||||
#if defined(__ia32__)
|
||||
#include <cpuid.h>
|
||||
#endif /* __ia32__ */
|
||||
#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
|
||||
#include <mbarrier.h>
|
||||
#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) && \
|
||||
(defined(HP_IA64) || defined(__ia64))
|
||||
#include <machine/sys/inline.h>
|
||||
#elif defined(__IBMC__) && defined(__powerpc)
|
||||
#include <atomic.h>
|
||||
#elif defined(_AIX)
|
||||
#include <builtins.h>
|
||||
#include <sys/atomic_op.h>
|
||||
#elif (defined(__osf__) && defined(__DECC)) || defined(__alpha)
|
||||
#include <c_asm.h>
|
||||
#include <machine/builtins.h>
|
||||
#elif defined(__MWERKS__)
|
||||
/* CodeWarrior - troubles ? */
|
||||
#pragma gcc_extensions
|
||||
#elif defined(__SNC__)
|
||||
/* Sony PS3 - troubles ? */
|
||||
#elif defined(__hppa__) || defined(__hppa)
|
||||
#include <machine/inline.h>
|
||||
#else
|
||||
#error Unsupported C compiler, please use GNU C 4.4 or newer
|
||||
#endif /* Compiler */
|
||||
|
||||
std::string format(const char *fmt, ...) {
|
||||
va_list ap, ones;
|
||||
va_start(ap, fmt);
|
||||
@@ -127,8 +93,22 @@ bool hex2data(const char *hex_begin, const char *hex_end, void *ptr,
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/* TODO: replace my 'libmera' fomr t1ha. */
|
||||
uint64_t entropy_ticks(void) {
|
||||
#if defined(EMSCRIPTEN)
|
||||
return (uint64_t)emscripten_get_now();
|
||||
#endif /* EMSCRIPTEN */
|
||||
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
return mach_absolute_time();
|
||||
#endif /* defined(__APPLE__) || defined(__MACH__) */
|
||||
|
||||
#if defined(__sun__) || defined(__sun)
|
||||
return gethrtime();
|
||||
#endif /* __sun__ */
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
|
||||
#if defined(__ia64__)
|
||||
uint64_t ticks;
|
||||
__asm __volatile("mov %0=ar.itc" : "=r"(ticks));
|
||||
@@ -145,29 +125,81 @@ uint64_t entropy_ticks(void) {
|
||||
uint64_t ticks;
|
||||
__asm __volatile("rpcc %0" : "=r"(ticks));
|
||||
return ticks;
|
||||
#elif defined(__sparc_v9__)
|
||||
uint64_t ticks;
|
||||
__asm __volatile("rd %%tick, %0" : "=r"(ticks));
|
||||
return ticks;
|
||||
#elif defined(__powerpc64__) || defined(__ppc64__)
|
||||
#elif defined(__sparc__) || defined(__sparc) || defined(__sparc64__) || \
|
||||
defined(__sparc64) || defined(__sparc_v8plus__) || \
|
||||
defined(__sparc_v8plus) || defined(__sparc_v8plusa__) || \
|
||||
defined(__sparc_v8plusa) || defined(__sparc_v9__) || defined(__sparc_v9)
|
||||
|
||||
union {
|
||||
uint64_t u64;
|
||||
struct {
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
uint32_t h, l;
|
||||
#else
|
||||
uint32_t l, h;
|
||||
#endif
|
||||
} u32;
|
||||
} cycles;
|
||||
|
||||
#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || \
|
||||
defined(__sparc_v9__) || defined(__sparc_v8plus) || \
|
||||
defined(__sparc_v8plusa) || defined(__sparc_v9)
|
||||
|
||||
#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul || \
|
||||
defined(__sparc64__) || defined(__sparc64)
|
||||
__asm __volatile("rd %%tick, %0" : "=r"(cycles.u64));
|
||||
#else
|
||||
__asm __volatile("rd %%tick, %1; srlx %1, 32, %0"
|
||||
: "=r"(cycles.u32.h), "=r"(cycles.u32.l));
|
||||
#endif /* __sparc64__ */
|
||||
|
||||
#else
|
||||
__asm __volatile(".byte 0x83, 0x41, 0x00, 0x00; mov %%g1, %0"
|
||||
: "=r"(cycles.u64)
|
||||
:
|
||||
: "%g1");
|
||||
#endif /* __sparc8plus__ || __sparc_v9__ */
|
||||
return cycles.u64;
|
||||
|
||||
#elif (defined(__powerpc64__) || defined(__ppc64__) || defined(__ppc64) || \
|
||||
defined(__powerpc64))
|
||||
uint64_t ticks;
|
||||
__asm __volatile("mfspr %0, 268" : "=r"(ticks));
|
||||
return ticks;
|
||||
#elif defined(__ppc__) || defined(__powerpc__)
|
||||
unsigned tbl, tbu;
|
||||
|
||||
/* LY: Here not a problem if a high-part (tbu)
|
||||
* would been updated during reading. */
|
||||
__asm __volatile("mftb %0" : "=r"(tbl));
|
||||
__asm __volatile("mftbu %0" : "=r"(tbu));
|
||||
|
||||
return (((uin64_t)tbu0) << 32) | tbl;
|
||||
#elif (defined(__powerpc__) || defined(__ppc__) || defined(__powerpc) || \
|
||||
defined(__ppc))
|
||||
#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul
|
||||
uint64_t ticks;
|
||||
__asm __volatile("mftb %0" : "=r"(ticks));
|
||||
*now = ticks;
|
||||
#else
|
||||
uint64_t ticks;
|
||||
uint32_t low, high_before, high_after;
|
||||
__asm __volatile("mftbu %0; mftb %1; mftbu %2"
|
||||
: "=r"(high_before), "=r"(low), "=r"(high_after));
|
||||
ticks = (uint64_t)high_after << 32;
|
||||
ticks |= low & /* zeroes if high part has changed */
|
||||
~(high_before - high_after);
|
||||
#endif
|
||||
#elif defined(__aarch64__) || (defined(__ARM_ARCH) && __ARM_ARCH > 7)
|
||||
uint64_t virtual_timer;
|
||||
__asm __volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer));
|
||||
return virtual_timer;
|
||||
#elif defined(__ARM_ARCH) && __ARM_ARCH > 5 && __ARM_ARCH < 8
|
||||
unsigned long pmccntr;
|
||||
__asm __volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr));
|
||||
return pmccntr;
|
||||
#elif defined(__mips__) || defined(__mips) || defined(_R4000)
|
||||
unsigned count;
|
||||
__asm __volatile("rdhwr %0, $2" : "=r"(count));
|
||||
return count;
|
||||
#endif /* arch selector */
|
||||
#endif /* __GNUC__ || __clang__ */
|
||||
|
||||
#if defined(__e2k__) || defined(__elbrus__) || defined(_M_IX86) || \
|
||||
defined(_M_X64) || defined(__x86_64__) || defined(__i386__)
|
||||
#if defined(__e2k__) || defined(__ia32__)
|
||||
return __rdtsc();
|
||||
#elif defined(_M_ARM)
|
||||
return __rdpmccntr64();
|
||||
#elif defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
|
||||
LARGE_INTEGER PerformanceCount;
|
||||
if (QueryPerformanceCounter(&PerformanceCount))
|
||||
|
||||
30
test/utils.h
30
test/utils.h
@@ -17,33 +17,8 @@
|
||||
|
||||
#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || \
|
||||
!defined(__ORDER_BIG_ENDIAN__)
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/param.h> /* for endianness */
|
||||
#endif
|
||||
#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
|
||||
#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN
|
||||
#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN
|
||||
#define __BYTE_ORDER__ __BYTE_ORDER
|
||||
#else
|
||||
#define __ORDER_LITTLE_ENDIAN__ 1234
|
||||
#define __ORDER_BIG_ENDIAN__ 4321
|
||||
#if defined(__LITTLE_ENDIAN__) || defined(_LITTLE_ENDIAN) || \
|
||||
defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
|
||||
defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) || \
|
||||
defined(__i386) || defined(__x86_64__) || defined(_M_IX86) || \
|
||||
defined(_M_X64) || defined(i386) || defined(_X86_) || defined(__i386__) || \
|
||||
defined(_X86_64_) || defined(_M_ARM) || defined(_M_ARM64) || \
|
||||
defined(__e2k__)
|
||||
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
|
||||
#elif defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) || defined(__ARMEB__) || \
|
||||
defined(__THUMBEB__) || defined(__AARCH64EB__) || defined(__MIPSEB__) || \
|
||||
defined(_MIPSEB) || defined(__MIPSEB) || defined(_M_IA64)
|
||||
#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
|
||||
#else
|
||||
#error __BYTE_ORDER__ should be defined.
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ && \
|
||||
__BYTE_ORDER__ != __ORDER_BIG_ENDIAN__
|
||||
@@ -274,7 +249,7 @@ static __inline void memory_barrier(void) {
|
||||
#elif defined(__INTEL_COMPILER) /* LY: Intel Compiler may mimic GCC and MSC */
|
||||
#if defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
|
||||
__mf();
|
||||
#elif defined(__i386__) || defined(__x86_64__)
|
||||
#elif defined(__ia32__)
|
||||
_mm_mfence();
|
||||
#else
|
||||
#error "Unknown target for Intel Compiler, please report to us."
|
||||
@@ -293,8 +268,7 @@ static __inline void memory_barrier(void) {
|
||||
}
|
||||
|
||||
static __inline void cpu_relax() {
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || \
|
||||
defined(_M_X64)
|
||||
#if defined(__ia32__)
|
||||
_mm_pause();
|
||||
#elif defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) || \
|
||||
defined(YieldProcessor)
|
||||
|
||||
Reference in New Issue
Block a user