mirror of
https://github.com/isar/libmdbx.git
synced 2025-12-15 04:32:21 +08:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
65
Makefile
65
Makefile
@@ -23,23 +23,21 @@ suffix ?=
|
||||
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
XCFLAGS ?= -DNDEBUG=1 -DMDBX_DEBUG=0 -DLIBMDBX_EXPORTS=1
|
||||
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
|
||||
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
|
||||
|
||||
XCFLAGS ?= -DNDEBUG=1 -DMDBX_DEBUG=0 -DLIBMDBX_EXPORTS=1
|
||||
CFLAGS += -D_GNU_SOURCE=1 -std=gnu11 -pthread $(XCFLAGS)
|
||||
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 ?= $(LDFLAGS) -static
|
||||
|
||||
# LY: just for benchmarking
|
||||
IOARENA ?= $(shell \
|
||||
@@ -90,6 +88,12 @@ clean:
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
define core-rule
|
||||
$(patsubst %.c,%.o,$(1)): $(1) $(CORE_INC) mdbx.h Makefile
|
||||
$(CC) $(CFLAGS) -c $(1) -o $$@
|
||||
@@ -111,10 +115,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 $@
|
||||
$(CXX) $(CXXFLAGS) $^ $(EXE_LDFLAGS) -o $@
|
||||
|
||||
###############################################################################
|
||||
|
||||
ifneq ($(wildcard $(IOARENA)),)
|
||||
|
||||
@@ -163,6 +169,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 +186,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
|
||||
|
||||
@@ -233,7 +233,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
|
||||
@@ -339,7 +339,7 @@ Improvements over LMDB
|
||||
This allows to minimize reclaim loop and make it execution time independent from 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.
|
||||
|
||||
@@ -378,7 +378,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.
|
||||
@@ -419,7 +419,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.
|
||||
|
||||
2
TODO.md
2
TODO.md
@@ -21,7 +21,7 @@
|
||||
Тесты
|
||||
=====
|
||||
- [ ] Тестирование поддержки lockless-режима.
|
||||
- [ ] Додумать имя и размещение тестовой БД по-умолчанию.
|
||||
- [x] Додумать имя и размещение тестовой БД по-умолчанию.
|
||||
- [ ] Реализовать cleanup в тесте.
|
||||
- [ ] usage для теста.
|
||||
- [ ] Логирование в файл, плюс более полный progress bar.
|
||||
|
||||
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
|
||||
|
||||
102
src/bits.h
102
src/bits.h
@@ -25,7 +25,7 @@
|
||||
|
||||
/* Features under development */
|
||||
#ifndef MDBX_DEVEL
|
||||
# define MDBX_DEVEL 1
|
||||
# define MDBX_DEVEL 0
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
@@ -55,6 +55,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 +90,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"
|
||||
|
||||
@@ -249,7 +253,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 +411,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) & \
|
||||
|
||||
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))
|
||||
|
||||
181
src/mdbx.c
181
src/mdbx.c
@@ -37,6 +37,117 @@
|
||||
|
||||
#include "./bits.h"
|
||||
|
||||
/* LY: temporary workaround for Elbrus's memcmp() bug. */
|
||||
#if defined(__e2k__) && !__GLIBC_PREREQ(2, 24)
|
||||
int __hot mdbx_e2k_memcmp_bug_workaround(const void *s1, const void *s2,
|
||||
size_t n) {
|
||||
if (unlikely(n > 42
|
||||
/* LY: align followed access if reasonable possible */ &&
|
||||
(((uintptr_t)s1) & 7) != 0 &&
|
||||
(((uintptr_t)s1) & 7) == (((uintptr_t)s2) & 7))) {
|
||||
if (((uintptr_t)s1) & 1) {
|
||||
const int diff = *(uint8_t *)s1 - *(uint8_t *)s2;
|
||||
if (diff)
|
||||
return diff;
|
||||
s1 = (char *)s1 + 1;
|
||||
s2 = (char *)s2 + 1;
|
||||
n -= 1;
|
||||
}
|
||||
|
||||
if (((uintptr_t)s1) & 2) {
|
||||
const uint16_t a = *(uint16_t *)s1;
|
||||
const uint16_t b = *(uint16_t *)s2;
|
||||
if (likely(a != b))
|
||||
return (__builtin_bswap16(a) > __builtin_bswap16(b)) ? 1 : -1;
|
||||
s1 = (char *)s1 + 2;
|
||||
s2 = (char *)s2 + 2;
|
||||
n -= 2;
|
||||
}
|
||||
|
||||
if (((uintptr_t)s1) & 4) {
|
||||
const uint32_t a = *(uint32_t *)s1;
|
||||
const uint32_t b = *(uint32_t *)s2;
|
||||
if (likely(a != b))
|
||||
return (__builtin_bswap32(a) > __builtin_bswap32(b)) ? 1 : -1;
|
||||
s1 = (char *)s1 + 4;
|
||||
s2 = (char *)s2 + 4;
|
||||
n -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
while (n >= 8) {
|
||||
const uint64_t a = *(uint64_t *)s1;
|
||||
const uint64_t b = *(uint64_t *)s2;
|
||||
if (likely(a != b))
|
||||
return (__builtin_bswap64(a) > __builtin_bswap64(b)) ? 1 : -1;
|
||||
s1 = (char *)s1 + 8;
|
||||
s2 = (char *)s2 + 8;
|
||||
n -= 8;
|
||||
}
|
||||
|
||||
if (n & 4) {
|
||||
const uint32_t a = *(uint32_t *)s1;
|
||||
const uint32_t b = *(uint32_t *)s2;
|
||||
if (likely(a != b))
|
||||
return (__builtin_bswap32(a) > __builtin_bswap32(b)) ? 1 : -1;
|
||||
s1 = (char *)s1 + 4;
|
||||
s2 = (char *)s2 + 4;
|
||||
}
|
||||
|
||||
if (n & 2) {
|
||||
const uint16_t a = *(uint16_t *)s1;
|
||||
const uint16_t b = *(uint16_t *)s2;
|
||||
if (likely(a != b))
|
||||
return (__builtin_bswap16(a) > __builtin_bswap16(b)) ? 1 : -1;
|
||||
s1 = (char *)s1 + 2;
|
||||
s2 = (char *)s2 + 2;
|
||||
}
|
||||
|
||||
return (n & 1) ? *(uint8_t *)s1 - *(uint8_t *)s2 : 0;
|
||||
}
|
||||
|
||||
int __hot mdbx_e2k_strcmp_bug_workaround(const char *s1, const char *s2) {
|
||||
while (true) {
|
||||
int diff = *(uint8_t *)s1 - *(uint8_t *)s2;
|
||||
if (likely(diff != 0) || *s1 == '\0')
|
||||
return diff;
|
||||
s1 += 1;
|
||||
s2 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
int __hot mdbx_e2k_strncmp_bug_workaround(const char *s1, const char *s2,
|
||||
size_t n) {
|
||||
while (n > 0) {
|
||||
int diff = *(uint8_t *)s1 - *(uint8_t *)s2;
|
||||
if (likely(diff != 0) || *s1 == '\0')
|
||||
return diff;
|
||||
s1 += 1;
|
||||
s2 += 1;
|
||||
n -= 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t __hot mdbx_e2k_strlen_bug_workaround(const char *s) {
|
||||
size_t n = 0;
|
||||
while (*s) {
|
||||
s += 1;
|
||||
n += 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t __hot mdbx_e2k_strnlen_bug_workaround(const char *s, size_t maxlen) {
|
||||
size_t n = 0;
|
||||
while (maxlen > n && *s) {
|
||||
s += 1;
|
||||
n += 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
#endif /* Elbrus's memcmp() bug. */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* rthc (tls keys and destructors) */
|
||||
|
||||
@@ -2507,6 +2618,12 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
|
||||
return MDBX_PANIC;
|
||||
}
|
||||
|
||||
STATIC_ASSERT(sizeof(MDBX_reader) == MDBX_CACHELINE_SIZE);
|
||||
STATIC_ASSERT(offsetof(MDBX_lockinfo, mti_numreaders) % MDBX_CACHELINE_SIZE ==
|
||||
0);
|
||||
STATIC_ASSERT(offsetof(MDBX_lockinfo, mti_readers) % MDBX_CACHELINE_SIZE ==
|
||||
0);
|
||||
|
||||
pgno_t upper_pgno = 0;
|
||||
if (flags & MDBX_TXN_RDONLY) {
|
||||
txn->mt_flags = MDBX_TXN_RDONLY;
|
||||
@@ -2562,9 +2679,6 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC_ASSERT(sizeof(MDBX_reader) == MDBX_CACHELINE_SIZE);
|
||||
STATIC_ASSERT(
|
||||
offsetof(MDBX_lockinfo, mti_readers) % MDBX_CACHELINE_SIZE == 0);
|
||||
r = &env->me_lck->mti_readers[slot];
|
||||
/* Claim the reader slot, carefully since other code
|
||||
* uses the reader table un-mutexed: First reset the
|
||||
@@ -2876,6 +2990,13 @@ uint64_t mdbx_txn_id(MDBX_txn *txn) {
|
||||
return txn->mt_txnid;
|
||||
}
|
||||
|
||||
int mdbx_txn_flags(MDBX_txn *txn) {
|
||||
if (unlikely(!txn || txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return -1;
|
||||
|
||||
return txn->mt_flags;
|
||||
}
|
||||
|
||||
/* Export or close DBI handles opened in this txn. */
|
||||
static void mdbx_dbis_update(MDBX_txn *txn, int keep) {
|
||||
MDBX_dbi n = txn->mt_numdbs;
|
||||
@@ -4042,7 +4163,7 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) {
|
||||
STATIC_ASSERT(MIN_MAPSIZE < MAX_MAPSIZE);
|
||||
if (mapsize_max > MAX_MAPSIZE ||
|
||||
MAX_PAGENO < mdbx_roundup2((size_t)mapsize_max, env->me_os_psize) /
|
||||
(uint64_t)page.mp_meta.mm_psize) {
|
||||
(size_t)page.mp_meta.mm_psize) {
|
||||
const uint64_t used_bytes =
|
||||
page.mp_meta.mm_geo.next * (uint64_t)page.mp_meta.mm_psize;
|
||||
if (page.mp_meta.mm_geo.next - 1 > MAX_PAGENO ||
|
||||
@@ -4644,13 +4765,13 @@ LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower,
|
||||
|
||||
if (pagesize < 0) {
|
||||
pagesize = env->me_os_psize;
|
||||
if (pagesize > MAX_PAGESIZE)
|
||||
if ((uintptr_t)pagesize > MAX_PAGESIZE)
|
||||
pagesize = MAX_PAGESIZE;
|
||||
mdbx_assert(env, pagesize >= MIN_PAGESIZE);
|
||||
mdbx_assert(env, (uintptr_t)pagesize >= MIN_PAGESIZE);
|
||||
}
|
||||
}
|
||||
|
||||
if (pagesize < MIN_PAGESIZE || pagesize > MAX_PAGESIZE ||
|
||||
if (pagesize < (intptr_t)MIN_PAGESIZE || pagesize > (intptr_t)MAX_PAGESIZE ||
|
||||
!mdbx_is_power2(pagesize)) {
|
||||
rc = MDBX_EINVAL;
|
||||
goto bailout;
|
||||
@@ -4684,7 +4805,7 @@ LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower,
|
||||
size_upper = pagesize * MAX_PAGENO;
|
||||
}
|
||||
|
||||
if (unlikely(size_lower < MIN_MAPSIZE || size_lower > size_upper)) {
|
||||
if (unlikely(size_lower < (intptr_t)MIN_MAPSIZE || size_lower > size_upper)) {
|
||||
rc = MDBX_EINVAL;
|
||||
goto bailout;
|
||||
}
|
||||
@@ -4991,7 +5112,7 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) {
|
||||
filesize_before_mmap,
|
||||
bytes2pgno(env, (size_t)filesize_before_mmap));
|
||||
} else {
|
||||
mdbx_notice("filesize mismatch (expect %" PRIuPTR "/%" PRIaPGNO
|
||||
mdbx_notice("filesize mismatch (expect %" PRIuSIZE "/%" PRIaPGNO
|
||||
", have %" PRIu64 "/%" PRIaPGNO ")",
|
||||
expected_bytes, bytes2pgno(env, expected_bytes),
|
||||
filesize_before_mmap,
|
||||
@@ -5007,11 +5128,11 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) {
|
||||
if (env->me_flags & MDBX_RDONLY) {
|
||||
mdbx_notice("ignore filesize mismatch in readonly-mode");
|
||||
} else {
|
||||
mdbx_info("resize datafile to %" PRIu64 " bytes, %" PRIaPGNO " pages",
|
||||
mdbx_info("resize datafile to %" PRIuSIZE " bytes, %" PRIaPGNO " pages",
|
||||
expected_bytes, bytes2pgno(env, expected_bytes));
|
||||
err = mdbx_ftruncate(env->me_fd, expected_bytes);
|
||||
if (unlikely(err != MDBX_SUCCESS)) {
|
||||
mdbx_error("error %d, while resize datafile to %" PRIu64
|
||||
mdbx_error("error %d, while resize datafile to %" PRIuSIZE
|
||||
" bytes, %" PRIaPGNO " pages",
|
||||
rc, expected_bytes, bytes2pgno(env, expected_bytes));
|
||||
return err;
|
||||
@@ -5048,15 +5169,30 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) {
|
||||
return MDBX_WANNA_RECOVERY /* LY: could not recovery/rollback */;
|
||||
}
|
||||
|
||||
const MDBX_meta *const meta0 = METAPAGE(env, 0);
|
||||
const MDBX_meta *const meta1 = METAPAGE(env, 1);
|
||||
const MDBX_meta *const meta2 = METAPAGE(env, 2);
|
||||
txnid_t undo_txnid = 0;
|
||||
while (
|
||||
(head != meta0 && mdbx_meta_txnid_fluid(env, meta0) == undo_txnid) ||
|
||||
(head != meta1 && mdbx_meta_txnid_fluid(env, meta1) == undo_txnid) ||
|
||||
(head != meta2 && mdbx_meta_txnid_fluid(env, meta2) == undo_txnid))
|
||||
undo_txnid += 1;
|
||||
if (unlikely(undo_txnid >= meta.mm_txnid_a)) {
|
||||
mdbx_fatal("rollback failed: no suitable txnid (0,1,2) < %" PRIaTXN,
|
||||
meta.mm_txnid_a);
|
||||
return MDBX_PANIC /* LY: could not recovery/rollback */;
|
||||
}
|
||||
|
||||
/* LY: rollback weak checkpoint */
|
||||
mdbx_trace("rollback: from %" PRIaTXN ", to %" PRIaTXN, head_txnid,
|
||||
meta.mm_txnid_a);
|
||||
mdbx_trace("rollback: from %" PRIaTXN ", to %" PRIaTXN " as %" PRIaTXN,
|
||||
head_txnid, meta.mm_txnid_a, undo_txnid);
|
||||
mdbx_ensure(env, head_txnid == mdbx_meta_txnid_stable(env, head));
|
||||
|
||||
if (env->me_flags & MDBX_WRITEMAP) {
|
||||
head->mm_txnid_a = 0;
|
||||
head->mm_txnid_a = undo_txnid;
|
||||
head->mm_datasync_sign = MDBX_DATASIGN_WEAK;
|
||||
head->mm_txnid_b = 0;
|
||||
head->mm_txnid_b = undo_txnid;
|
||||
const size_t offset =
|
||||
((uint8_t *)container_of(head, MDBX_page, mp_meta)) -
|
||||
env->me_dxb_mmap.dxb;
|
||||
@@ -5066,7 +5202,7 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) {
|
||||
err = mdbx_msync(&env->me_dxb_mmap, paged_offset, paged_length, false);
|
||||
} else {
|
||||
MDBX_meta rollback = *head;
|
||||
mdbx_meta_set_txnid(env, &rollback, 0);
|
||||
mdbx_meta_set_txnid(env, &rollback, undo_txnid);
|
||||
rollback.mm_datasync_sign = MDBX_DATASIGN_WEAK;
|
||||
err = mdbx_pwrite(env->me_fd, &rollback, sizeof(MDBX_meta),
|
||||
(uint8_t *)head - (uint8_t *)env->me_map);
|
||||
@@ -5075,7 +5211,7 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) {
|
||||
return err;
|
||||
|
||||
mdbx_invalidate_cache(env->me_map, pgno2bytes(env, NUM_METAS));
|
||||
mdbx_ensure(env, 0 == mdbx_meta_txnid_fluid(env, head));
|
||||
mdbx_ensure(env, undo_txnid == mdbx_meta_txnid_fluid(env, head));
|
||||
mdbx_ensure(env, 0 == mdbx_meta_eq_mask(env));
|
||||
continue;
|
||||
}
|
||||
@@ -7273,9 +7409,11 @@ int mdbx_cursor_put(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
|
||||
memcpy((char *)mp + mp->mp_upper + PAGEHDRSZ,
|
||||
(char *)fp + fp->mp_upper + PAGEHDRSZ,
|
||||
olddata.iov_len - fp->mp_upper - PAGEHDRSZ);
|
||||
memcpy((char *)(&mp->mp_ptrs), (char *)(&fp->mp_ptrs),
|
||||
NUMKEYS(fp) * sizeof(mp->mp_ptrs[0]));
|
||||
for (i = 0; i < NUMKEYS(fp); i++) {
|
||||
mdbx_cassert(mc, fp->mp_ptrs[i] + offset <= UINT16_MAX);
|
||||
mp->mp_ptrs[i] = (indx_t)(fp->mp_ptrs[i] + offset);
|
||||
mdbx_cassert(mc, mp->mp_ptrs[i] + offset <= UINT16_MAX);
|
||||
mp->mp_ptrs[i] += (indx_t)offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10349,13 +10487,13 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
|
||||
!strncmp(table_name, txn->mt_dbxs[scan].md_name.iov_base, len)) {
|
||||
*dbi = scan;
|
||||
rc = mdbx_dbi_bind(txn, scan, user_flags, keycmp, datacmp);
|
||||
goto unlock_return_rc;
|
||||
goto bailout;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(slot >= env->me_maxdbs)) {
|
||||
rc = MDBX_DBS_FULL;
|
||||
goto unlock_return_rc;
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
unsigned dbflag = DB_FRESH | DB_VALID | DB_USRVALID;
|
||||
@@ -10405,7 +10543,6 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
|
||||
*dbi = slot;
|
||||
}
|
||||
|
||||
unlock_return_rc:
|
||||
mdbx_ensure(env, mdbx_fastmutex_release(&env->me_dbi_lock) == MDBX_SUCCESS);
|
||||
return rc;
|
||||
}
|
||||
|
||||
182
src/osal.h
182
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;
|
||||
@@ -504,7 +540,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 +558,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 'read-%s' in %s mode...\n", envname,
|
||||
(envflags & MDBX_RDONLY) ? "read" : "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);
|
||||
|
||||
@@ -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