diff --git a/.travis.yml b/.travis.yml index 93590840..e46991f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ compiler: os: - linux +- osx script: if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then make all check; fi diff --git a/Makefile b/Makefile index 1abc03d6..f471a016 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ suffix ?= CC ?= gcc CXX ?= g++ +LD ?= ld CFLAGS ?= -O2 -g3 -Wall -Werror -Wextra -ffunction-sections -fPIC -fvisibility=hidden XCFLAGS ?= -DNDEBUG=1 -DMDBX_DEBUG=0 -DLIBMDBX_EXPORTS=1 @@ -32,8 +33,8 @@ 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,-O1,--no-as-needed,-lrt -EXE_LDFLAGS ?= -pthread -lrt +LDFLAGS ?= $(shell $(LD) --help 2>/dev/null | grep -q -- --gc-sections && echo '-Wl,--gc-sections,-z,relro,-O1')$(shell $(LD) --help 2>/dev/null | grep -q -- -dead_strip && echo '-Wl,-dead_strip') +EXE_LDFLAGS ?= -pthread # LY: just for benchmarking IOARENA ?= $(shell \ @@ -44,33 +45,51 @@ NN ?= 25000000 ######################################################################## -HEADERS := mdbx.h -LIBRARIES := libmdbx.a libmdbx.so -TOOLS := mdbx_stat mdbx_copy mdbx_dump mdbx_load mdbx_chk -MANPAGES := mdbx_stat.1 mdbx_copy.1 mdbx_dump.1 mdbx_load.1 -SHELL := /bin/bash - ifdef MSVC + UNAME := Windows LCK_IMPL := windows TEST_OSAL := windows + TEST_ITER := 42 else + UNAME := $(shell uname -s 2>/dev/null || echo Unknown) define uname2lck - case "`uname -s 2>/dev/null`" in + case "$(UNAME)" in Linux) echo linux;; - CYGWIN*|MINGW32*|MSYS*) echo windows;; + CYGWIN*|MINGW32*|MSYS*|Windows*) echo windows;; *) echo posix;; esac endef define uname2osal - case "`uname -s 2>/dev/null`" in - CYGWIN*|MINGW32*|MSYS*) echo windows;; + case "$(UNAME)" in + CYGWIN*|MINGW32*|MSYS*|Windows*) echo windows;; *) echo unix;; esac endef + define uname2titer + case "$(UNAME)" in + Darwin*|Mach*) echo 3;; + *) echo 42;; + esac + endef + define uname2suffix + case "$(UNAME)" in + Darwin*|Mach*) echo dylib;; + CYGWIN*|MINGW32*|MSYS*|Windows*) echo dll;; + *) echo so;; + esac + endef LCK_IMPL := $(shell $(uname2lck)) TEST_OSAL := $(shell $(uname2osal)) + TEST_ITER := $(shell $(uname2titer)) + SO_SUFFIX := $(shell $(uname2suffix)) endif +HEADERS := mdbx.h +LIBRARIES := libmdbx.a libmdbx.$(SO_SUFFIX) +TOOLS := mdbx_stat mdbx_copy mdbx_dump mdbx_load mdbx_chk +MANPAGES := mdbx_stat.1 mdbx_copy.1 mdbx_dump.1 mdbx_load.1 +SHELL := /bin/bash + CORE_SRC := src/lck-$(LCK_IMPL).c $(filter-out $(wildcard src/lck-*.c), $(wildcard src/*.c)) CORE_INC := $(wildcard src/*.h) CORE_OBJ := $(patsubst %.c,%.o,$(CORE_SRC)) @@ -82,10 +101,10 @@ TEST_OBJ := $(patsubst %.cc,%.o,$(TEST_SRC)) all: $(LIBRARIES) $(TOOLS) mdbx_test example -mdbx: libmdbx.a libmdbx.so +mdbx: libmdbx.a libmdbx.$(SO_SUFFIX) -example: mdbx.h tutorial/sample-mdbx.c libmdbx.so - $(CC) $(CFLAGS) -I. tutorial/sample-mdbx.c ./libmdbx.so -o example +example: mdbx.h tutorial/sample-mdbx.c libmdbx.$(SO_SUFFIX) + $(CC) $(CFLAGS) -I. tutorial/sample-mdbx.c ./libmdbx.$(SO_SUFFIX) -o example tools: $(TOOLS) @@ -103,7 +122,7 @@ clean: 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; ./mdbx_test --repeat=42 --pathname=$(TESTDB) --dont-cleanup-after basic | tee -a $(TESTLOG) | tail -n 42) \ + rm -f $(TESTDB) $(TESTLOG) && (set -o pipefail; ./mdbx_test --repeat=$(TEST_ITER) --pathname=$(TESTDB) --dont-cleanup-after basic | tee -a $(TESTLOG) | tail -n 42) \ && ./mdbx_chk -vvn $(TESTDB) && ./mdbx_chk -vvn $(TESTDB)-copy check-singleprocess: all @@ -134,13 +153,13 @@ $(foreach file,$(TEST_SRC),$(eval $(call test-rule,$(file)))) libmdbx.a: $(CORE_OBJ) $(AR) rs $@ $? -libmdbx.so: $(CORE_OBJ) +libmdbx.$(SO_SUFFIX): $(CORE_OBJ) $(CC) $(CFLAGS) -save-temps $^ -pthread -shared $(LDFLAGS) -o $@ mdbx_%: src/tools/mdbx_%.c libmdbx.a $(CC) $(CFLAGS) $^ $(EXE_LDFLAGS) -o $@ -mdbx_test: $(TEST_OBJ) libmdbx.so +mdbx_test: $(TEST_OBJ) libmdbx.$(SO_SUFFIX) $(CXX) $(CXXFLAGS) $(TEST_OBJ) -Wl,-rpath . -L . -l mdbx $(EXE_LDFLAGS) -o $@ ############################################################################### @@ -166,7 +185,7 @@ bench-$(1)_$(2).txt: $(3) $(IOARENA) Makefile endef -$(eval $(call bench-rule,mdbx,$(NN),libmdbx.so)) +$(eval $(call bench-rule,mdbx,$(NN),libmdbx.$(SO_SUFFIX))) $(eval $(call bench-rule,sophia,$(NN))) $(eval $(call bench-rule,leveldb,$(NN))) diff --git a/src/bits.h b/src/bits.h index 52e89f45..7660e50e 100644 --- a/src/bits.h +++ b/src/bits.h @@ -23,6 +23,12 @@ # undef NDEBUG #endif +#define MDBX_OSX_WANNA_DURABILITY 0 /* using fcntl(F_FULLFSYNC) with 5-10 times slowdown */ +#define MDBX_OSX_WANNA_SPEED 1 /* using fsync() with chance of data lost on power failure */ +#ifndef MDBX_OSX_SPEED_OR_DURABILITY +#define MDBX_OSX_SPEED_OR_DURABILITY MDBX_OSX_WANNA_DURABILITY +#endif + /*----------------------------------------------------------------------------*/ /* Should be defined before any includes */ @@ -30,6 +36,10 @@ # define _FILE_OFFSET_BITS 64 #endif +#ifdef __APPLE__ +#define _DARWIN_C_SOURCE +#endif + #ifdef _MSC_VER # if _MSC_VER < 1400 # error "Microsoft Visual C++ 8.0 (Visual Studio 2005) or later version is required" diff --git a/src/lck-posix.c b/src/lck-posix.c index bbb07c4f..37f4026e 100644 --- a/src/lck-posix.c +++ b/src/lck-posix.c @@ -18,7 +18,7 @@ * even though they don't support Robust Mutexes. * Compile with -DMDBX_USE_ROBUST=0. */ #ifndef MDBX_USE_ROBUST -#if defined(EOWNERDEAD) || _POSIX_C_SOURCE >= 200809L +#if (defined(EOWNERDEAD) || _POSIX_C_SOURCE >= 200809L) && !defined(__APPLE__) #define MDBX_USE_ROBUST 1 #else #define MDBX_USE_ROBUST 0 diff --git a/src/mdbx.c b/src/mdbx.c index 138f4e0e..a8a6f302 100644 --- a/src/mdbx.c +++ b/src/mdbx.c @@ -292,6 +292,16 @@ static CRITICAL_SECTION rthc_critical_section; #else int __cxa_thread_atexit_impl(void (*dtor)(void *), void *obj, void *dso_symbol) __attribute__((weak)); +#ifdef __APPLE__ /* FIXME: Thread-Local Storage destructors & DSO-unloading */ +int __cxa_thread_atexit_impl(void (*dtor)(void *), void *obj, + void *dso_symbol) { + (void)dtor; + (void)obj; + (void)dso_symbol; + return -1; +} +#endif /* __APPLE__ */ + static pthread_mutex_t mdbx_rthc_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t mdbx_rthc_cond = PTHREAD_COND_INITIALIZER; static mdbx_thread_key_t mdbx_rthc_key; @@ -515,9 +525,9 @@ __cold void mdbx_rthc_global_dtor(void) { mdbx_thread_key_delete(key); for (MDBX_reader *rthc = rthc_table[i].begin; rthc < rthc_table[i].end; ++rthc) { - mdbx_trace("== [%i] = key %u, %p ... %p, rthc %p (%+i), " + mdbx_trace("== [%i] = key %zu, %p ... %p, rthc %p (%+i), " "rthc-pid %i, current-pid %i", - i, key, rthc_table[i].begin, rthc_table[i].end, rthc, + i, (size_t)key, rthc_table[i].begin, rthc_table[i].end, rthc, (int)(rthc - rthc_table[i].begin), rthc->mr_pid, self_pid); if (rthc->mr_pid == self_pid) { rthc->mr_pid = 0; @@ -553,8 +563,8 @@ __cold int mdbx_rthc_alloc(mdbx_thread_key_t *key, MDBX_reader *begin, return rc; mdbx_rthc_lock(); - mdbx_trace(">> key 0x%x, rthc_count %u, rthc_limit %u", *key, rthc_count, - rthc_limit); + mdbx_trace(">> key %zu, rthc_count %u, rthc_limit %u", (size_t)*key, + rthc_count, rthc_limit); if (rthc_count == rthc_limit) { rthc_entry_t *new_table = mdbx_realloc((rthc_table == rthc_table_static) ? nullptr : rthc_table, @@ -568,13 +578,14 @@ __cold int mdbx_rthc_alloc(mdbx_thread_key_t *key, MDBX_reader *begin, rthc_table = new_table; rthc_limit *= 2; } - mdbx_trace("== [%i] = key %u, %p ... %p", rthc_count, *key, begin, end); + mdbx_trace("== [%i] = key %zu, %p ... %p", rthc_count, (size_t)*key, begin, + end); rthc_table[rthc_count].key = *key; rthc_table[rthc_count].begin = begin; rthc_table[rthc_count].end = end; ++rthc_count; - mdbx_trace("<< key 0x%x, rthc_count %u, rthc_limit %u", *key, rthc_count, - rthc_limit); + mdbx_trace("<< key %zu, rthc_count %u, rthc_limit %u", (size_t)*key, + rthc_count, rthc_limit); mdbx_rthc_unlock(); return MDBX_SUCCESS; @@ -587,8 +598,8 @@ bailout: __cold void mdbx_rthc_remove(const mdbx_thread_key_t key) { mdbx_thread_key_delete(key); mdbx_rthc_lock(); - mdbx_trace(">> key 0x%x, rthc_count %u, rthc_limit %u", key, rthc_count, - rthc_limit); + mdbx_trace(">> key %zu, rthc_count %u, rthc_limit %u", (size_t)key, + rthc_count, rthc_limit); for (unsigned i = 0; i < rthc_count; ++i) { if (key == rthc_table[i].key) { @@ -614,8 +625,8 @@ __cold void mdbx_rthc_remove(const mdbx_thread_key_t key) { } } - mdbx_trace("<< key 0x%x, rthc_count %u, rthc_limit %u", key, rthc_count, - rthc_limit); + mdbx_trace("<< key %zu, rthc_count %u, rthc_limit %u", (size_t)key, + rthc_count, rthc_limit); mdbx_rthc_unlock(); } @@ -3030,7 +3041,7 @@ __cold static int mdbx_env_sync_ex(MDBX_env *env, int force, int nonblock) { int rc = (flags & MDBX_WRITEMAP) ? mdbx_msync(&env->me_dxb_mmap, 0, usedbytes, flags & MDBX_MAPASYNC) - : mdbx_filesync(env->me_fd, false); + : mdbx_filesync(env->me_fd, MDBX_SYNC_DATA); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -5411,14 +5422,16 @@ static int mdbx_sync_locked(MDBX_env *env, unsigned flags, goto fail; if ((flags & MDBX_MAPASYNC) == 0) { if (unlikely(pending->mm_geo.next > steady->mm_geo.now)) { - rc = mdbx_filesize_sync(env->me_fd); + rc = mdbx_filesync(env->me_fd, MDBX_SYNC_SIZE); if (unlikely(rc != MDBX_SUCCESS)) goto fail; } env->me_sync_pending = 0; } } else { - rc = mdbx_filesync(env->me_fd, pending->mm_geo.next > steady->mm_geo.now); + rc = mdbx_filesync(env->me_fd, (pending->mm_geo.next > steady->mm_geo.now) + ? MDBX_SYNC_DATA | MDBX_SYNC_SIZE + : MDBX_SYNC_DATA); if (unlikely(rc != MDBX_SUCCESS)) goto fail; env->me_sync_pending = 0; @@ -5566,7 +5579,7 @@ static int mdbx_sync_locked(MDBX_env *env, unsigned flags, if (unlikely(rc != MDBX_SUCCESS)) goto fail; } else { - rc = mdbx_filesync(env->me_fd, false); + rc = mdbx_filesync(env->me_fd, MDBX_SYNC_DATA | MDBX_SYNC_IODQ); if (rc != MDBX_SUCCESS) goto undo; } @@ -11814,12 +11827,15 @@ int __cold mdbx_env_copy2fd(MDBX_env *env, mdbx_filehandle_t fd, mdbx_txn_abort(read_txn); if (likely(rc == MDBX_SUCCESS)) - rc = mdbx_filesync(fd, true); + rc = mdbx_filesync(fd, MDBX_SYNC_DATA | MDBX_SYNC_SIZE); /* Write actual meta */ if (likely(rc == MDBX_SUCCESS)) rc = mdbx_pwrite(fd, buffer, pgno2bytes(env, NUM_METAS), 0); + if (likely(rc == MDBX_SUCCESS)) + rc = mdbx_filesync(fd, MDBX_SYNC_DATA | MDBX_SYNC_IODQ); + mdbx_memalign_free(buffer); return rc; } @@ -12860,7 +12876,7 @@ int __cold mdbx_setup_debug(int flags, MDBX_debug_func *logger) { unsigned ret = mdbx_runtime_flags; mdbx_runtime_flags = flags; -#ifdef __linux__ +#if defined(__linux__) || defined(__gnu_linux__) if (flags & MDBX_DBG_DUMP) { int core_filter_fd = open("/proc/self/coredump_filter", O_TRUNC | O_RDWR); if (core_filter_fd >= 0) { @@ -12883,7 +12899,7 @@ int __cold mdbx_setup_debug(int flags, MDBX_debug_func *logger) { close(core_filter_fd); } } -#endif /* __linux__ */ +#endif /* Linux */ mdbx_debug_logger = logger; return ret; diff --git a/src/osal.c b/src/osal.c index 03d4c86f..4e917a76 100644 --- a/src/osal.c +++ b/src/osal.c @@ -159,9 +159,14 @@ typedef struct _FILE_PROVIDER_EXTERNAL_INFO_V1 { /* Prototype should match libc runtime. ISO POSIX (2003) & LSB 1.x-3.x */ __nothrow __noreturn void __assert_fail(const char *assertion, const char *file, unsigned line, const char *function); -#elif (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ - defined(__BSD__) || defined(__NETBSD__) || defined(__bsdi__) || \ - defined(__DragonFly__)) +#elif defined(__APPLE__) || defined(__MACH__) +__nothrow __noreturn void __assert_rtn(const char *function, const char *file, + int line, const char *assertion); +#define __assert_fail(assertion, file, line, function) \ + __assert_rtn(function, file, line, assertion) +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__BSD__) || defined(__NETBSD__) || defined(__bsdi__) || \ + defined(__DragonFly__) __nothrow __noreturn void __assert(const char *function, const char *file, int line, const char *assertion); #define __assert_fail(assertion, file, line, function) \ @@ -548,6 +553,9 @@ int mdbx_openfile(const char *pathname, int flags, mode_t mode, if (fd_flags != -1) (void)fcntl(*fd, F_SETFL, fd_flags | O_DIRECT); #endif /* O_DIRECT */ +#if defined(F_NOCACHE) + (void)fcntl(*fd, F_NOCACHE, 1); +#endif /* F_NOCACHE */ } #endif @@ -626,7 +634,7 @@ int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf, size_t bytes, int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov, int iovcnt, uint64_t offset, size_t expected_written) { -#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) || defined(_WIN64) || defined(__APPLE__) size_t written = 0; for (int i = 0; i < iovcnt; ++i) { int rc = mdbx_pwrite(fd, iov[i].iov_base, iov[i].iov_len, offset); @@ -652,11 +660,23 @@ int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov, int iovcnt, #endif } -int mdbx_filesync(mdbx_filehandle_t fd, bool filesize_changed) { +int mdbx_filesync(mdbx_filehandle_t fd, enum mdbx_syncmode_bits mode_bits) { #if defined(_WIN32) || defined(_WIN64) - (void)filesize_changed; - return FlushFileBuffers(fd) ? MDBX_SUCCESS : GetLastError(); + return ((mode_bits & (MDBX_SYNC_DATA | MDBX_SYNC_IODQ)) == 0 || + FlushFileBuffers(fd)) + ? MDBX_SUCCESS + : GetLastError(); #else + +#if defined(__APPLE__) && \ + MDBX_OSX_SPEED_OR_DURABILITY == MDBX_OSX_WANNA_DURABILITY + if (mode_bits & MDBX_SYNC_IODQ) + return likely(fcntl(fd, F_FULLFSYNC) != -1) ? MDBX_SUCCESS : errno; +#endif /* MacOS */ +#if defined(__linux__) || defined(__gnu_linux__) + if (mode_bits == MDBX_SYNC_SIZE && linux_kernel_version >= 0x03060000) + return MDBX_SUCCESS; +#endif /* Linux */ int rc; do { #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 @@ -665,12 +685,12 @@ int mdbx_filesync(mdbx_filehandle_t fd, bool filesize_changed) { * * For more info about of a corresponding fdatasync() bug * see http://www.spinics.net/lists/linux-ext4/msg33714.html */ - if (!filesize_changed) { + if ((mode_bits & MDBX_SYNC_SIZE) == 0) { if (fdatasync(fd) == 0) return MDBX_SUCCESS; } else #else - (void)filesize_changed; + (void)mode_bits; #endif if (fsync(fd) == 0) return MDBX_SUCCESS; @@ -680,22 +700,6 @@ int mdbx_filesync(mdbx_filehandle_t fd, bool filesize_changed) { #endif } -int mdbx_filesize_sync(mdbx_filehandle_t fd) { -#if defined(_WIN32) || defined(_WIN64) - (void)fd; - /* Nothing on Windows (i.e. newer 100% steady) */ - return MDBX_SUCCESS; -#else - for (;;) { - if (fsync(fd) == 0) - return MDBX_SUCCESS; - int rc = errno; - if (rc != EINTR) - return rc; - } -#endif -} - int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length) { #if defined(_WIN32) || defined(_WIN64) BY_HANDLE_FILE_INFORMATION info; @@ -792,7 +796,13 @@ int mdbx_msync(mdbx_mmap_t *map, size_t offset, size_t length, int async) { return MDBX_SUCCESS; #endif /* Linux */ const int mode = async ? MS_ASYNC : MS_SYNC; - return (msync(ptr, length, mode) == 0) ? MDBX_SUCCESS : errno; + int rc = (msync(ptr, length, mode) == 0) ? MDBX_SUCCESS : errno; +#if defined(__APPLE__) && \ + MDBX_OSX_SPEED_OR_DURABILITY == MDBX_OSX_WANNA_DURABILITY + if (rc == MDBX_SUCCESS && mode == MS_SYNC) + rc = likely(fcntl(map->fd, F_FULLFSYNC) != -1) ? MDBX_SUCCESS : errno; +#endif /* MacOS */ + return rc; #endif } @@ -1165,7 +1175,10 @@ retry_mapview:; return rc; #else if (limit != map->length) { -#if defined(_GNU_SOURCE) && !defined(__FreeBSD__) +#if defined(_GNU_SOURCE) && \ + !(defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__BSD__) || defined(__NETBSD__) || defined(__bsdi__) || \ + defined(__DragonFly__) || defined(__APPLE__) || defined(__MACH__)) void *ptr = mremap(map->address, map->length, limit, /* LY: in case changing the mapping size calling code must guarantees the absence of competing threads, and diff --git a/src/osal.h b/src/osal.h index d57a380a..3564e8dc 100644 --- a/src/osal.h +++ b/src/osal.h @@ -55,7 +55,7 @@ #include #if !(defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ defined(__BSD__) || defined(__NETBSD__) || defined(__bsdi__) || \ - defined(__DragonFly__)) + defined(__DragonFly__) || defined(__APPLE__) || defined(__MACH__)) #include #endif /* xBSD */ @@ -522,7 +522,13 @@ int mdbx_thread_create(mdbx_thread_t *thread, void *arg); int mdbx_thread_join(mdbx_thread_t thread); -int mdbx_filesync(mdbx_filehandle_t fd, bool fullsync); +enum mdbx_syncmode_bits { + MDBX_SYNC_DATA = 1, + MDBX_SYNC_SIZE = 2, + MDBX_SYNC_IODQ = 4 +}; + +int mdbx_filesync(mdbx_filehandle_t fd, enum mdbx_syncmode_bits mode_bits); int mdbx_filesize_sync(mdbx_filehandle_t fd); int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length); int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos); diff --git a/test/base.h b/test/base.h index 0b4d26e5..5ca134a8 100644 --- a/test/base.h +++ b/test/base.h @@ -39,6 +39,10 @@ #include #endif /* WINDOWS */ +#ifdef __APPLE__ +#define _DARWIN_C_SOURCE +#endif + #include #include #include diff --git a/test/config.h b/test/config.h index decd9612..89889d8e 100644 --- a/test/config.h +++ b/test/config.h @@ -102,6 +102,22 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option, bool parse_option(int argc, char *const argv[], int &narg, const char *option, int32_t &value, const int32_t minval, const int32_t maxval, const int32_t default_value = -1); + +inline bool parse_option_intptr(int argc, char *const argv[], int &narg, + const char *option, intptr_t &value, + const intptr_t minval, const intptr_t maxval, + const intptr_t default_value = -1) { + static_assert(sizeof(intptr_t) == 4 || sizeof(intptr_t) == 8, "WTF?"); + if (sizeof(intptr_t) == 8) + return parse_option(argc, argv, narg, option, + *reinterpret_cast(&value), int64_t(minval), + int64_t(maxval), int64_t(default_value)); + else + return parse_option(argc, argv, narg, option, + *reinterpret_cast(&value), int32_t(minval), + int32_t(maxval), int32_t(default_value)); +} + //----------------------------------------------------------------------------- #pragma pack(push, 1) diff --git a/test/darwin/LICENSE b/test/darwin/LICENSE new file mode 100644 index 00000000..6a0dd306 --- /dev/null +++ b/test/darwin/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2015, Aleksey Demakov +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/test/darwin/README.md b/test/darwin/README.md new file mode 100644 index 00000000..a6a8fd1a --- /dev/null +++ b/test/darwin/README.md @@ -0,0 +1,8 @@ +# DarwinPthreadBarrier + +A pthread_barrier_t implementation for Mac OS/X + +There is no pthread_barrier_t in Mac OS/X pthreads. This project fixes +this omission by providing a simple-minded barrier implementation based +on a pair of pthread_mutex_t and pthread_cond_t. + diff --git a/test/darwin/pthread_barrier.c b/test/darwin/pthread_barrier.c new file mode 100644 index 00000000..26e052ed --- /dev/null +++ b/test/darwin/pthread_barrier.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, Aleksey Demakov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pthread_barrier.h" + +#include + +#ifdef __APPLE__ + +#define __unused __attribute__((unused)) + +int pthread_barrierattr_init(pthread_barrierattr_t *attr) { + memset(attr, 0, sizeof(pthread_barrierattr_t)); + int m = pthread_mutexattr_init(&attr->mattr); + int c = pthread_condattr_init(&attr->cattr); + return m ? m : c; +} + +int pthread_barrierattr_destroy(pthread_barrierattr_t *attr) { + int c = pthread_condattr_destroy(&attr->cattr); + int m = pthread_mutexattr_destroy(&attr->mattr); + return m ? m : c; +} + +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict attr, + int *__restrict pshared) { + return pthread_condattr_getpshared(&attr->cattr, pshared); +} + +int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) { + int m = pthread_mutexattr_setpshared(&attr->mattr, pshared); + int c = pthread_condattr_setpshared(&attr->cattr, pshared); + return m ? m : c; +} + +int pthread_barrier_init(pthread_barrier_t *__restrict barrier, + const pthread_barrierattr_t *__restrict attr, + unsigned count) { + if (count == 0) + return errno = EINVAL; + + int rc = pthread_mutex_init(&barrier->mutex, attr ? &attr->mattr : 0); + if (rc) + return rc; + + rc = pthread_cond_init(&barrier->cond, attr ? &attr->cattr : 0); + if (rc) { + int errno_save = errno; + pthread_mutex_destroy(&barrier->mutex); + errno = errno_save; + return rc; + } + + barrier->limit = count; + barrier->count = 0; + barrier->phase = 0; + return 0; +} + +int pthread_barrier_destroy(pthread_barrier_t *barrier) { + pthread_mutex_destroy(&barrier->mutex); + pthread_cond_destroy(&barrier->cond); + return 0; +} + +int pthread_barrier_wait(pthread_barrier_t *barrier) { + int rc = pthread_mutex_lock(&barrier->mutex); + if (rc) + return rc; + + barrier->count++; + if (barrier->count >= barrier->limit) { + barrier->phase++; + barrier->count = 0; + pthread_cond_broadcast(&barrier->cond); + pthread_mutex_unlock(&barrier->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } else { + unsigned phase = barrier->phase; + do + pthread_cond_wait(&barrier->cond, &barrier->mutex); + while (phase == barrier->phase); + pthread_mutex_unlock(&barrier->mutex); + return 0; + } +} + +#endif /* __APPLE__ */ diff --git a/test/darwin/pthread_barrier.h b/test/darwin/pthread_barrier.h new file mode 100644 index 00000000..efa9b9b7 --- /dev/null +++ b/test/darwin/pthread_barrier.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, Aleksey Demakov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PTHREAD_BARRIER_H +#define PTHREAD_BARRIER_H + +#include + +#ifdef __APPLE__ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(PTHREAD_BARRIER_SERIAL_THREAD) +#define PTHREAD_BARRIER_SERIAL_THREAD (1) +#endif + +#if !defined(PTHREAD_PROCESS_PRIVATE) +#define PTHREAD_PROCESS_PRIVATE (42) +#endif +#if !defined(PTHREAD_PROCESS_SHARED) +#define PTHREAD_PROCESS_SHARED (43) +#endif + +typedef struct { + pthread_mutexattr_t mattr; + pthread_condattr_t cattr; +} pthread_barrierattr_t; + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + unsigned int limit; + unsigned int count; + unsigned int phase; +} pthread_barrier_t; + +int pthread_barrierattr_init(pthread_barrierattr_t *attr); +int pthread_barrierattr_destroy(pthread_barrierattr_t *attr); + +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict attr, + int *__restrict pshared); +int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared); + +int pthread_barrier_init(pthread_barrier_t *__restrict barrier, + const pthread_barrierattr_t *__restrict attr, + unsigned int count); +int pthread_barrier_destroy(pthread_barrier_t *barrier); + +int pthread_barrier_wait(pthread_barrier_t *barrier); + +#ifdef __cplusplus +} +#endif + +#endif /* __APPLE__ */ + +#endif /* PTHREAD_BARRIER_H */ diff --git a/test/main.cc b/test/main.cc index 69ce6973..959359a5 100644 --- a/test/main.cc +++ b/test/main.cc @@ -182,17 +182,19 @@ int main(int argc, char *const argv[]) { params.datalen_max = datalen_max; continue; } - if (config::parse_option(argc, argv, narg, "size-lower", params.size_lower, - mdbx_limits_dbsize_min(params.pagesize), - mdbx_limits_dbsize_max(params.pagesize))) + if (config::parse_option_intptr(argc, argv, narg, "size-lower", + params.size_lower, + mdbx_limits_dbsize_min(params.pagesize), + mdbx_limits_dbsize_max(params.pagesize))) continue; - if (config::parse_option(argc, argv, narg, "size-upper", params.size_upper, - mdbx_limits_dbsize_min(params.pagesize), - mdbx_limits_dbsize_max(params.pagesize))) + if (config::parse_option_intptr(argc, argv, narg, "size-upper", + params.size_upper, + mdbx_limits_dbsize_min(params.pagesize), + mdbx_limits_dbsize_max(params.pagesize))) continue; - if (config::parse_option(argc, argv, narg, "size", params.size_now, - mdbx_limits_dbsize_min(params.pagesize), - mdbx_limits_dbsize_max(params.pagesize))) + if (config::parse_option_intptr(argc, argv, narg, "size", params.size_now, + mdbx_limits_dbsize_min(params.pagesize), + mdbx_limits_dbsize_max(params.pagesize))) continue; if (config::parse_option( argc, argv, narg, "shrink-threshold", params.shrink_threshold, 0, diff --git a/test/osal-unix.cc b/test/osal-unix.cc index 95e2ab3e..0157bace 100644 --- a/test/osal-unix.cc +++ b/test/osal-unix.cc @@ -21,6 +21,10 @@ #include #include +#ifdef __APPLE__ +#include "darwin/pthread_barrier.c" +#endif + struct shared_t { pthread_barrier_t barrier; pthread_mutex_t mutex; diff --git a/test/ttl.cc b/test/ttl.cc index 1ce8d4b7..b2650f0c 100644 --- a/test/ttl.cc +++ b/test/ttl.cc @@ -53,11 +53,26 @@ bool testcase_ttl::run() { */ /* LY: для параметризации используем подходящие параметры, которые не имеют - * здесь смысла в первоначальном значении */ - const unsigned window_max = - (config.params.batch_read > 999) ? config.params.batch_read : 1000; - const unsigned count_max = - (config.params.batch_write > 999) ? config.params.batch_write : 1000; + * здесь смысла в первоначальном значении. */ + const unsigned window_max_lower = +#ifdef __APPLE__ + 333; +#else + 999; +#endif + const unsigned count_max_lower = +#ifdef __APPLE__ + 333; +#else + 999; +#endif + + const unsigned window_max = (config.params.batch_read > window_max_lower) + ? config.params.batch_read + : window_max_lower; + const unsigned count_max = (config.params.batch_write > count_max_lower) + ? config.params.batch_write + : count_max_lower; log_info("ttl: using `batch_read` value %u for window_max", window_max); log_info("ttl: using `batch_write` value %u for count_max", count_max); diff --git a/test/utils.cc b/test/utils.cc index 18f6c6ab..d9b3538b 100644 --- a/test/utils.cc +++ b/test/utils.cc @@ -17,6 +17,9 @@ #if defined(HAVE_IEEE754_H) || __has_include() #include #endif +#if defined(__APPLE__) || defined(__MACH__) +#include +#endif /* defined(__APPLE__) || defined(__MACH__) */ std::string format(const char *fmt, ...) { va_list ap, ones; diff --git a/test/utils.h b/test/utils.h index 520506ea..d1b859ac 100644 --- a/test/utils.h +++ b/test/utils.h @@ -247,18 +247,20 @@ struct simple_checksum { simple_checksum() : value(0) {} - void push(uint32_t data) { + void push(const uint32_t &data) { value += data * UINT64_C(9386433910765580089) + 1; value ^= value >> 41; value *= UINT64_C(0xBD9CACC22C6E9571); } - void push(uint64_t data) { + void push(const uint64_t &data) { push((uint32_t)data); push((uint32_t)(data >> 32)); } - void push(bool data) { push(data ? UINT32_C(0x780E) : UINT32_C(0xFA18E)); } + void push(const bool data) { + push(data ? UINT32_C(0x780E) : UINT32_C(0xFA18E)); + } void push(const void *ptr, size_t bytes) { const uint8_t *data = (const uint8_t *)ptr; @@ -271,7 +273,7 @@ struct simple_checksum { void push(const std::string &str) { push(str.data(), str.size()); } void push(unsigned salt, const MDBX_val &val) { - push(val.iov_len); + push(unsigned(val.iov_len)); push(salt); push(val.iov_base, val.iov_len); }