mirror of
https://github.com/isar/libmdbx.git
synced 2025-12-15 04:32:21 +08:00
Compare commits
29 Commits
LMDB_0.9.1
...
v0.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ecbc0b9c12 | ||
|
|
a783325a6d | ||
|
|
f55c30f286 | ||
|
|
4874852b79 | ||
|
|
6760ca87ae | ||
|
|
d5a0fe539f | ||
|
|
bce8731e60 | ||
|
|
ef941b2587 | ||
|
|
7a5decc779 | ||
|
|
baf0fad11d | ||
|
|
bb205df001 | ||
|
|
4507c1c6bb | ||
|
|
36bc576036 | ||
|
|
c0c4742dba | ||
|
|
dac4534cb7 | ||
|
|
dbacbafa2d | ||
|
|
55b832977b | ||
|
|
a15ebc9923 | ||
|
|
41fbc0279d | ||
|
|
5814f408ac | ||
|
|
78da60dedd | ||
|
|
d7c2247569 | ||
|
|
deefa3d2f4 | ||
|
|
43eff26278 | ||
|
|
f1acaf72ca | ||
|
|
cd14429b5d | ||
|
|
0a65b26c58 | ||
|
|
46b8915087 | ||
|
|
ce06c8df9e |
14
Makefile
14
Makefile
@@ -1,5 +1,5 @@
|
||||
# GNU Makefile for libmdbx (reliable lightning memory-mapped DB library for Linux).
|
||||
# https://github.com/ReOpen/libmdbx
|
||||
# https://github.com/leo-yuriev/libmdbx
|
||||
|
||||
########################################################################
|
||||
# Configuration. The compiler options must enable threaded compilation.
|
||||
@@ -41,9 +41,9 @@ LIBRARIES := libmdbx.a libmdbx.so
|
||||
TOOLS := mdbx_stat mdbx_copy mdbx_dump mdbx_load mdbx_chk
|
||||
MANPAGES := mdb_stat.1 mdb_copy.1 mdb_dump.1 mdb_load.1
|
||||
TESTS := mtest0 mtest1 mtest2 mtest3 mtest4 mtest5 mtest6 wbench \
|
||||
yota_test1 yota_test2
|
||||
yota_test1 yota_test2 mtest7 mtest8
|
||||
|
||||
SRC_LMDB := mdb.c midl.c lmdb.h midl.h reopen.h barriers.h
|
||||
SRC_LMDB := mdb.c midl.c lmdb.h midl.h defs.h barriers.h
|
||||
SRC_MDBX := $(SRC_LMDB) mdbx.c mdbx.h
|
||||
|
||||
.PHONY: mdbx lmdb all install clean check tests coverage
|
||||
@@ -80,6 +80,8 @@ check: tests
|
||||
&& echo "*** LMDB-TEST-4" && ./mtest4 && ./mdbx_chk -v testdb \
|
||||
&& echo "*** LMDB-TEST-5" && ./mtest5 && ./mdbx_chk -v testdb \
|
||||
&& echo "*** LMDB-TEST-6" && ./mtest6 && ./mdbx_chk -v testdb \
|
||||
&& echo "*** LMDB-TEST-7" && ./mtest7 && ./mdbx_chk -v testdb \
|
||||
&& echo "*** LMDB-TEST-8" && ./mtest8 && ./mdbx_chk -v testdb \
|
||||
&& echo "*** LMDB-TESTs - all done"
|
||||
|
||||
libmdbx.a: mdbx.o
|
||||
@@ -130,6 +132,12 @@ mtest5: mtest5.o mdbx.o
|
||||
mtest6: mtest6.o mdbx.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
mtest7: mtest7.o mdbx.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
mtest8: mtest8.o mdbx.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
yota_test1: yota_test1.o mdbx.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ libmdbx
|
||||
Extended LMDB, aka "Расширенная LMDB".
|
||||
|
||||
*The Future will Positive. Всё будет хорошо.*
|
||||
[](https://travis-ci.org/ReOpen/libmdbx)
|
||||
[](https://travis-ci.org/leo-yuriev/libmdbx)
|
||||
|
||||
English version by Google [is here](https://translate.googleusercontent.com/translate_c?act=url&ie=UTF8&sl=ru&tl=en&u=https://github.com/ReOpen/libmdbx/tree/master).
|
||||
English version by Google [is here](https://translate.googleusercontent.com/translate_c?act=url&ie=UTF8&sl=ru&tl=en&u=https://github.com/leo-yuriev/libmdbx/tree/stable%2F0.0).
|
||||
|
||||
|
||||
## Кратко
|
||||
@@ -28,7 +28,7 @@ _libmdbx_ является потомком "Lightning Memory-Mapped Database",
|
||||
известной под аббревиатурой
|
||||
[LMDB](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
|
||||
Изначально доработка производилась в составе проекта
|
||||
[ReOpenLDAP](https://github.com/ReOpen/ReOpenLDAP). Примерно за год
|
||||
[ReOpenLDAP](https://github.com/leo-yuriev/ReOpenLDAP). Примерно за год
|
||||
работы внесенные изменения приобрели самостоятельную ценность. Осенью
|
||||
2015 доработанный движок был выделен в отдельный проект, который был
|
||||
[представлен на конференции Highload++
|
||||
|
||||
14
circle.yml
Normal file
14
circle.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
machine:
|
||||
timezone:
|
||||
Europe/Moscow
|
||||
|
||||
database:
|
||||
override:
|
||||
|
||||
compile:
|
||||
override:
|
||||
- make all lmdb
|
||||
|
||||
test:
|
||||
override:
|
||||
- make check
|
||||
336
defs.h
Normal file
336
defs.h
Normal file
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright 2015-2017 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __GNUC_PREREQ
|
||||
# if defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||
# define __GNUC_PREREQ(maj, min) \
|
||||
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
|
||||
# else
|
||||
# define __GNUC_PREREQ(maj, min) (0)
|
||||
# endif
|
||||
#endif /* __GNUC_PREREQ */
|
||||
|
||||
#ifndef __CLANG_PREREQ
|
||||
# ifdef __clang__
|
||||
# define __CLANG_PREREQ(maj,min) \
|
||||
((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min))
|
||||
# else
|
||||
# define __CLANG_PREREQ(maj,min) (0)
|
||||
# endif
|
||||
#endif /* __CLANG_PREREQ */
|
||||
|
||||
#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 */
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) (0)
|
||||
#endif
|
||||
|
||||
#ifndef __has_feature
|
||||
# define __has_feature(x) (0)
|
||||
#endif
|
||||
|
||||
#ifndef __has_extension
|
||||
# define __has_extension(x) (0)
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
# define __has_builtin(x) (0)
|
||||
#endif
|
||||
|
||||
#if __has_feature(thread_sanitizer)
|
||||
# define __SANITIZE_THREAD__ 1
|
||||
#endif
|
||||
|
||||
#if __has_feature(address_sanitizer)
|
||||
# define __SANITIZE_ADDRESS__ 1
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef __extern_C
|
||||
# ifdef __cplusplus
|
||||
# define __extern_C extern "C"
|
||||
# else
|
||||
# define __extern_C
|
||||
# endif
|
||||
#endif /* __extern_C */
|
||||
|
||||
#ifndef __cplusplus
|
||||
# ifndef bool
|
||||
# define bool _Bool
|
||||
# endif
|
||||
# ifndef true
|
||||
# define true (1)
|
||||
# endif
|
||||
# ifndef false
|
||||
# define false (0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(nullptr) && !defined(__cplusplus) || (__cplusplus < 201103L && !defined(_MSC_VER))
|
||||
# define nullptr NULL
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined(__thread) && (defined(_MSC_VER) || defined(__DMC__))
|
||||
# define __thread __declspec(thread)
|
||||
#endif /* __thread */
|
||||
|
||||
#ifndef __alwaysinline
|
||||
# if defined(__GNUC__) || __has_attribute(always_inline)
|
||||
# define __alwaysinline __inline __attribute__((always_inline))
|
||||
# elif defined(_MSC_VER)
|
||||
# define __alwaysinline __forceinline
|
||||
# else
|
||||
# define __alwaysinline
|
||||
# endif
|
||||
#endif /* __alwaysinline */
|
||||
|
||||
#ifndef __noinline
|
||||
# if defined(__GNUC__) || __has_attribute(noinline)
|
||||
# define __noinline __attribute__((noinline))
|
||||
# elif defined(_MSC_VER)
|
||||
# define __noinline __declspec(noinline)
|
||||
# elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
|
||||
# define __noinline inline
|
||||
# elif !defined(__INTEL_COMPILER)
|
||||
# define __noinline /* FIXME ? */
|
||||
# endif
|
||||
#endif /* __noinline */
|
||||
|
||||
#ifndef __must_check_result
|
||||
# if defined(__GNUC__) || __has_attribute(warn_unused_result)
|
||||
# define __must_check_result __attribute__((warn_unused_result))
|
||||
# else
|
||||
# define __must_check_result
|
||||
# endif
|
||||
#endif /* __must_check_result */
|
||||
|
||||
#ifndef __deprecated
|
||||
# if defined(__GNUC__) || __has_attribute(deprecated)
|
||||
# define __deprecated __attribute__((deprecated))
|
||||
# elif defined(_MSC_VER)
|
||||
# define __deprecated __declspec(deprecated)
|
||||
# else
|
||||
# define __deprecated
|
||||
# endif
|
||||
#endif /* __deprecated */
|
||||
|
||||
#ifndef __packed
|
||||
# if defined(__GNUC__) || __has_attribute(packed)
|
||||
# define __packed __attribute__((packed))
|
||||
# else
|
||||
# define __packed
|
||||
# endif
|
||||
#endif /* __packed */
|
||||
|
||||
#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))
|
||||
# elif defined(_MSC_VER)
|
||||
# define __noreturn __declspec(noreturn)
|
||||
# else
|
||||
# define __noreturn
|
||||
# endif
|
||||
#endif /* __noreturn */
|
||||
|
||||
#ifndef __nothrow
|
||||
# if defined(__GNUC__) || __has_attribute(nothrow)
|
||||
# define __nothrow __attribute__((nothrow))
|
||||
# elif defined(_MSC_VER) && defined(__cplusplus)
|
||||
# define __nothrow __declspec(nothrow)
|
||||
# else
|
||||
# define __nothrow
|
||||
# endif
|
||||
#endif /* __nothrow */
|
||||
|
||||
#ifndef __pure_function
|
||||
/* Many functions have no effects except the return value and their
|
||||
* return value depends only on the parameters and/or global variables.
|
||||
* Such a function can be subject to common subexpression elimination
|
||||
* and loop optimization just as an arithmetic operator would be.
|
||||
* These functions should be declared with the attribute pure. */
|
||||
# if defined(__GNUC__) || __has_attribute(pure)
|
||||
# define __pure_function __attribute__((pure))
|
||||
# else
|
||||
# define __pure_function
|
||||
# endif
|
||||
#endif /* __pure_function */
|
||||
|
||||
#ifndef __const_function
|
||||
/* Many functions do not examine any values except their arguments,
|
||||
* and have no effects except the return value. Basically this is just
|
||||
* slightly more strict class than the PURE attribute, since function
|
||||
* is not allowed to read global memory.
|
||||
*
|
||||
* Note that a function that has pointer arguments and examines the
|
||||
* data pointed to must not be declared const. Likewise, a function
|
||||
* that calls a non-const function usually must not be const.
|
||||
* It does not make sense for a const function to return void. */
|
||||
# if defined(__GNUC__) || __has_attribute(const)
|
||||
# define __const_function __attribute__((const))
|
||||
# else
|
||||
# define __const_function
|
||||
# endif
|
||||
#endif /* __const_function */
|
||||
|
||||
#ifndef __dll_hidden
|
||||
# if defined(__GNUC__) || __has_attribute(visibility)
|
||||
# define __hidden __attribute__((visibility("hidden")))
|
||||
# else
|
||||
# define __hidden
|
||||
# endif
|
||||
#endif /* __dll_hidden */
|
||||
|
||||
#ifndef __optimize
|
||||
# if defined(__OPTIMIZE__)
|
||||
# if defined(__clang__) && !__has_attribute(optimize)
|
||||
# define __optimize(ops)
|
||||
# elif defined(__GNUC__) || __has_attribute(optimize)
|
||||
# define __optimize(ops) __attribute__((optimize(ops)))
|
||||
# else
|
||||
# define __optimize(ops)
|
||||
# endif
|
||||
# else
|
||||
# define __optimize(ops)
|
||||
# endif
|
||||
#endif /* __optimize */
|
||||
|
||||
#ifndef __hot
|
||||
# if defined(__OPTIMIZE__)
|
||||
# if defined(__clang__) && !__has_attribute(hot)
|
||||
/* just put frequently used functions in separate section */
|
||||
# define __hot __attribute__((section("text.hot"))) __optimize("O3")
|
||||
# elif defined(__GNUC__) || __has_attribute(hot)
|
||||
# define __hot __attribute__((hot)) __optimize("O3")
|
||||
# else
|
||||
# define __hot __optimize("O3")
|
||||
# endif
|
||||
# else
|
||||
# define __hot
|
||||
# endif
|
||||
#endif /* __hot */
|
||||
|
||||
#ifndef __cold
|
||||
# if defined(__OPTIMIZE__)
|
||||
# if defined(__clang__) && !__has_attribute(cold)
|
||||
/* just put infrequently used functions in separate section */
|
||||
# define __cold __attribute__((section("text.unlikely"))) __optimize("Os")
|
||||
# elif defined(__GNUC__) || __has_attribute(cold)
|
||||
# define __cold __attribute__((cold)) __optimize("Os")
|
||||
# else
|
||||
# define __cold __optimize("Os")
|
||||
# endif
|
||||
# else
|
||||
# define __cold
|
||||
# endif
|
||||
#endif /* __cold */
|
||||
|
||||
#ifndef __flatten
|
||||
# if defined(__OPTIMIZE__) && (defined(__GNUC__) || __has_attribute(flatten))
|
||||
# define __flatten __attribute__((flatten))
|
||||
# else
|
||||
# define __flatten
|
||||
# endif
|
||||
#endif /* __flatten */
|
||||
|
||||
#ifndef likely
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define likely(cond) __builtin_expect(!!(cond), 1)
|
||||
# else
|
||||
# define likely(x) (x)
|
||||
# endif
|
||||
#endif /* likely */
|
||||
|
||||
#ifndef unlikely
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define unlikely(cond) __builtin_expect(!!(cond), 0)
|
||||
# else
|
||||
# define unlikely(x) (x)
|
||||
# endif
|
||||
#endif /* unlikely */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Wrapper around __func__, which is a C99 feature */
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
# define mdbx_func_ __func__
|
||||
#elif (defined(__GNUC__) && __GNUC__ >= 2) || defined(__clang__) || defined(_MSC_VER)
|
||||
# define mdbx_func_ __FUNCTION__
|
||||
#else
|
||||
# define mdbx_func_ "<mdbx_unknown>"
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(HAVE_VALGRIND) || defined(USE_VALGRIND)
|
||||
/* Get debugging help from Valgrind */
|
||||
# include <valgrind/memcheck.h>
|
||||
# ifndef VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE
|
||||
/* LY: available since Valgrind 3.10 */
|
||||
# define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
|
||||
# define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
|
||||
# endif
|
||||
#else
|
||||
# define VALGRIND_CREATE_MEMPOOL(h,r,z)
|
||||
# define VALGRIND_DESTROY_MEMPOOL(h)
|
||||
# define VALGRIND_MEMPOOL_TRIM(h,a,s)
|
||||
# define VALGRIND_MEMPOOL_ALLOC(h,a,s)
|
||||
# define VALGRIND_MEMPOOL_FREE(h,a)
|
||||
# define VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
|
||||
# define VALGRIND_MAKE_MEM_NOACCESS(a,s)
|
||||
# define VALGRIND_MAKE_MEM_DEFINED(a,s)
|
||||
# define VALGRIND_MAKE_MEM_UNDEFINED(a,s)
|
||||
# define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
|
||||
# define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
|
||||
# define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,s) (0)
|
||||
# define VALGRIND_CHECK_MEM_IS_DEFINED(a,s) (0)
|
||||
#endif /* ! USE_VALGRIND */
|
||||
|
||||
#ifdef __SANITIZE_THREAD__
|
||||
# define ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread, noinline))
|
||||
#else
|
||||
# define ATTRIBUTE_NO_SANITIZE_THREAD
|
||||
#endif
|
||||
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
# include <sanitizer/asan_interface.h>
|
||||
# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address, noinline))
|
||||
#else
|
||||
# define ASAN_POISON_MEMORY_REGION(addr, size) \
|
||||
((void)(addr), (void)(size))
|
||||
# define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
|
||||
((void)(addr), (void)(size))
|
||||
# define ATTRIBUTE_NO_SANITIZE_ADDRESS
|
||||
#endif /* __SANITIZE_ADDRESS__ */
|
||||
166
lmdb.h
166
lmdb.h
@@ -212,7 +212,7 @@ typedef int mdb_filehandle_t;
|
||||
#define MDB_VERSION_DATE "2017-02-17"
|
||||
|
||||
/** A stringifier for the version info */
|
||||
#define MDB_VERSTR(a,b,c,d) "MDBX " #a "." #b "." #c ": (" d ", https://github.com/ReOpen/libmdbx)"
|
||||
#define MDB_VERSTR(a,b,c,d) "MDBX " #a "." #b "." #c ": (" d ", https://github.com/leo-yuriev/libmdbx)"
|
||||
|
||||
/** A helper for the stringifier macro */
|
||||
#define MDB_VERFOO(a,b,c,d) MDB_VERSTR(a,b,c,d)
|
||||
@@ -1671,6 +1671,170 @@ int mdb_reader_check(MDB_env *env, int *dead);
|
||||
|
||||
char* mdb_dkey(MDB_val *key, char *buf);
|
||||
|
||||
/* attribute support functions for Nexenta ***********************************/
|
||||
#if MDBX_MODE_ENABLED
|
||||
|
||||
typedef uint64_t mdbx_attr_t;
|
||||
|
||||
/** @brief Store by cursor with attribute.
|
||||
*
|
||||
* This function stores key/data pairs into the database.
|
||||
* The cursor is positioned at the new item, or on failure usually near it.
|
||||
* @note Internally based on #MDB_RESERVE feature, therefore doesn't support #MDB_DUPSORT.
|
||||
* @note Earlier documentation incorrectly said errors would leave the
|
||||
* state of the cursor unchanged.
|
||||
* @param[in] cursor A cursor handle returned by #mdb_cursor_open()
|
||||
* @param[in] key The key operated on.
|
||||
* @param[in] data The data operated on.
|
||||
* @param[in] attr The attribute.
|
||||
* @param[in] flags Options for this operation. This parameter
|
||||
* must be set to 0 or one of the values described here.
|
||||
* <ul>
|
||||
* <li>#MDB_CURRENT - replace the item at the current cursor position.
|
||||
* The \b key parameter must still be provided, and must match it.
|
||||
* This is intended to be used when the
|
||||
* new data is the same size as the old. Otherwise it will simply
|
||||
* perform a delete of the old record followed by an insert.
|
||||
* <li>#MDB_NOOVERWRITE - enter the new key/data pair only if the key
|
||||
* does not already appear in the database. The function will return
|
||||
* #MDB_KEYEXIST if the key already appears in the database.
|
||||
* <li>#MDB_RESERVE - reserve space for data of the given size, but
|
||||
* don't copy the given data. Instead, return a pointer to the
|
||||
* reserved space, which the caller can fill in later. This saves
|
||||
* an extra memcpy if the data is being generated later.
|
||||
* <li>#MDB_APPEND - append the given key/data pair to the end of the
|
||||
* database. No key comparisons are performed. This option allows
|
||||
* fast bulk loading when keys are already known to be in the
|
||||
* correct order. Loading unsorted keys with this flag will cause
|
||||
* data corruption.
|
||||
* </ul>
|
||||
* @return A non-zero error value on failure and 0 on success. Some possible
|
||||
* errors are:
|
||||
* <ul>
|
||||
* <li>#MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize().
|
||||
* <li>#MDB_TXN_FULL - the transaction has too many dirty pages.
|
||||
* <li>EACCES - an attempt was made to write in a read-only transaction.
|
||||
* <li>EINVAL - an invalid parameter was specified.
|
||||
* </ul>
|
||||
*/
|
||||
int mdbx_cursor_put_attr(MDB_cursor *cursor, MDB_val *key, MDB_val *data,
|
||||
mdbx_attr_t attr, unsigned flags);
|
||||
|
||||
/** @brief Store items and attributes into a database.
|
||||
*
|
||||
* This function stores key/data pairs in the database. The default behavior
|
||||
* is to enter the new key/data pair, replacing any previously existing key
|
||||
* if duplicates are disallowed.
|
||||
* @note Internally based on #MDB_RESERVE feature, therefore doesn't support #MDB_DUPSORT.
|
||||
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
|
||||
* @param[in] dbi A database handle returned by #mdb_dbi_open()
|
||||
* @param[in] key The key to store in the database
|
||||
* @param[in] attr The attribute to store in the database
|
||||
* @param[in,out] data The data to store
|
||||
* @param[in] flags Special options for this operation. This parameter
|
||||
* must be set to 0 or by bitwise OR'ing together one or more of the
|
||||
* values described here.
|
||||
* <ul>
|
||||
* <li>#MDB_NOOVERWRITE - enter the new key/data pair only if the key
|
||||
* does not already appear in the database. The function will return
|
||||
* #MDB_KEYEXIST if the key already appears in the database. The \b data
|
||||
* parameter will be set to point to the existing item.
|
||||
* <li>#MDB_RESERVE - reserve space for data of the given size, but
|
||||
* don't copy the given data. Instead, return a pointer to the
|
||||
* reserved space, which the caller can fill in later - before
|
||||
* the next update operation or the transaction ends. This saves
|
||||
* an extra memcpy if the data is being generated later.
|
||||
* LMDB does nothing else with this memory, the caller is expected
|
||||
* to modify all of the space requested.
|
||||
* <li>#MDB_APPEND - append the given key/data pair to the end of the
|
||||
* database. This option allows fast bulk loading when keys are
|
||||
* already known to be in the correct order. Loading unsorted keys
|
||||
* with this flag will cause a #MDB_KEYEXIST error.
|
||||
* </ul>
|
||||
* @return A non-zero error value on failure and 0 on success. Some possible
|
||||
* errors are:
|
||||
* <ul>
|
||||
* <li>#MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize().
|
||||
* <li>#MDB_TXN_FULL - the transaction has too many dirty pages.
|
||||
* <li>EACCES - an attempt was made to write in a read-only transaction.
|
||||
* <li>EINVAL - an invalid parameter was specified.
|
||||
* </ul>
|
||||
*/
|
||||
int mdbx_put_attr(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data,
|
||||
mdbx_attr_t attr, unsigned flags);
|
||||
|
||||
/** @brief Set items attribute from a database.
|
||||
*
|
||||
* This function stores key/data pairs attribute to the database.
|
||||
* @note Internally based on #MDB_RESERVE feature, therefore doesn't support #MDB_DUPSORT.
|
||||
*
|
||||
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
|
||||
* @param[in] dbi A database handle returned by #mdb_dbi_open()
|
||||
* @param[in] key The key to search for in the database
|
||||
* @param[in] data The data to be stored or NULL to save previous value.
|
||||
* @param[in] attr The attribute to be stored
|
||||
* @return A non-zero error value on failure and 0 on success. Some possible
|
||||
* errors are:
|
||||
* <ul>
|
||||
* <li>#MDB_NOTFOUND - the key-value pair was not in the database.
|
||||
* <li>EINVAL - an invalid parameter was specified.
|
||||
* </ul>
|
||||
*/
|
||||
int mdbx_set_attr(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data,
|
||||
mdbx_attr_t attr);
|
||||
|
||||
/** @brief Get items attribute from a database cursor.
|
||||
*
|
||||
* This function retrieves key/data pairs attribute from the database.
|
||||
* The attribute of the specified key-value pair is returned in
|
||||
* uint64_t to which \b attrptr refers.
|
||||
* If the database supports duplicate keys (#MDB_DUPSORT) then both
|
||||
* key and data parameters are required, otherwise data could be NULL.
|
||||
*
|
||||
* @note Values returned from the database are valid only until a
|
||||
* subsequent update operation, or the end of the transaction.
|
||||
* @param[in] mc A database cursor pointing at the node
|
||||
* @param[in] key The key to search for in the database
|
||||
* @param[in,out] data The data for #MDB_DUPSORT databases
|
||||
* @param[out] attrptr The pointer to the result
|
||||
* @param[in] op A cursor operation #MDB_cursor_op
|
||||
* @return A non-zero error value on failure and 0 on success. Some possible
|
||||
* errors are:
|
||||
* <ul>
|
||||
* <li>#MDB_NOTFOUND - the key-value pair was not in the database.
|
||||
* <li>EINVAL - an invalid parameter was specified.
|
||||
* </ul>
|
||||
*/
|
||||
int mdbx_cursor_get_attr(MDB_cursor *mc, MDB_val *key, MDB_val *data,
|
||||
mdbx_attr_t *attrptr, MDB_cursor_op op);
|
||||
|
||||
/** @brief Get items attribute from a database.
|
||||
*
|
||||
* This function retrieves key/data pairs attribute from the database.
|
||||
* The attribute of the specified key-value pair is returned in
|
||||
* uint64_t to which \b attrptr refers.
|
||||
* If the database supports duplicate keys (#MDB_DUPSORT) then both
|
||||
* key and data parameters are required, otherwise data is ignored.
|
||||
*
|
||||
* @note Values returned from the database are valid only until a
|
||||
* subsequent update operation, or the end of the transaction.
|
||||
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
|
||||
* @param[in] dbi A database handle returned by #mdb_dbi_open()
|
||||
* @param[in] key The key to search for in the database
|
||||
* @param[in] data The data for #MDB_DUPSORT databases
|
||||
* @param[out] attrptr The pointer to the result
|
||||
* @return A non-zero error value on failure and 0 on success. Some possible
|
||||
* errors are:
|
||||
* <ul>
|
||||
* <li>#MDB_NOTFOUND - the key-value pair was not in the database.
|
||||
* <li>EINVAL - an invalid parameter was specified.
|
||||
* </ul>
|
||||
*/
|
||||
int mdbx_get_attr(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data,
|
||||
mdbx_attr_t *attrptr);
|
||||
|
||||
#endif /* MDBX_MODE_ENABLED */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
133
mdb.c
133
mdb.c
@@ -47,12 +47,15 @@
|
||||
/* LY: Please do not ask us for Windows support, just never!
|
||||
* But you can make a fork for Windows, or become maintainer for FreeBSD... */
|
||||
#ifndef __gnu_linux__
|
||||
# warning "ReOpenMDBX supports only GNU Linux"
|
||||
# warning "This version of ReOpenMDBX supports only GNU Linux"
|
||||
#endif
|
||||
|
||||
#include <features.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include "./lmdb.h"
|
||||
#include "./defs.h"
|
||||
|
||||
#if !defined(__GNUC__) || !__GNUC_PREREQ(4,2)
|
||||
#if !__GNUC_PREREQ(4,2)
|
||||
/* LY: Actualy ReOpenMDBX was not tested with compilers
|
||||
* older than GCC 4.4 (from RHEL6).
|
||||
* But you could remove this #error and try to continue at your own risk.
|
||||
@@ -61,7 +64,7 @@
|
||||
# warning "ReOpenMDBX required at least GCC 4.2 compatible C/C++ compiler."
|
||||
#endif
|
||||
|
||||
#if !defined(__GNU_LIBRARY__) || !__GLIBC_PREREQ(2,12)
|
||||
#if !__GLIBC_PREREQ(2,12)
|
||||
/* LY: Actualy ReOpenMDBX was not tested with something
|
||||
* older than glibc 2.12 (from RHEL6).
|
||||
* But you could remove this #error and try to continue at your own risk.
|
||||
@@ -74,7 +77,6 @@
|
||||
# undef NDEBUG
|
||||
#endif
|
||||
|
||||
#include "./reopen.h"
|
||||
#include "./barriers.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -88,8 +90,6 @@
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -98,15 +98,40 @@
|
||||
#include <malloc.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#if !(defined(BYTE_ORDER) || defined(__BYTE_ORDER))
|
||||
# include <netinet/in.h>
|
||||
# include <resolv.h> /* defines BYTE_ORDER on HPUX and Solaris */
|
||||
#endif
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef __GLIBC__
|
||||
# include <assert.h>
|
||||
#elif defined(NDEBUG)
|
||||
# define assert(expr) ((void)0)
|
||||
#else
|
||||
# define assert(expr) \
|
||||
do { \
|
||||
if (unlikely(!(expr))) \
|
||||
__assert_fail(#expr, __FILE__, __LINE__, mdbx_func_); \
|
||||
} while(0)
|
||||
#endif /* __GLIBC__ */
|
||||
|
||||
/* Prototype should match libc runtime. ISO POSIX (2003) & LSB 3.1 */
|
||||
__extern_C void __assert_fail(
|
||||
const char* assertion,
|
||||
const char* file,
|
||||
unsigned line,
|
||||
const char* function) __nothrow __noreturn;
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef _POSIX_SYNCHRONIZED_IO
|
||||
# define fdatasync fsync
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#if !(defined(BYTE_ORDER) || defined(__BYTE_ORDER))
|
||||
# include <netinet/in.h>
|
||||
# include <resolv.h> /* defines BYTE_ORDER on HPUX and Solaris */
|
||||
#endif
|
||||
|
||||
#ifndef BYTE_ORDER
|
||||
# if (defined(_LITTLE_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN))
|
||||
/* Solaris just defines one or the other */
|
||||
@@ -133,7 +158,16 @@
|
||||
# define MISALIGNED_OK 1
|
||||
#endif
|
||||
|
||||
#include "./lmdb.h"
|
||||
#ifndef CACHELINE_SIZE
|
||||
# if defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
|
||||
# define CACHELINE_SIZE 128
|
||||
# else
|
||||
# define CACHELINE_SIZE 64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "./midl.h"
|
||||
|
||||
#if ! MDBX_MODE_ENABLED
|
||||
@@ -190,9 +224,9 @@
|
||||
*/
|
||||
#ifndef MDB_USE_ROBUST
|
||||
/* Howard Chu: Android currently lacks Robust Mutex support */
|
||||
# if defined(EOWNERDEAD) && !defined(ANDROID) \
|
||||
# if defined(EOWNERDEAD) \
|
||||
/* LY: glibc before 2.10 has a troubles with Robust Mutex too. */ \
|
||||
&& __GLIBC_PREREQ(2,10)
|
||||
&& ((__GLIBC_PREREQ(2,10) && !defined(ANDROID)) || defined(PTHREAD_MUTEX_ROBUST))
|
||||
# define MDB_USE_ROBUST 1
|
||||
# else
|
||||
# define MDB_USE_ROBUST 0
|
||||
@@ -1014,7 +1048,7 @@ typedef struct MDB_pgstate {
|
||||
} MDB_pgstate;
|
||||
|
||||
/** Context for deferred cleanup of reader's threads.
|
||||
* to avoid https://github.com/ReOpen/ReOpenLDAP/issues/48 */
|
||||
* to avoid https://github.com/leo-yuriev/ReOpenLDAP/issues/48 */
|
||||
typedef struct MDBX_rthc {
|
||||
struct MDBX_rthc *rc_next;
|
||||
pthread_t rc_thread;
|
||||
@@ -2864,23 +2898,22 @@ mdb_txn_renew0(MDB_txn *txn, unsigned flags)
|
||||
}
|
||||
|
||||
while((env->me_flags & MDB_FATAL_ERROR) == 0) {
|
||||
MDB_meta *meta = mdb_meta_head_r(txn->mt_env);
|
||||
txnid_t lead = meta->mm_txnid;
|
||||
MDB_meta * const meta = mdb_meta_head_r(txn->mt_env);
|
||||
const txnid_t lead = meta->mm_txnid;
|
||||
r->mr_txnid = lead;
|
||||
mdbx_coherent_barrier();
|
||||
|
||||
txnid_t snap = txn->mt_env->me_txns->mti_txnid;
|
||||
/* LY: Retry on a race, ITS#7970. */
|
||||
if (likely(lead == snap)) {
|
||||
txn->mt_txnid = lead;
|
||||
txn->mt_next_pgno = meta->mm_last_pg+1;
|
||||
/* Copy the DB info and flags */
|
||||
memcpy(txn->mt_dbs, meta->mm_dbs, CORE_DBS * sizeof(MDB_db));
|
||||
txn->mt_txnid = lead;
|
||||
txn->mt_next_pgno = meta->mm_last_pg+1;
|
||||
/* Copy the DB info and flags */
|
||||
memcpy(txn->mt_dbs, meta->mm_dbs, CORE_DBS * sizeof(MDB_db));
|
||||
#if MDBX_MODE_ENABLED
|
||||
txn->mt_canary = meta->mm_canary;
|
||||
txn->mt_canary = meta->mm_canary;
|
||||
#endif
|
||||
/* LY: Retry on a race, ITS#7970. */
|
||||
const txnid_t snap = txn->mt_env->me_txns->mti_txnid;
|
||||
if (likely(lead == snap))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
txn->mt_u.reader = r;
|
||||
@@ -3225,7 +3258,8 @@ mdb_txn_end(MDB_txn *txn, unsigned mode)
|
||||
|
||||
if (mode & MDB_END_FREE) {
|
||||
txn->mt_signature = 0;
|
||||
free(txn);
|
||||
if (txn != env->me_txn0)
|
||||
free(txn);
|
||||
}
|
||||
|
||||
return MDB_SUCCESS;
|
||||
@@ -4307,7 +4341,7 @@ mdb_env_create(MDB_env **env)
|
||||
}
|
||||
|
||||
static int __cold
|
||||
mdb_env_map(MDB_env *env, void *addr, size_t usedsize)
|
||||
mdb_env_map(MDB_env *env, void *addr)
|
||||
{
|
||||
unsigned flags = env->me_flags;
|
||||
|
||||
@@ -4347,12 +4381,6 @@ mdb_env_map(MDB_env *env, void *addr, size_t usedsize)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MADV_REMOVE
|
||||
if (flags & MDB_WRITEMAP) {
|
||||
(void) madvise(env->me_map + usedsize, env->me_mapsize - usedsize, MADV_REMOVE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Turn on/off readahead. It's harmful when the DB is larger than RAM. */
|
||||
if (madvise(env->me_map, env->me_mapsize, (flags & MDB_NORDAHEAD) ? MADV_RANDOM : MADV_WILLNEED))
|
||||
return errno;
|
||||
@@ -4405,7 +4433,7 @@ mdb_env_set_mapsize(MDB_env *env, size_t size)
|
||||
#endif
|
||||
env->me_mapsize = size;
|
||||
old = (env->me_flags & MDB_FIXEDMAP) ? env->me_map : NULL;
|
||||
rc = mdb_env_map(env, old, usedsize);
|
||||
rc = mdb_env_map(env, old);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
@@ -4523,8 +4551,7 @@ mdb_env_open2(MDB_env *env, MDB_meta *meta)
|
||||
newenv = 0;
|
||||
}
|
||||
|
||||
const size_t usedsize = (meta->mm_last_pg + 1) * env->me_psize;
|
||||
rc = mdb_env_map(env, (flags & MDB_FIXEDMAP) ? meta->mm_address : NULL, usedsize);
|
||||
rc = mdb_env_map(env, (flags & MDB_FIXEDMAP) ? meta->mm_address : NULL);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@@ -4597,7 +4624,7 @@ void mdbx_rthc_dtor(void)
|
||||
* TSD-деструкторах и поэтому может выгрузить lib.so до того как
|
||||
* отработали все деструкторы.
|
||||
* - Исходное проявление проблемы было зафиксировано
|
||||
* в https://github.com/ReOpen/ReOpenLDAP/issues/48
|
||||
* в https://github.com/leo-yuriev/ReOpenLDAP/issues/48
|
||||
*
|
||||
* Предыдущее решение посредством выделяемого динамически MDB_rthc
|
||||
* было не удачным, так как порождало либо утечку памяти,
|
||||
@@ -4672,7 +4699,7 @@ void mdbx_pthread_crutch_dtor(void)
|
||||
* деструкторы уже могли начать выполняться.
|
||||
* Уступая квант времени сразу после удаления ключа
|
||||
* мы даем им шанс завершиться. */
|
||||
pthread_yield();
|
||||
sched_yield(); sched_yield(); sched_yield();
|
||||
|
||||
mdbx_rthc_lock();
|
||||
pid_t pid = getpid();
|
||||
@@ -4691,11 +4718,12 @@ void mdbx_pthread_crutch_dtor(void)
|
||||
* Поэтому на каждой итерации уступаем квант времени,
|
||||
* в надежде что деструкторы успеют отработать. */
|
||||
mdbx_rthc_unlock();
|
||||
pthread_yield();
|
||||
sched_yield(); sched_yield(); sched_yield();
|
||||
mdbx_rthc_lock();
|
||||
}
|
||||
mdbx_rthc_unlock();
|
||||
pthread_yield();
|
||||
|
||||
sched_yield(); sched_yield(); sched_yield();
|
||||
}
|
||||
#endif /* MDBX_USE_THREAD_ATEXIT */
|
||||
|
||||
@@ -6204,7 +6232,7 @@ mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op)
|
||||
/** Set the cursor on a specific data item. */
|
||||
static int
|
||||
mdb_cursor_set(MDB_cursor *mc, MDB_val *key, MDB_val *data,
|
||||
MDB_cursor_op op, int *exactp)
|
||||
MDB_cursor_op op, int *exactp)
|
||||
{
|
||||
int rc;
|
||||
MDB_page *mp;
|
||||
@@ -8767,15 +8795,20 @@ mdb_cursor_del0(MDB_cursor *mc)
|
||||
}
|
||||
if (mc->mc_db->md_flags & MDB_DUPSORT) {
|
||||
MDB_node *node = NODEPTR(m3->mc_pg[m3->mc_top], m3->mc_ki[m3->mc_top]);
|
||||
/* If this node is a fake page, it needs to be reinited
|
||||
* because its data has moved. But just reset mc_pg[0]
|
||||
* if the xcursor is already live.
|
||||
/* If this node has dupdata, it may need to be reinited
|
||||
* because its data has moved.
|
||||
* If the xcursor was not initd it must be reinited.
|
||||
* Else if node points to a subDB, nothing is needed.
|
||||
* Else (xcursor was initd, not a subDB) needs mc_pg[0] reset.
|
||||
*/
|
||||
if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) {
|
||||
if (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)
|
||||
m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node);
|
||||
else
|
||||
if (node->mn_flags & F_DUPDATA) {
|
||||
if (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) {
|
||||
if (!(node->mn_flags & F_SUBDATA))
|
||||
m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node);
|
||||
} else {
|
||||
mdb_xcursor_init1(m3, node);
|
||||
m3->mc_xcursor->mx_cursor.mc_flags |= C_DEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10694,6 +10727,8 @@ mdb_mutex_failed(MDB_env *env, pthread_mutex_t *mutex, int rc)
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void) mutex;
|
||||
#endif /* MDB_USE_ROBUST */
|
||||
if (unlikely(rc)) {
|
||||
mdb_debug("lock mutex failed, %s", mdb_strerror(rc));
|
||||
|
||||
167
mdbx.c
167
mdbx.c
@@ -140,7 +140,8 @@ int mdbx_txn_straggler(MDB_txn *txn, int *percent)
|
||||
{
|
||||
MDB_env *env;
|
||||
MDB_meta *meta;
|
||||
txnid_t lag;
|
||||
txnid_t recent, lag;
|
||||
size_t maxpg;
|
||||
|
||||
if(unlikely(!txn))
|
||||
return -EINVAL;
|
||||
@@ -148,19 +149,23 @@ int mdbx_txn_straggler(MDB_txn *txn, int *percent)
|
||||
if(unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDB_VERSION_MISMATCH;
|
||||
|
||||
if (unlikely(! txn->mt_u.reader))
|
||||
return -1;
|
||||
|
||||
env = txn->mt_env;
|
||||
meta = mdb_meta_head_r(env);
|
||||
if (percent) {
|
||||
size_t maxpg = env->me_maxpg;
|
||||
size_t last = meta->mm_last_pg + 1;
|
||||
if (env->me_txn)
|
||||
last = env->me_txn0->mt_next_pgno;
|
||||
*percent = (last * 100ull + maxpg / 2) / maxpg;
|
||||
maxpg = env->me_maxpg;
|
||||
if (unlikely((txn->mt_flags & MDB_RDONLY) == 0)) {
|
||||
*percent = (int)((txn->mt_next_pgno * 100ull + maxpg / 2) / maxpg);
|
||||
return -1;
|
||||
}
|
||||
lag = meta->mm_txnid - txn->mt_u.reader->mr_txnid;
|
||||
|
||||
do {
|
||||
meta = mdb_meta_head_r(env);
|
||||
recent = meta->mm_txnid;
|
||||
if (percent) {
|
||||
pgno_t last = meta->mm_last_pg + 1;
|
||||
*percent = (int)((last * 100ull + maxpg / 2) / maxpg);
|
||||
}
|
||||
} while (unlikely(recent != meta->mm_txnid));
|
||||
|
||||
lag = recent - txn->mt_u.reader->mr_txnid;
|
||||
return (0 > (long) lag) ? ~0u >> 1: lag;
|
||||
}
|
||||
|
||||
@@ -737,3 +742,141 @@ int mdbx_dbi_open_ex(MDB_txn *txn, const char *name, unsigned flags,
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* attribute support functions for Nexenta ***********************************/
|
||||
|
||||
static __inline int
|
||||
mdbx_attr_peek(MDB_val *data, mdbx_attr_t *attrptr)
|
||||
{
|
||||
if (unlikely(data->mv_size < sizeof(mdbx_attr_t)))
|
||||
return MDB_INCOMPATIBLE;
|
||||
|
||||
if (likely(attrptr != NULL))
|
||||
*attrptr = *(mdbx_attr_t*) data->mv_data;
|
||||
data->mv_size -= sizeof(mdbx_attr_t);
|
||||
data->mv_data = likely(data->mv_size > 0)
|
||||
? ((mdbx_attr_t*) data->mv_data) + 1 : NULL;
|
||||
|
||||
return MDB_SUCCESS;
|
||||
}
|
||||
|
||||
static __inline int
|
||||
mdbx_attr_poke(MDB_val *reserved, MDB_val *data, mdbx_attr_t attr, unsigned flags)
|
||||
{
|
||||
mdbx_attr_t *space = reserved->mv_data;
|
||||
if (flags & MDB_RESERVE) {
|
||||
if (likely(data != NULL)) {
|
||||
data->mv_data = data->mv_size ? space + 1 : NULL;
|
||||
}
|
||||
} else {
|
||||
*space = attr;
|
||||
if (likely(data != NULL)) {
|
||||
memcpy(space + 1, data->mv_data, data->mv_size );
|
||||
}
|
||||
}
|
||||
|
||||
return MDB_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
mdbx_cursor_get_attr(MDB_cursor *mc, MDB_val *key, MDB_val *data,
|
||||
mdbx_attr_t *attrptr, MDB_cursor_op op)
|
||||
{
|
||||
int rc = mdbx_cursor_get(mc, key, data, op);
|
||||
if (unlikely(rc != MDB_SUCCESS))
|
||||
return rc;
|
||||
|
||||
return mdbx_attr_peek(data, attrptr);
|
||||
}
|
||||
|
||||
int
|
||||
mdbx_get_attr(MDB_txn *txn, MDB_dbi dbi,
|
||||
MDB_val *key, MDB_val *data, uint64_t *attrptr)
|
||||
{
|
||||
int rc = mdbx_get(txn, dbi, key, data);
|
||||
if (unlikely(rc != MDB_SUCCESS))
|
||||
return rc;
|
||||
|
||||
return mdbx_attr_peek(data, attrptr);
|
||||
}
|
||||
|
||||
int
|
||||
mdbx_put_attr(MDB_txn *txn, MDB_dbi dbi,
|
||||
MDB_val *key, MDB_val *data, mdbx_attr_t attr, unsigned flags)
|
||||
{
|
||||
MDB_val reserve = {
|
||||
.mv_data = NULL,
|
||||
.mv_size = (data ? data->mv_size : 0) + sizeof(mdbx_attr_t)
|
||||
};
|
||||
|
||||
int rc = mdbx_put(txn, dbi, key, &reserve, flags | MDB_RESERVE);
|
||||
if (unlikely(rc != MDB_SUCCESS))
|
||||
return rc;
|
||||
|
||||
return mdbx_attr_poke(&reserve, data, attr, flags);
|
||||
}
|
||||
|
||||
int mdbx_cursor_put_attr(MDB_cursor *cursor, MDB_val *key, MDB_val *data,
|
||||
mdbx_attr_t attr, unsigned flags)
|
||||
{
|
||||
MDB_val reserve = {
|
||||
.mv_data = NULL,
|
||||
.mv_size = (data ? data->mv_size : 0) + sizeof(mdbx_attr_t)
|
||||
};
|
||||
|
||||
int rc = mdbx_cursor_put(cursor, key, &reserve, flags | MDB_RESERVE);
|
||||
if (unlikely(rc != MDB_SUCCESS))
|
||||
return rc;
|
||||
|
||||
return mdbx_attr_poke(&reserve, data, attr, flags);
|
||||
}
|
||||
|
||||
int mdbx_set_attr(MDB_txn *txn, MDB_dbi dbi,
|
||||
MDB_val *key, MDB_val *data, mdbx_attr_t attr)
|
||||
{
|
||||
MDB_cursor mc;
|
||||
MDB_xcursor mx;
|
||||
MDB_val old_data;
|
||||
mdbx_attr_t old_attr;
|
||||
int rc;
|
||||
|
||||
if (unlikely(!key || !txn))
|
||||
return EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
|
||||
return MDB_VERSION_MISMATCH;
|
||||
|
||||
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
|
||||
return EINVAL;
|
||||
|
||||
if (unlikely(txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED)))
|
||||
return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
|
||||
|
||||
mdb_cursor_init(&mc, txn, dbi, &mx);
|
||||
rc = mdb_cursor_set(&mc, key, &old_data, MDB_SET, NULL);
|
||||
if (unlikely(rc != MDB_SUCCESS)) {
|
||||
if (rc == MDB_NOTFOUND && data) {
|
||||
mc.mc_next = txn->mt_cursors[dbi];
|
||||
txn->mt_cursors[dbi] = &mc;
|
||||
rc = mdbx_cursor_put_attr(&mc, key, data, attr, 0);
|
||||
txn->mt_cursors[dbi] = mc.mc_next;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
old_attr = 0;
|
||||
rc = mdbx_attr_peek(&old_data, &old_attr);
|
||||
if (unlikely(rc != MDB_SUCCESS))
|
||||
return rc;
|
||||
|
||||
if (old_attr == attr && (!data ||
|
||||
(data->mv_size == old_data.mv_size
|
||||
&& memcmp(data->mv_data, old_data.mv_data, old_data.mv_size) == 0)))
|
||||
return MDB_SUCCESS;
|
||||
|
||||
mc.mc_next = txn->mt_cursors[dbi];
|
||||
txn->mt_cursors[dbi] = &mc;
|
||||
rc = mdbx_cursor_put_attr(&mc, key, data ? data : &old_data, attr, MDB_CURRENT);
|
||||
txn->mt_cursors[dbi] = mc.mc_next;
|
||||
return rc;
|
||||
}
|
||||
|
||||
124
mtest7.c
Normal file
124
mtest7.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/* mtest7.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2015 Ilya Usvyatsky, Nexenta Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
/* Tests for DB attributes */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include "mdbx.h"
|
||||
|
||||
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
|
||||
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
|
||||
#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
|
||||
"%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
|
||||
|
||||
char dkbuf[1024];
|
||||
|
||||
#ifndef DBPATH
|
||||
# define DBPATH "./testdb/data.mdb"
|
||||
#endif
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
int i = 0, j = 0, rc;
|
||||
MDB_env *env;
|
||||
MDB_dbi dbi;
|
||||
MDB_val key, data;
|
||||
MDB_txn *txn;
|
||||
MDB_stat mst;
|
||||
int count;
|
||||
int *values;
|
||||
char sval[32];
|
||||
uint64_t *timestamps, timestamp;
|
||||
struct timeval tv;
|
||||
int env_opt = MDB_NOMEMINIT | MDB_NOSYNC | MDB_NOSUBDIR | MDB_NORDAHEAD;
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
memset(sval, 0, sizeof(sval));
|
||||
count = (rand()%384) + 64;
|
||||
if (argc > 1)
|
||||
count = atoi(argv[1]);
|
||||
values = (int *)malloc(count*sizeof(int));
|
||||
timestamps = (uint64_t *)calloc(count,sizeof(uint64_t));
|
||||
|
||||
unlink(DBPATH);
|
||||
E(mdb_env_create(&env));
|
||||
E(mdb_env_set_mapsize(env, 104857600));
|
||||
E(mdb_env_set_maxdbs(env, 8));
|
||||
E(mdb_env_open(env, DBPATH, env_opt, 0664));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_dbi_open(txn, "id7", MDB_CREATE|MDB_INTEGERKEY, &dbi));
|
||||
|
||||
key.mv_size = sizeof(int);
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
|
||||
printf("Adding %d values\n", count);
|
||||
for (i=0;i<count;i++) {
|
||||
(void)gettimeofday(&tv, NULL);
|
||||
timestamps[i] = tv.tv_usec + 1000000UL * tv.tv_sec;
|
||||
values[i] = rand()%16383 ^ (timestamps[i] & 0xffff);
|
||||
key.mv_data = values + i;
|
||||
sprintf(sval, "%03x %d foo bar", values[i], values[i]);
|
||||
E(mdbx_put_attr(txn, dbi, &key, &data, timestamps[i], MDB_NODUPDATA));
|
||||
}
|
||||
if (j) printf("%d duplicates skipped\n", j);
|
||||
E(mdb_txn_commit(txn));
|
||||
E(mdb_env_stat(env, &mst));
|
||||
mdb_env_close(env);
|
||||
|
||||
E(mdb_env_create(&env));
|
||||
E(mdb_env_set_mapsize(env, 10485760));
|
||||
E(mdb_env_set_maxdbs(env, 8));
|
||||
E(mdb_env_open(env, DBPATH, env_opt, 0664));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_dbi_open(txn, "id7", MDB_CREATE|MDB_INTEGERKEY, &dbi));
|
||||
for (i=0;!rc&&i<count;i++) {
|
||||
if (!timestamps[i])
|
||||
continue;
|
||||
key.mv_data = values + i;
|
||||
sprintf(sval, "%03x %d foo bar", values[i], values[i]);
|
||||
E(mdbx_get_attr(txn, dbi, &key, &data, ×tamp));
|
||||
if (timestamps[i] != timestamp) {
|
||||
for (j = 0; j < count; ++j) {
|
||||
if (j != i && values[i] == values[j] &&
|
||||
timestamp == timestamps[j]) {
|
||||
printf("Duplicate keys "
|
||||
"%d %d %d %d %lu %lu\n",
|
||||
i, j, values[i], values[j],
|
||||
timestamps[i], timestamps[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j >= count) {
|
||||
printf("Timestamp mismatch "
|
||||
"%d %03x %d %lu != %lu\n",
|
||||
i, values[i], values[i], timestamps[i],
|
||||
timestamp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
E(mdb_txn_commit(txn));
|
||||
E(mdb_env_stat(env, &mst));
|
||||
mdb_env_close(env);
|
||||
|
||||
return 0;
|
||||
}
|
||||
146
mtest8.c
Normal file
146
mtest8.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/* mtest8.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2015 Ilya Usvyatsky, Nexenta Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
/* Tests for DB attributes */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include "mdbx.h"
|
||||
|
||||
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
|
||||
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
|
||||
#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
|
||||
"%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
|
||||
|
||||
char dkbuf[1024];
|
||||
|
||||
#ifndef DBPATH
|
||||
# define DBPATH "./testdb/data.mdb"
|
||||
#endif
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
int i = 0, rc;
|
||||
MDB_env *env;
|
||||
MDB_dbi dbi;
|
||||
MDB_val key, data;
|
||||
MDB_txn *txn;
|
||||
MDB_stat mst;
|
||||
int count;
|
||||
int *values;
|
||||
char sval[8000];
|
||||
uint64_t *timestamps, timestamp;
|
||||
struct timeval tv;
|
||||
int env_opt = MDB_NOMEMINIT | MDB_NOSYNC | MDB_NOSUBDIR | MDB_NORDAHEAD;
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
memset(sval, 0, sizeof(sval));
|
||||
count = 2000; //(rand()%384) + 64;
|
||||
if (argc > 1)
|
||||
count = atoi(argv[1]);
|
||||
values = (int *)malloc(count*sizeof(int));
|
||||
timestamps = (uint64_t *)calloc(count,sizeof(uint64_t));
|
||||
|
||||
key.mv_size = sizeof(int);
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
|
||||
values[0] = 42;
|
||||
values[1] = 17;
|
||||
|
||||
for (i = 2; i < count; ++i)
|
||||
values[i] = values[i - 1] + values[i - 2];
|
||||
|
||||
unlink(DBPATH);
|
||||
E(mdb_env_create(&env));
|
||||
E(mdb_env_set_mapsize(env, 104857600));
|
||||
E(mdb_env_set_maxdbs(env, 8));
|
||||
E(mdb_env_open(env, DBPATH, env_opt, 0664));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_dbi_open(txn, "id8", MDB_CREATE|MDB_INTEGERKEY, &dbi));
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
(void)gettimeofday(&tv, NULL);
|
||||
timestamps[i] = tv.tv_usec + 1000000UL * tv.tv_sec;
|
||||
|
||||
snprintf(sval, 4000, "Value %d\n", values[i]);
|
||||
snprintf(sval + 4000, 4000, "Value %d\n", values[i]);
|
||||
key.mv_data = values + i;
|
||||
E(mdbx_put_attr(txn, dbi, &key, &data, timestamps[i], MDB_NOOVERWRITE));
|
||||
}
|
||||
|
||||
E(mdb_txn_commit(txn));
|
||||
E(mdb_env_stat(env, &mst));
|
||||
mdb_env_close(env);
|
||||
|
||||
E(mdb_env_create(&env));
|
||||
E(mdb_env_set_mapsize(env, 10485760));
|
||||
E(mdb_env_set_maxdbs(env, 8));
|
||||
E(mdb_env_open(env, DBPATH, env_opt, 0664));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_dbi_open(txn, "id8", MDB_INTEGERKEY, &dbi));
|
||||
for (i = 0; i < count; ++i) {
|
||||
key.mv_data = values + i;
|
||||
E(mdbx_get_attr(txn, dbi, &key, &data, ×tamp));
|
||||
E(timestamps[i] != timestamp);
|
||||
}
|
||||
|
||||
E(mdb_txn_commit(txn));
|
||||
E(mdb_env_stat(env, &mst));
|
||||
mdb_env_close(env);
|
||||
|
||||
E(mdb_env_create(&env));
|
||||
E(mdb_env_set_mapsize(env, 104857600));
|
||||
E(mdb_env_set_maxdbs(env, 8));
|
||||
E(mdb_env_open(env, DBPATH, env_opt, 0664));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_dbi_open(txn, "id8", MDB_INTEGERKEY, &dbi));
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
(void)gettimeofday(&tv, NULL);
|
||||
timestamps[i] = tv.tv_usec + 1000000UL * tv.tv_sec;
|
||||
|
||||
key.mv_data = values + i;
|
||||
E(mdbx_set_attr(txn, dbi, &key, NULL, timestamps[i]));
|
||||
}
|
||||
|
||||
E(mdb_txn_commit(txn));
|
||||
E(mdb_env_stat(env, &mst));
|
||||
mdb_env_close(env);
|
||||
|
||||
E(mdb_env_create(&env));
|
||||
E(mdb_env_set_mapsize(env, 10485760));
|
||||
E(mdb_env_set_maxdbs(env, 8));
|
||||
E(mdb_env_open(env, DBPATH, env_opt, 0664));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_dbi_open(txn, "id8", MDB_INTEGERKEY, &dbi));
|
||||
for (i = 0; i < count; ++i) {
|
||||
key.mv_data = values + i;
|
||||
E(mdbx_get_attr(txn, dbi, &key, &data, ×tamp));
|
||||
E(timestamps[i] != timestamp);
|
||||
}
|
||||
|
||||
E(mdb_txn_commit(txn));
|
||||
E(mdb_env_stat(env, &mst));
|
||||
mdb_env_close(env);
|
||||
|
||||
return 0;
|
||||
}
|
||||
237
reopen.h
237
reopen.h
@@ -1,237 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015-2017 Leonid Yuriev <leo@yuriev.ru>.
|
||||
* Copyright 2015,2016 Peter-Service R&D LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#ifndef _REOPEN_H
|
||||
#define _REOPEN_H
|
||||
|
||||
#ifndef __CLANG_PREREQ
|
||||
# ifdef __clang__
|
||||
# define __CLANG_PREREQ(maj,min) \
|
||||
((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min))
|
||||
# else
|
||||
# define __CLANG_PREREQ(maj,min) (0)
|
||||
# endif
|
||||
#endif /* __CLANG_PREREQ */
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) (0)
|
||||
#endif
|
||||
|
||||
#if !defined(__thread) && (defined(_MSC_VER) || defined(__DMC__))
|
||||
# define __thread __declspec(thread)
|
||||
#endif
|
||||
|
||||
#ifndef __forceinline
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define __forceinline __inline __attribute__((always_inline))
|
||||
# elif ! defined(_MSC_VER)
|
||||
# define __forceinline
|
||||
# endif
|
||||
#endif /* __forceinline */
|
||||
|
||||
#ifndef __noinline
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define __noinline __attribute__((noinline))
|
||||
# elif defined(_MSC_VER)
|
||||
# define __noinline __declspec(noinline)
|
||||
# endif
|
||||
#endif /* __noinline */
|
||||
|
||||
#ifndef __must_check_result
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define __must_check_result __attribute__((warn_unused_result))
|
||||
# else
|
||||
# define __must_check_result
|
||||
# endif
|
||||
#endif /* __must_check_result */
|
||||
|
||||
#ifndef __hot
|
||||
# if defined(__OPTIMIZE__) && (defined(__GNUC__) && !defined(__clang__))
|
||||
# define __hot __attribute__((hot, optimize("O3")))
|
||||
# elif defined(__GNUC__)
|
||||
/* cland case, just put frequently used functions in separate section */
|
||||
# define __hot __attribute__((section("text.hot")))
|
||||
# else
|
||||
# define __hot
|
||||
# endif
|
||||
#endif /* __hot */
|
||||
|
||||
#ifndef __cold
|
||||
# if defined(__OPTIMIZE__) && (defined(__GNUC__) && !defined(__clang__))
|
||||
# define __cold __attribute__((cold, optimize("Os")))
|
||||
# elif defined(__GNUC__)
|
||||
/* cland case, just put infrequently used functions in separate section */
|
||||
# define __cold __attribute__((section("text.unlikely")))
|
||||
# else
|
||||
# define __cold
|
||||
# endif
|
||||
#endif /* __cold */
|
||||
|
||||
#ifndef __flatten
|
||||
# if defined(__OPTIMIZE__) && (defined(__GNUC__) || defined(__clang__))
|
||||
# define __flatten __attribute__((flatten))
|
||||
# else
|
||||
# define __flatten
|
||||
# endif
|
||||
#endif /* __flatten */
|
||||
|
||||
#ifndef __aligned
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define __aligned(N) __attribute__((aligned(N)))
|
||||
# elif defined(__MSC_VER)
|
||||
# define __aligned(N) __declspec(align(N))
|
||||
# else
|
||||
# define __aligned(N)
|
||||
# endif
|
||||
#endif /* __align */
|
||||
|
||||
#ifndef __noreturn
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define __noreturn __attribute__((noreturn))
|
||||
# elif defined(__MSC_VER)
|
||||
# define __noreturn __declspec(noreturn)
|
||||
# else
|
||||
# define __noreturn
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef __nothrow
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define __nothrow __attribute__((nothrow))
|
||||
# elif defined(__MSC_VER)
|
||||
# define __nothrow __declspec(nothrow)
|
||||
# else
|
||||
# define __nothrow
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef CACHELINE_SIZE
|
||||
# if defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
|
||||
# define CACHELINE_SIZE 128
|
||||
# else
|
||||
# define CACHELINE_SIZE 64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef __cache_aligned
|
||||
# define __cache_aligned __aligned(CACHELINE_SIZE)
|
||||
#endif
|
||||
|
||||
#ifndef likely
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# ifdef __cplusplus
|
||||
/* LY: workaround for "pretty" boost */
|
||||
static __inline __attribute__((always_inline))
|
||||
bool likely(bool cond) { return __builtin_expect(cond, 1); }
|
||||
# else
|
||||
# define likely(cond) __builtin_expect(!!(cond), 1)
|
||||
# endif
|
||||
# else
|
||||
# define likely(x) (x)
|
||||
# endif
|
||||
#endif /* likely */
|
||||
|
||||
#ifndef unlikely
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# ifdef __cplusplus
|
||||
/* LY: workaround for "pretty" boost */
|
||||
static __inline __attribute__((always_inline))
|
||||
bool unlikely(bool cond) { return __builtin_expect(cond, 0); }
|
||||
# else
|
||||
# define unlikely(cond) __builtin_expect(!!(cond), 0)
|
||||
# endif
|
||||
# else
|
||||
# define unlikely(x) (x)
|
||||
# endif
|
||||
#endif /* unlikely */
|
||||
|
||||
#ifndef __extern_C
|
||||
# ifdef __cplusplus
|
||||
# define __extern_C extern "C"
|
||||
# else
|
||||
# define __extern_C
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef __noop
|
||||
# define __noop() do {} while (0)
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* Prototype should match libc runtime. ISO POSIX (2003) & LSB 3.1 */
|
||||
__extern_C void __assert_fail(
|
||||
const char* assertion,
|
||||
const char* file,
|
||||
unsigned line,
|
||||
const char* function) __nothrow __noreturn;
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(HAVE_VALGRIND) || defined(USE_VALGRIND)
|
||||
/* Get debugging help from Valgrind */
|
||||
# include <valgrind/memcheck.h>
|
||||
# ifndef VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE
|
||||
/* LY: available since Valgrind 3.10 */
|
||||
# define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
|
||||
# define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
|
||||
# endif
|
||||
#else
|
||||
# define VALGRIND_CREATE_MEMPOOL(h,r,z)
|
||||
# define VALGRIND_DESTROY_MEMPOOL(h)
|
||||
# define VALGRIND_MEMPOOL_TRIM(h,a,s)
|
||||
# define VALGRIND_MEMPOOL_ALLOC(h,a,s)
|
||||
# define VALGRIND_MEMPOOL_FREE(h,a)
|
||||
# define VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
|
||||
# define VALGRIND_MAKE_MEM_NOACCESS(a,s)
|
||||
# define VALGRIND_MAKE_MEM_DEFINED(a,s)
|
||||
# define VALGRIND_MAKE_MEM_UNDEFINED(a,s)
|
||||
# define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
|
||||
# define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
|
||||
# define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,s) (0)
|
||||
# define VALGRIND_CHECK_MEM_IS_DEFINED(a,s) (0)
|
||||
#endif /* ! USE_VALGRIND */
|
||||
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(thread_sanitizer)
|
||||
# define __SANITIZE_THREAD__ 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __SANITIZE_THREAD__
|
||||
# define ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread, noinline))
|
||||
#else
|
||||
# define ATTRIBUTE_NO_SANITIZE_THREAD
|
||||
#endif
|
||||
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(address_sanitizer)
|
||||
# define __SANITIZE_ADDRESS__ 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
# include <sanitizer/asan_interface.h>
|
||||
# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address, noinline))
|
||||
#else
|
||||
# define ASAN_POISON_MEMORY_REGION(addr, size) \
|
||||
((void)(addr), (void)(size))
|
||||
# define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
|
||||
((void)(addr), (void)(size))
|
||||
# define ATTRIBUTE_NO_SANITIZE_ADDRESS
|
||||
#endif /* __SANITIZE_ADDRESS__ */
|
||||
|
||||
#endif /* _REOPEN_H */
|
||||
Reference in New Issue
Block a user