summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/libmdbx/src/mdbx.h178
-rw-r--r--libs/libmdbx/src/src/elements/core.c1038
-rw-r--r--libs/libmdbx/src/src/elements/defs.h47
-rw-r--r--libs/libmdbx/src/src/elements/internals.h13
-rw-r--r--libs/libmdbx/src/src/elements/osal.c3
-rw-r--r--libs/libmdbx/src/test/pcrf/pcrf_test.c52
6 files changed, 1002 insertions, 329 deletions
diff --git a/libs/libmdbx/src/mdbx.h b/libs/libmdbx/src/mdbx.h
index 8f2b89c63e..fba8c4602b 100644
--- a/libs/libmdbx/src/mdbx.h
+++ b/libs/libmdbx/src/mdbx.h
@@ -201,6 +201,14 @@
* necessary) in a child process would be both extreme complicated and so
* fragile.
*
+ * Do not start more than one transaction for a one thread. If you think about
+ * this, it's really strange to do something with two data snapshots at once,
+ * which may be different. MDBX checks and preventing this by returning
+ * corresponding error code (MDBX_TXN_OVERLAPPING, MDBX_BAD_RSLOT, MDBX_BUSY)
+ * unless you using MDBX_NOTLS option on the environment. Nonetheless, with the
+ * MDBX_NOTLS option, you must know exactly what you are doing, otherwise you
+ * will get deadlocks or reading an alien data.
+ *
* Also note that a transaction is tied to one thread by default using Thread
* Local Storage. If you want to pass read-only transactions across threads,
* you can use the MDBX_NOTLS option on the environment. Nevertheless, a write
@@ -298,19 +306,19 @@
* - optimize (bulk) loading speed
* - (temporarily) reduce robustness to gain even more speed
* - gather statistics about the database
- * - define custom sort orders
* - estimate size of range query result
* - double perfomance by LIFO reclaiming on storages with write-back
* - use sequences and canary markers
* - use lack-of-space callback (aka OOM-KICK)
* - use exclusive mode
+ * - define custom sort orders (but this is recommended to be avoided)
*
*
**** RESTRICTIONS & CAVEATS ***************************************************
* in addition to those listed for some functions.
*
* - Troubleshooting the LCK-file.
- * 1. A broken LCK-file can cause sync issues, including appearance of
+ * 1. A broken LCK-file can cause sync issues, including appearance of
* wrong/inconsistent data for readers. When database opened in the
* cooperative read-write mode the LCK-file requires to be mapped to
* memory in read-write access. In this case it is always possible for
@@ -327,14 +335,14 @@
* Workaround: Just make all programs using the database close it;
* the LCK-file is always reset on first open.
*
- * 2. Stale reader transactions left behind by an aborted program cause
+ * 2. Stale reader transactions left behind by an aborted program cause
* further writes to grow the database quickly, and stale locks can
* block further operation.
* MDBX checks for stale readers while opening environment and before
* growth the database. But in some cases, this may not be enough.
*
* Workaround: Check for stale readers periodically, using the
- * mdbx_reader_check() function or the mdbx_stat tool.
+ * mdbx_reader_check() function or the mdbx_stat tool.
*
* 3. Stale writers will be cleared automatically by MDBX on supprted
* platforms. But this is platform-specific, especially of
@@ -379,10 +387,18 @@
* The "next" version of libmdbx (MithrilDB) will solve this issue.
*
* - A thread can only use one transaction at a time, plus any nested
- * read-write transactions in the non-writemap mode. Each transaction
+ * read-write transactions in the non-writemap mode. Each transaction
* belongs to one thread. The MDBX_NOTLS flag changes this for read-only
* transactions. See below.
*
+ * Do not start more than one transaction for a one thread. If you think
+ * about this, it's really strange to do something with two data snapshots
+ * at once, which may be different. MDBX checks and preventing this by
+ * returning corresponding error code (MDBX_TXN_OVERLAPPING, MDBX_BAD_RSLOT,
+ * MDBX_BUSY) unless you using MDBX_NOTLS option on the environment.
+ * Nonetheless, with the MDBX_NOTLS option, you must know exactly what you
+ * are doing, otherwise you will get deadlocks or reading an alien data.
+ *
* - Do not have open an MDBX database twice in the same process at the same
* time. By default MDBX prevent this in most cases by tracking databases
* opening and return MDBX_BUSY if anyone LCK-file is already open.
@@ -451,7 +467,7 @@
* above.
*
* - An MDBX database configuration will often reserve considerable unused
- * memory address space and maybe file size for future growth. This does
+ * memory address space and maybe file size for future growth. This does
* not use actual memory or disk space, but users may need to understand
* the difference so they won't be scared off.
*
@@ -822,13 +838,24 @@ typedef struct iovec MDBX_val;
* but MDBX_DBG_ASSERT, MDBX_DBG_AUDIT and MDBX_DBG_JITTER only if libmdbx
* builded with MDBX_DEBUG. */
-#define MDBX_DBG_ASSERT 1 /* Enable assertion checks */
-#define MDBX_DBG_AUDIT 2 /* Enable pages usage audit at commit transactions */
-#define MDBX_DBG_JITTER 4 /* Enable small random delays in critical points */
-#define MDBX_DBG_DUMP /* Include or not meta-pages in coredump files, MAY \
- affect performance in MDBX_WRITEMAP mode */ \
- 8
-#define MDBX_DBG_LEGACY_MULTIOPEN 16 /* Enable multi-opening environment(s) */
+/* Enable assertion checks */
+#define MDBX_DBG_ASSERT 1
+
+/* Enable pages usage audit at commit transactions */
+#define MDBX_DBG_AUDIT 2
+
+/* Enable small random delays in critical points */
+#define MDBX_DBG_JITTER 4
+
+/* Include or not meta-pages in coredump files,
+ * MAY affect performance in MDBX_WRITEMAP mode */
+#define MDBX_DBG_DUMP 8
+
+/* Allow multi-opening environment(s) */
+#define MDBX_DBG_LEGACY_MULTIOPEN 16
+
+/* Allow read and write transactions overlapping for the same thread */
+#define MDBX_DBG_LEGACY_OVERLAP 32
/* A debug-logger callback function,
* called before printing the message and aborting.
@@ -838,7 +865,12 @@ typedef struct iovec MDBX_val;
typedef void MDBX_debug_func(int loglevel, const char *function, int line,
const char *msg, va_list args);
-/* FIXME: Complete description */
+/* Don't change current settings */
+#define MDBX_LOG_DONTCHANGE (-1)
+#define MDBX_DBG_DONTCHANGE (-1)
+#define MDBX_LOGGER_DONTCHANGE ((MDBX_debug_func *)(intptr_t)-1)
+
+/* Setup global log-level, debug options and debug logger. */
LIBMDBX_API int mdbx_setup_debug(int loglevel, int flags,
MDBX_debug_func *logger);
@@ -1290,17 +1322,26 @@ LIBMDBX_API const char *mdbx_dump_val(const MDBX_val *key, char *const buf,
/**** DATABASE FLAGS **********************************************************/
/* Use reverse string keys */
#define MDBX_REVERSEKEY 0x02u
+
/* Use sorted duplicates */
#define MDBX_DUPSORT 0x04u
+
/* Numeric keys in native byte order, either uint32_t or uint64_t.
- * The keys must all be of the same size. */
+ * The keys must all be of the same size and must be aligned while passing as
+ * arguments. */
#define MDBX_INTEGERKEY 0x08u
+
/* With MDBX_DUPSORT, sorted dup items have fixed size */
#define MDBX_DUPFIXED 0x10u
-/* With MDBX_DUPSORT, dups are MDBX_INTEGERKEY-style integers */
+
+/* With MDBX_DUPSORT, dups are MDBX_INTEGERKEY-style integers.
+ * The data values must all be of the same size and must be aligned while
+ * passing as arguments. */
#define MDBX_INTEGERDUP 0x20u
+
/* With MDBX_DUPSORT, use reverse string dups */
#define MDBX_REVERSEDUP 0x40u
+
/* Create DB if not already existing */
#define MDBX_CREATE 0x40000u
@@ -1380,56 +1421,82 @@ typedef enum MDBX_cursor_op {
/* key/data pair already exists */
#define MDBX_KEYEXIST (-30799)
+
/* key/data pair not found (EOF) */
#define MDBX_NOTFOUND (-30798)
+
/* Requested page not found - this usually indicates corruption */
#define MDBX_PAGE_NOTFOUND (-30797)
+
/* Database is corrupted (page was wrong type and so on) */
#define MDBX_CORRUPTED (-30796)
+
/* Environment had fatal error (i.e. update of meta page failed and so on) */
#define MDBX_PANIC (-30795)
+
/* DB file version mismatch with libmdbx */
#define MDBX_VERSION_MISMATCH (-30794)
+
/* File is not a valid MDBX file */
#define MDBX_INVALID (-30793)
+
/* Environment mapsize reached */
#define MDBX_MAP_FULL (-30792)
+
/* Environment maxdbs reached */
#define MDBX_DBS_FULL (-30791)
+
/* Environment maxreaders reached */
#define MDBX_READERS_FULL (-30790)
-/* Txn has too many dirty pages */
+
+/* Transaction has too many dirty pages, i.e transaction too big */
#define MDBX_TXN_FULL (-30788)
+
/* Cursor stack too deep - internal error */
#define MDBX_CURSOR_FULL (-30787)
+
/* Page has not enough space - internal error */
#define MDBX_PAGE_FULL (-30786)
-/* Database contents grew beyond environment mapsize */
+
+/* Database contents grew beyond environment mapsize and engine was
+ * unable to extend mapping, e.g. since address space is unavailable or busy */
#define MDBX_MAP_RESIZED (-30785)
-/* Operation and DB incompatible, or DB type changed. This can mean:
+
+/* Environment or database is not compatible with the requested operation
+ * or the specified flags. This can mean:
* - The operation expects an MDBX_DUPSORT / MDBX_DUPFIXED database.
* - Opening a named DB when the unnamed DB has MDBX_DUPSORT/MDBX_INTEGERKEY.
* - Accessing a data record as a database, or vice versa.
* - The database was dropped and recreated with different flags. */
#define MDBX_INCOMPATIBLE (-30784)
-/* Invalid reuse of reader locktable slot */
+
+/* Invalid reuse of reader locktable slot,
+ * e.g. read-transaction already run for current thread */
#define MDBX_BAD_RSLOT (-30783)
-/* Transaction must abort, has a child, or is invalid */
+
+/* Transaction is not valid for requested operation,
+ * e.g. had errored and be must aborted, has a child, or is invalid */
#define MDBX_BAD_TXN (-30782)
-/* Unsupported size of key/DB name/data, or wrong DUPFIXED size */
+
+/* Invalid size or alignment of key or data for target database,
+ * either invalid subDB name */
#define MDBX_BAD_VALSIZE (-30781)
-/* The specified DBI was changed unexpectedly */
+
+/* The specified DBI-handle is invalid
+ * or changed by another thread/transaction */
#define MDBX_BAD_DBI (-30780)
-/* Unexpected problem - txn should abort */
+
+/* Unexpected internal error, transaction should be aborted */
#define MDBX_PROBLEM (-30779)
+
+/* The last LMDB-compatible defined error code */
+#define MDBX_LAST_LMDB_ERRCODE MDBX_PROBLEM
+
/* Another write transaction is running or environment is already used while
* opening with MDBX_EXCLUSIVE flag */
#define MDBX_BUSY (-30778)
-/* The last defined error code */
-#define MDBX_LAST_ERRCODE MDBX_BUSY
-/* The mdbx_put() or mdbx_replace() was called for key,
- * that has more that one associated value. */
+/* The specified key has more than one associated value */
#define MDBX_EMULTIVAL (-30421)
/* Bad signature of a runtime object(s), this can mean:
@@ -1437,8 +1504,8 @@ typedef enum MDBX_cursor_op {
* - ABI version mismatch (rare case); */
#define MDBX_EBADSIGN (-30420)
-/* Database should be recovered, but this could NOT be done automatically
- * right now (e.g. in readonly mode and so forth). */
+/* Database should be recovered, but this could NOT be done for now
+ * since it opened in read-only mode */
#define MDBX_WANNA_RECOVERY (-30419)
/* The given key value is mismatched to the current cursor position,
@@ -1453,6 +1520,9 @@ typedef enum MDBX_cursor_op {
* e.g. a transaction that started by another thread. */
#define MDBX_THREAD_MISMATCH (-30416)
+/* Overlapping read and write transactions for the current thread */
+#define MDBX_TXN_OVERLAPPING (-30415)
+
/**** FUNCTIONS & RELATED STRUCTURES ******************************************/
/* Return a string describing a given error code.
@@ -1579,8 +1649,8 @@ LIBMDBX_API int mdbx_env_open(MDBX_env *env, const char *pathname,
*
* [in] env An environment handle returned by mdbx_env_create(). It must
* have already been opened successfully.
- * [in] dest The directory in which the copy will reside. This directory
- * must already exist and be writable but must otherwise be empty.
+ * [in] dest The pathname of a file in which the copy will reside. This file
+ * must not be already exist, but parent directory must be writable.
* [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:
@@ -2471,9 +2541,6 @@ typedef int(MDBX_cmp_func)(const MDBX_val *a, const MDBX_val *b);
* In contrast to LMDB, the MDBX allow this function to be called from multiple
* concurrent transactions or threads in the same process.
*
- * Legacy mdbx_dbi_open() correspond to calling mdbx_dbi_open_ex() with the null
- * keycmp and datacmp arguments.
- *
* To use named database (with name != NULL), mdbx_env_set_maxdbs()
* must be called before opening the environment. Table names are
* keys in the internal unnamed database, and may be read but not written.
@@ -2495,7 +2562,7 @@ typedef int(MDBX_cmp_func)(const MDBX_val *a, const MDBX_val *b);
* - MDBX_INTEGERKEY
* Keys are binary integers in native byte order, either uin32_t or
* uint64_t, and will be sorted as such. The keys must all be of the
- * same size.
+ * same size and must be aligned while passing as arguments.
* - MDBX_DUPFIXED
* This flag may only be used in combination with MDBX_DUPSORT. This
* option tells the library that the data items for this database are
@@ -2505,7 +2572,8 @@ typedef int(MDBX_cmp_func)(const MDBX_val *a, const MDBX_val *b);
* to retrieve multiple items at once.
* - MDBX_INTEGERDUP
* This option specifies that duplicate data items are binary integers,
- * similar to MDBX_INTEGERKEY keys.
+ * similar to MDBX_INTEGERKEY keys. The data values must all be of the
+ * same size and must be aligned while passing as arguments.
* - MDBX_REVERSEDUP
* This option specifies that duplicate data items should be compared as
* strings in reverse order (the comparison is performed in the direction
@@ -2514,10 +2582,19 @@ typedef int(MDBX_cmp_func)(const MDBX_val *a, const MDBX_val *b);
* Create the named database if it doesn't exist. This option is not
* allowed in a read-only transaction or a read-only environment.
*
+ * [out] dbi Address where the new MDBX_dbi handle will be stored.
+ *
+ * For mdbx_dbi_open_ex() additional arguments allow you to set custom
+ * comparison functions for keys and values (for multimaps).
+ * However, I recommend not using custom comparison functions, but instead
+ * converting the keys to one of the forms that are suitable for built-in
+ * comparators. The main reason for this is that you can't use mdbx_chk tools
+ * with a custom comparators. For instance take look to the mdbx_key_from_xxx()
+ * functions.
+ *
* [in] keycmp Optional custom key comparison function for a database.
* [in] datacmp Optional custom data comparison function for a database, takes
* effect only if database was opened with the MDB_DUPSORT flag.
- * [out] dbi Address where the new MDBX_dbi handle will be stored.
*
* Returns A non-zero error value on failure and 0 on success, some
* possible errors are:
@@ -2535,6 +2612,25 @@ LIBMDBX_API int mdbx_dbi_open_ex(MDBX_txn *txn, const char *name,
LIBMDBX_API int mdbx_dbi_open(MDBX_txn *txn, const char *name, unsigned flags,
MDBX_dbi *dbi);
+/* Key-making functions to avoid custom comparators.
+ *
+ * The mdbx_key_from_jsonInteger() build key which are comparable with
+ * keys created by mdbx_key_from_double(). So this allow mix int64 and IEEE754
+ * double values in one index for JSON-numbers with restriction for integer
+ * numbers range corresponding to RFC-7159 (i.e. [-(2**53)+1, (2**53)-1].
+ * See bottom of page 6 at https://tools.ietf.org/html/rfc7159 */
+LIBMDBX_API uint64_t mdbx_key_from_jsonInteger(const int64_t json_integer);
+LIBMDBX_API uint64_t mdbx_key_from_double(const double ieee754_64bit);
+LIBMDBX_API uint64_t mdbx_key_from_ptrdouble(const double *const ieee754_64bit);
+LIBMDBX_API uint32_t mdbx_key_from_float(const float ieee754_32bit);
+LIBMDBX_API uint32_t mdbx_key_from_ptrfloat(const float *const ieee754_32bit);
+__inline uint64_t mdbx_key_from_int64(const int64_t i64) {
+ return UINT64_C(0x8000000000000000) + i64;
+}
+__inline uint32_t mdbx_key_from_int32(const int32_t i32) {
+ return UINT32_C(0x80000000) + i32;
+}
+
/* Retrieve statistics for a database.
*
* [in] txn A transaction handle returned by mdbx_txn_begin().
@@ -3382,7 +3478,7 @@ typedef uint_fast64_t mdbx_attr_t;
* [in] flags Options for this operation. This parameter must be set to 0
* or one of the values described here:
*
- * - MDBX_CURRENT
+ * - MDBX_CURRENT
* Replace the item at the current cursor position. The key parameter
* must still be provided, and must match it, otherwise the function
* return MDBX_EKEYMISMATCH.
@@ -3464,8 +3560,8 @@ LIBMDBX_API int mdbx_put_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
*
* Returns A non-zero error value on failure and 0 on success, some
* possible errors are:
- * - MDBX_NOTFOUND = the key-value pair was not in the database.
- * - MDBX_EINVAL = an invalid parameter was specified. */
+ * - MDBX_NOTFOUND = the key-value pair was not in the database.
+ * - MDBX_EINVAL = an invalid parameter was specified. */
LIBMDBX_API int mdbx_set_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
MDBX_val *data, mdbx_attr_t attr);
diff --git a/libs/libmdbx/src/src/elements/core.c b/libs/libmdbx/src/src/elements/core.c
index 2cd3445e9b..d1cf8979ae 100644
--- a/libs/libmdbx/src/src/elements/core.c
+++ b/libs/libmdbx/src/src/elements/core.c
@@ -40,16 +40,6 @@
/*------------------------------------------------------------------------------
* Internal inlines */
-static __pure_function __always_inline bool is_powerof2(size_t x) {
- return (x & (x - 1)) == 0;
-}
-
-static __pure_function __always_inline size_t
-roundup_powerof2(size_t value, size_t granularity) {
- assert(is_powerof2(granularity));
- return (value + granularity - 1) & ~(granularity - 1);
-}
-
static __pure_function unsigned log2n(size_t value) {
assert(value > 0 && value < INT32_MAX && is_powerof2(value));
assert((value & -(int32_t)value) == value);
@@ -751,7 +741,9 @@ static __always_inline bool atomic_cas64(volatile uint64_t *p, uint64_t c,
uint64_t v) {
#if defined(ATOMIC_VAR_INIT) || defined(ATOMIC_LLONG_LOCK_FREE)
STATIC_ASSERT(sizeof(long long) >= sizeof(uint64_t));
+#ifndef __COVERITY__
STATIC_ASSERT(atomic_is_lock_free(p));
+#endif /* Workaround for Coverity */
return atomic_compare_exchange_strong((_Atomic uint64_t *)p, &c, v);
#elif defined(__GNUC__) || defined(__clang__)
return __sync_bool_compare_and_swap(p, c, v);
@@ -770,7 +762,9 @@ static __always_inline bool atomic_cas32(volatile uint32_t *p, uint32_t c,
uint32_t v) {
#if defined(ATOMIC_VAR_INIT) || defined(ATOMIC_INT_LOCK_FREE)
STATIC_ASSERT(sizeof(int) >= sizeof(uint32_t));
+#ifndef __COVERITY__
STATIC_ASSERT(atomic_is_lock_free(p));
+#endif /* Workaround for Coverity */
return atomic_compare_exchange_strong((_Atomic uint32_t *)p, &c, v);
#elif defined(__GNUC__) || defined(__clang__)
return __sync_bool_compare_and_swap(p, c, v);
@@ -787,7 +781,9 @@ static __always_inline bool atomic_cas32(volatile uint32_t *p, uint32_t c,
static __always_inline uint32_t atomic_add32(volatile uint32_t *p, uint32_t v) {
#if defined(ATOMIC_VAR_INIT) || defined(ATOMIC_INT_LOCK_FREE)
STATIC_ASSERT(sizeof(int) >= sizeof(uint32_t));
+#ifndef __COVERITY__
STATIC_ASSERT(atomic_is_lock_free(p));
+#endif /* Workaround for Coverity */
return atomic_fetch_add((_Atomic uint32_t *)p, v);
#elif defined(__GNUC__) || defined(__clang__)
return __sync_fetch_and_add(p, v);
@@ -1466,7 +1462,8 @@ static int lcklist_detach_locked(MDBX_env *env) {
/*------------------------------------------------------------------------------
* LY: State of the art quicksort-based sorting, with internal stack
- * and bitonic-sort for small chunks. */
+ * and network-sort for small chunks.
+ * Thanks to John M. Gamble for the http://pages.ripco.net/~jgamble/nw.html */
#define SORT_CMP_SWAP(TYPE, CMP, a, b) \
do { \
@@ -1476,19 +1473,36 @@ static int lcklist_detach_locked(MDBX_env *env) {
(b) = swap_cmp ? b : swap_tmp; \
} while (0)
-#define SORT_BITONIC_2(TYPE, CMP, begin) \
- do { \
- SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
- } while (0)
-
-#define SORT_BITONIC_3(TYPE, CMP, begin) \
+// 3 comparators, 3 parallel operations
+// o-----^--^--o
+// | |
+// o--^--|--v--o
+// | |
+// o--v--v-----o
+//
+// [[1,2]]
+// [[0,2]]
+// [[0,1]]
+#define SORT_NETWORK_3(TYPE, CMP, begin) \
do { \
SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]); \
SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]); \
SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
} while (0)
-#define SORT_BITONIC_4(TYPE, CMP, begin) \
+// 5 comparators, 3 parallel operations
+// o--^--^--------o
+// | |
+// o--v--|--^--^--o
+// | | |
+// o--^--v--|--v--o
+// | |
+// o--v-----v-----o
+//
+// [[0,1],[2,3]]
+// [[0,2],[1,3]]
+// [[1,2]]
+#define SORT_NETWORK_4(TYPE, CMP, begin) \
do { \
SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]); \
@@ -1497,20 +1511,55 @@ static int lcklist_detach_locked(MDBX_env *env) {
SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]); \
} while (0)
-#define SORT_BITONIC_5(TYPE, CMP, begin) \
+// 9 comparators, 5 parallel operations
+// o--^--^-----^-----------o
+// | | |
+// o--|--|--^--v-----^--^--o
+// | | | | |
+// o--|--v--|--^--^--|--v--o
+// | | | | |
+// o--|-----v--|--v--|--^--o
+// | | | |
+// o--v--------v-----v--v--o
+//
+// [[0,4],[1,3]]
+// [[0,2]]
+// [[2,4],[0,1]]
+// [[2,3],[1,4]]
+// [[1,2],[3,4]]
+#define SORT_NETWORK_5(TYPE, CMP, begin) \
do { \
- SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]); \
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]); \
SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[3]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]); \
SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]); \
} while (0)
-#define SORT_BITONIC_6(TYPE, CMP, begin) \
+// 12 comparators, 6 parallel operations
+// o-----^--^--^-----------------o
+// | | |
+// o--^--|--v--|--^--------^-----o
+// | | | | |
+// o--v--v-----|--|--^--^--|--^--o
+// | | | | | |
+// o-----^--^--v--|--|--|--v--v--o
+// | | | | |
+// o--^--|--v-----v--|--v--------o
+// | | |
+// o--v--v-----------v-----------o
+//
+// [[1,2],[4,5]]
+// [[0,2],[3,5]]
+// [[0,1],[3,4],[2,5]]
+// [[0,3],[1,4]]
+// [[2,4],[1,3]]
+// [[2,3]]
+#define SORT_NETWORK_6(TYPE, CMP, begin) \
do { \
SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]); \
SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]); \
@@ -1526,50 +1575,122 @@ static int lcklist_detach_locked(MDBX_env *env) {
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]); \
} while (0)
-#define SORT_BITONIC_7(TYPE, CMP, begin) \
+// 16 comparators, 6 parallel operations
+// o--^--------^-----^-----------------o
+// | | |
+// o--|--^-----|--^--v--------^--^-----o
+// | | | | | |
+// o--|--|--^--v--|--^-----^--|--v-----o
+// | | | | | | |
+// o--|--|--|-----v--|--^--v--|--^--^--o
+// | | | | | | | |
+// o--v--|--|--^-----v--|--^--v--|--v--o
+// | | | | | |
+// o-----v--|--|--------v--v-----|--^--o
+// | | | |
+// o--------v--v-----------------v--v--o
+//
+// [[0,4],[1,5],[2,6]]
+// [[0,2],[1,3],[4,6]]
+// [[2,4],[3,5],[0,1]]
+// [[2,3],[4,5]]
+// [[1,4],[3,6]]
+// [[1,2],[3,4],[5,6]]
+#define SORT_NETWORK_7(TYPE, CMP, begin) \
do { \
- SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]); \
SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]); \
SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[5]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[3]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[5]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]); \
SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]); \
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]); \
- } while (0)
-
-#define SORT_BITONIC_8(TYPE, CMP, begin) \
- do { \
+ SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]); \
SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]); \
SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[7]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[6]); \
SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]); \
SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]); \
+ } while (0)
+
+// 19 comparators, 6 parallel operations
+// o--^--------^-----^-----------------o
+// | | |
+// o--|--^-----|--^--v--------^--^-----o
+// | | | | | |
+// o--|--|--^--v--|--^-----^--|--v-----o
+// | | | | | | |
+// o--|--|--|--^--v--|--^--v--|--^--^--o
+// | | | | | | | | |
+// o--v--|--|--|--^--v--|--^--v--|--v--o
+// | | | | | | |
+// o-----v--|--|--|--^--v--v-----|--^--o
+// | | | | | |
+// o--------v--|--v--|--^--------v--v--o
+// | | |
+// o-----------v-----v--v--------------o
+//
+// [[0,4],[1,5],[2,6],[3,7]]
+// [[0,2],[1,3],[4,6],[5,7]]
+// [[2,4],[3,5],[0,1],[6,7]]
+// [[2,3],[4,5]]
+// [[1,4],[3,6]]
+// [[1,2],[3,4],[5,6]]
+#define SORT_NETWORK_8(TYPE, CMP, begin) \
+ do { \
SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[4]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[7]); \
SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[5]); \
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[6]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]); \
- SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[6]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[7]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[2]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[3]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[6]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[7]); \
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[4]); \
SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[5]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[6], begin[7]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[4]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[6]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[2]); \
SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]); \
} while (0)
-#define SORT_BITONIC_9(TYPE, CMP, begin) \
+// 25 comparators, 9 parallel operations
+// o--^-----^--^-----^-----------------------------------o
+// | | | |
+// o--v--^--v--|-----|--^-----^-----------^--------------o
+// | | | | | |
+// o-----v-----|-----|--|-----|--^-----^--|--^-----^--^--o
+// | | | | | | | | | |
+// o--^-----^--v--^--v--|-----|--|-----|--v--|-----|--v--o
+// | | | | | | | | |
+// o--v--^--v-----|-----v--^--v--|-----|-----|--^--v-----o
+// | | | | | | |
+// o-----v--------|--------|-----v--^--v--^--|--|--^-----o
+// | | | | | | |
+// o--^-----^-----v--------|--------|-----|--v--v--v-----o
+// | | | | |
+// o--v--^--v--------------v--------|-----v--------------o
+// | |
+// o-----v--------------------------v--------------------o
+//
+// [[0,1],[3,4],[6,7]]
+// [[1,2],[4,5],[7,8]]
+// [[0,1],[3,4],[6,7],[2,5]]
+// [[0,3],[1,4],[5,8]]
+// [[3,6],[4,7],[2,5]]
+// [[0,3],[1,4],[5,7],[2,6]]
+// [[1,3],[4,6]]
+// [[2,4],[5,6]]
+// [[2,3]]
+#define SORT_NETWORK_9(TYPE, CMP, begin) \
do { \
SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[4]); \
@@ -1598,7 +1719,37 @@ static int lcklist_detach_locked(MDBX_env *env) {
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]); \
} while (0)
-#define SORT_BITONIC_10(TYPE, CMP, begin) \
+// 29 comparators, 9 parallel operations
+// o--------------^-----^--^--^-----------------------o
+// | | | |
+// o-----------^--|--^--|--|--v--^--------^-----------o
+// | | | | | | |
+// o--------^--|--|--|--|--v--^--v-----^--|--^--------o
+// | | | | | | | | |
+// o-----^--|--|--|--|--v--^--|-----^--|--v--v--^-----o
+// | | | | | | | | | |
+// o--^--|--|--|--|--v-----|--v--^--|--|--^-----v--^--o
+// | | | | | | | | | | |
+// o--|--|--|--|--v--^-----|--^--|--v--v--|-----^--v--o
+// | | | | | | | | | |
+// o--|--|--|--v--^--|-----v--|--v--^-----|--^--v-----o
+// | | | | | | | | |
+// o--|--|--v-----|--|--^-----v--^--|-----v--v--------o
+// | | | | | | |
+// o--|--v--------|--v--|--^-----v--v-----------------o
+// | | | |
+// o--v-----------v-----v--v--------------------------o
+//
+// [[4,9],[3,8],[2,7],[1,6],[0,5]]
+// [[1,4],[6,9],[0,3],[5,8]]
+// [[0,2],[3,6],[7,9]]
+// [[0,1],[2,4],[5,7],[8,9]]
+// [[1,2],[4,6],[7,8],[3,5]]
+// [[2,5],[6,8],[1,3],[4,7]]
+// [[2,3],[6,7]]
+// [[3,4],[5,6]]
+// [[4,5]]
+#define SORT_NETWORK_10(TYPE, CMP, begin) \
do { \
SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[9]); \
SORT_CMP_SWAP(TYPE, CMP, begin[3], begin[8]); \
@@ -1631,7 +1782,39 @@ static int lcklist_detach_locked(MDBX_env *env) {
SORT_CMP_SWAP(TYPE, CMP, begin[4], begin[5]); \
} while (0)
-#define SORT_BITONIC_11(TYPE, CMP, begin) \
+// 35 comparators, 9 parallel operations
+// o--^-----^-----------------^--------^--------------------o
+// | | | |
+// o--v--^--|--^--^--------^--|--------|--^-----------------o
+// | | | | | | | |
+// o--^--|--v--v--|-----^--|--|--------|--|-----^--^--------o
+// | | | | | | | | | |
+// o--v--v--------|-----|--|--|--^-----|--|--^--v--|--^--^--o
+// | | | | | | | | | | |
+// o--^-----^-----|-----|--|--v--|--^--v--v--|-----v--|--v--o
+// | | | | | | | | |
+// o--v--^--|--^--v--^--|--v-----|--|--------|--------v--^--o
+// | | | | | | | | |
+// o--^--|--v--v--^--|--v--^-----|--|--------|--------^--v--o
+// | | | | | | | | |
+// o--v--v--------|--|-----|-----v--|--^-----|-----^--|--^--o
+// | | | | | | | | |
+// o--^--^--------|--|-----|--------v--|-----v--^--|--v--v--o
+// | | | | | | | |
+// o--v--|--^-----|--v-----|-----------|--------v--v--------o
+// | | | | |
+// o-----v--v-----v--------v-----------v--------------------o
+//
+// [[0,1],[2,3],[4,5],[6,7],[8,9]]
+// [[1,3],[5,7],[0,2],[4,6],[8,10]]
+// [[1,2],[5,6],[9,10],[0,4],[3,7]]
+// [[1,5],[6,10],[4,8]]
+// [[5,9],[2,6],[0,4],[3,8]]
+// [[1,5],[6,10],[2,3],[8,9]]
+// [[1,4],[7,10],[3,5],[6,8]]
+// [[2,4],[7,9],[5,6]]
+// [[3,4],[7,8]]
+#define SORT_NETWORK_11(TYPE, CMP, begin) \
do { \
SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]); \
@@ -1670,7 +1853,41 @@ static int lcklist_detach_locked(MDBX_env *env) {
SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[8]); \
} while (0)
-#define SORT_BITONIC_12(TYPE, CMP, begin) \
+// 39 comparators, parallel operations
+// o--^-----^-----------------^--------^--------------------o
+// | | | |
+// o--v--^--|--^--^--------^--|--------|--^-----------------o
+// | | | | | | | |
+// o--^--|--v--v--|-----^--|--|--------|--|-----^--^--------o
+// | | | | | | | | | |
+// o--v--v--------|-----|--|--|--^-----|--|--^--v--|--^--^--o
+// | | | | | | | | | | |
+// o--^-----^-----|-----|--|--v--|--^--v--v--|-----v--|--v--o
+// | | | | | | | | |
+// o--v--^--|--^--v--^--|--v-----|--|--------|--------v--^--o
+// | | | | | | | | |
+// o--^--|--v--v--^--|--v--^-----|--|--------|--------^--v--o
+// | | | | | | | | |
+// o--v--v--------|--|-----|--^--v--|--^--^--|-----^--|--^--o
+// | | | | | | | | | | |
+// o--^-----^-----|--|-----|--|-----v--|--|--v--^--|--v--v--o
+// | | | | | | | | | |
+// o--v--^--|--^--|--v-----|--|--------|--|-----v--v--------o
+// | | | | | | | |
+// o--^--|--v--v--v--------v--|--------|--v-----------------o
+// | | | |
+// o--v--v--------------------v--------v--------------------o
+//
+// [[0,1],[2,3],[4,5],[6,7],[8,9],[10,11]]
+// [[1,3],[5,7],[9,11],[0,2],[4,6],[8,10]]
+// [[1,2],[5,6],[9,10],[0,4],[7,11]]
+// [[1,5],[6,10],[3,7],[4,8]]
+// [[5,9],[2,6],[0,4],[7,11],[3,8]]
+// [[1,5],[6,10],[2,3],[8,9]]
+// [[1,4],[7,10],[3,5],[6,8]]
+// [[2,4],[7,9],[5,6]]
+// [[3,4],[7,8]]
+#define SORT_NETWORK_12(TYPE, CMP, begin) \
do { \
SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]); \
@@ -1713,7 +1930,44 @@ static int lcklist_detach_locked(MDBX_env *env) {
SORT_CMP_SWAP(TYPE, CMP, begin[7], begin[8]); \
} while (0)
-#define SORT_BITONIC_13(TYPE, CMP, begin) \
+// 45 comparators, 10 parallel operations
+// o--------^--^-----^-----------------------------^-----------------o
+// | | | |
+// o--^-----|--v-----|-----^--------------^-----^--|-----^-----------o
+// | | | | | | | |
+// o--|-----|--^--^--v-----|--------------|--^--|--|--^--v--^--------o
+// | | | | | | | | | | |
+// o--|--^--|--|--v-----^--|--------^-----|--|--v--|--|--^--v-----^--o
+// | | | | | | | | | | | | |
+// o--|--v--|--|--^-----|--v-----^--v-----|--|--^--|--|--|--^--^--v--o
+// | | | | | | | | | | | | | |
+// o--|--^--|--|--|--^--|--------|-----^--|--|--|--v--v--v--|--v--^--o
+// | | | | | | | | | | | | | |
+// o--|--|--|--v--v--|--|--^-----|--^--v--|--v--|--^--------v--^--v--o
+// | | | | | | | | | | | |
+// o--v--|--|-----^--|--v--|--^--|--|-----v-----v--|--^--------v-----o
+// | | | | | | | | | |
+// o-----v--|--^--|--|-----|--v--|--|--^-----^-----v--v--^-----------o
+// | | | | | | | | | |
+// o--^-----|--|--|--v-----|-----v--|--v--^--|--^--------v-----------o
+// | | | | | | | | |
+// o--|-----|--|--|--^-----|--------v--^--|--v--v--------------------o
+// | | | | | | | |
+// o--v-----|--v--|--v-----|--^--------v--v--------------------------o
+// | | | |
+// o--------v-----v--------v--v--------------------------------------o
+//
+// [[1,7],[9,11],[3,4],[5,8],[0,12],[2,6]]
+// [[0,1],[2,3],[4,6],[8,11],[7,12],[5,9]]
+// [[0,2],[3,7],[10,11],[1,4],[6,12]]
+// [[7,8],[11,12],[4,9],[6,10]]
+// [[3,4],[5,6],[8,9],[10,11],[1,7]]
+// [[2,6],[9,11],[1,3],[4,7],[8,10],[0,5]]
+// [[2,5],[6,8],[9,10]]
+// [[1,2],[3,5],[7,8],[4,6]]
+// [[2,3],[4,5],[6,7],[8,9]]
+// [[3,4],[5,6]]
+#define SORT_NETWORK_13(TYPE, CMP, begin) \
do { \
SORT_CMP_SWAP(TYPE, CMP, begin[1], begin[7]); \
SORT_CMP_SWAP(TYPE, CMP, begin[9], begin[11]); \
@@ -1762,7 +2016,53 @@ static int lcklist_detach_locked(MDBX_env *env) {
SORT_CMP_SWAP(TYPE, CMP, begin[5], begin[6]); \
} while (0)
-#define SORT_BITONIC_14(TYPE, CMP, begin) \
+/* *INDENT-OFF* */
+/* clang-format off */
+
+// 51 comparators, 10 parallel operations
+// o--^--^-----^-----------^-----------------------------------------------------------o
+// | | | |
+// o--v--|--^--|--^--------|--^-----^-----------------------^--------------------------o
+// | | | | | | | |
+// o--^--v--|--|--|--^-----|--|--^--v-----------------------|--^--^--------------------o
+// | | | | | | | | | | |
+// o--v-----v--|--|--|--^--|--|--|--^--------------^--------|--|--|--^--^--^-----------o
+// | | | | | | | | | | | | | | |
+// o--^--^-----v--|--|--|--|--|--|--|--^-----------|-----^--v--|--v--|--|--v-----------o
+// | | | | | | | | | | | | | | |
+// o--v--|--^-----v--|--|--|--|--|--|--|--^--^-----|-----|-----|--^--|--v-----^--------o
+// | | | | | | | | | | | | | | | | |
+// o--^--v--|--------v--|--|--|--|--|--|--|--|--^--|-----|-----|--v--|-----^--v-----^--o
+// | | | | | | | | | | | | | | | | |
+// o--v-----v-----------v--|--|--|--|--|--|--|--|--|--^--|--^--|-----|--^--|--^--^--v--o
+// | | | | | | | | | | | | | | | | | |
+// o--^--^-----^-----------v--|--|--|--|--|--|--|--|--|--v--|--v-----v--|--v--|--v--^--o
+// | | | | | | | | | | | | | | | |
+// o--v--|--^--|--^-----------v--|--|--|--|--|--v--|--|-----|--^--------|-----v--^--v--o
+// | | | | | | | | | | | | | | |
+// o--^--v--|--|--|--------------v--|--|--|--v-----|--|-----|--v--------|--^-----v-----o
+// | | | | | | | | | | | |
+// o--v-----v--|--|-----------------v--|--|--------|--v-----|--^--------|--|--^--------o
+// | | | | | | | | | |
+// o--^--------v--|--------------------v--|--------v--------|--|--------v--v--v--------o
+// | | | | |
+// o--v-----------v-----------------------v-----------------v--v-----------------------o
+//
+// [[0,1],[2,3],[4,5],[6,7],[8,9],[10,11],[12,13]]
+// [[0,2],[4,6],[8,10],[1,3],[5,7],[9,11]]
+// [[0,4],[8,12],[1,5],[9,13],[2,6],[3,7]]
+// [[0,8],[1,9],[2,10],[3,11],[4,12],[5,13]]
+// [[5,10],[6,9],[3,12],[7,11],[1,2],[4,8]]
+// [[1,4],[7,13],[2,8],[5,6],[9,10]]
+// [[2,4],[11,13],[3,8],[7,12]]
+// [[6,8],[10,12],[3,5],[7,9]]
+// [[3,4],[5,6],[7,8],[9,10],[11,12]]
+// [[6,7],[8,9]]
+
+/* *INDENT-ON* */
+/* clang-format on */
+
+#define SORT_NETWORK_14(TYPE, CMP, begin) \
do { \
SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]); \
@@ -1817,7 +2117,55 @@ static int lcklist_detach_locked(MDBX_env *env) {
SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]); \
} while (0)
-#define SORT_BITONIC_15(TYPE, CMP, begin) \
+/* *INDENT-OFF* */
+/* clang-format off */
+
+// 56 comparators, 10 parallel operations
+// o--^--^-----^-----------^--------------------------------------------------------------o
+// | | | |
+// o--v--|--^--|--^--------|--^-----^--------------------------^--------------------------o
+// | | | | | | | |
+// o--^--v--|--|--|--^-----|--|--^--v--------------------------|--^--^--------------------o
+// | | | | | | | | | | |
+// o--v-----v--|--|--|--^--|--|--|--^-----------------^--------|--|--|--^--^--^-----------o
+// | | | | | | | | | | | | | | |
+// o--^--^-----v--|--|--|--|--|--|--|--^--------------|-----^--v--|--v--|--|--v-----------o
+// | | | | | | | | | | | | | | |
+// o--v--|--^-----v--|--|--|--|--|--|--|--^-----^-----|-----|-----|--^--|--v-----^--------o
+// | | | | | | | | | | | | | | | | |
+// o--^--v--|--------v--|--|--|--|--|--|--|--^--|--^--|-----|-----|--v--|-----^--v-----^--o
+// | | | | | | | | | | | | | | | | | |
+// o--v-----v-----------v--|--|--|--|--|--|--|--|--|--|--^--|--^--|-----|--^--|--^--^--v--o
+// | | | | | | | | | | | | | | | | | | |
+// o--^--^-----^-----------v--|--|--|--|--|--|--|--|--|--|--v--|--v-----v--|--v--|--v--^--o
+// | | | | | | | | | | | | | | | | |
+// o--v--|--^--|--^-----------v--|--|--|--|--|--|--v--|--|-----|--^--------|-----v--^--v--o
+// | | | | | | | | | | | | | | | |
+// o--^--v--|--|--|--^-----------v--|--|--|--|--v-----|--|-----|--v--------|--^-----v-----o
+// | | | | | | | | | | | | | |
+// o--v-----v--|--|--|--------------v--|--|--|--------|--v-----|--^--^-----|--|--^--------o
+// | | | | | | | | | | | | |
+// o--^--^-----v--|--|-----------------v--|--|--------v--------|--|--|-----v--v--v--------o
+// | | | | | | | | |
+// o--v--|--------v--|--------------------v--|--^--------------v--|--v--------------------o
+// | | | | |
+// o-----v-----------v-----------------------v--v-----------------v-----------------------o
+//
+// [[0,1],[2,3],[4,5],[6,7],[8,9],[10,11],[12,13]]
+// [[0,2],[4,6],[8,10],[12,14],[1,3],[5,7],[9,11]]
+// [[0,4],[8,12],[1,5],[9,13],[2,6],[10,14],[3,7]]
+// [[0,8],[1,9],[2,10],[3,11],[4,12],[5,13],[6,14]]
+// [[5,10],[6,9],[3,12],[13,14],[7,11],[1,2],[4,8]]
+// [[1,4],[7,13],[2,8],[11,14],[5,6],[9,10]]
+// [[2,4],[11,13],[3,8],[7,12]]
+// [[6,8],[10,12],[3,5],[7,9]]
+// [[3,4],[5,6],[7,8],[9,10],[11,12]]
+// [[6,7],[8,9]]
+
+/* *INDENT-ON* */
+/* clang-format on */
+
+#define SORT_NETWORK_15(TYPE, CMP, begin) \
do { \
SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]); \
@@ -1877,7 +2225,57 @@ static int lcklist_detach_locked(MDBX_env *env) {
SORT_CMP_SWAP(TYPE, CMP, begin[8], begin[9]); \
} while (0)
-#define SORT_BITONIC_16(TYPE, CMP, begin) \
+/* *INDENT-OFF* */
+/* clang-format off */
+
+// 60 comparators, 10 parallel operations
+// o--^--^-----^-----------^-----------------------------------------------------------------o
+// | | | |
+// o--v--|--^--|--^--------|--^-----^-----------------------------^--------------------------o
+// | | | | | | | |
+// o--^--v--|--|--|--^-----|--|--^--v-----------------------------|--^--^--------------------o
+// | | | | | | | | | | |
+// o--v-----v--|--|--|--^--|--|--|--^--------------------^--------|--|--|--^--^--^-----------o
+// | | | | | | | | | | | | | | |
+// o--^--^-----v--|--|--|--|--|--|--|--^-----------------|-----^--v--|--v--|--|--v-----------o
+// | | | | | | | | | | | | | | |
+// o--v--|--^-----v--|--|--|--|--|--|--|--^--------^-----|-----|-----|--^--|--v-----^--------o
+// | | | | | | | | | | | | | | | | |
+// o--^--v--|--------v--|--|--|--|--|--|--|--^-----|--^--|-----|-----|--v--|-----^--v-----^--o
+// | | | | | | | | | | | | | | | | | |
+// o--v-----v-----------v--|--|--|--|--|--|--|--^--|--|--|--^--|--^--|-----|--^--|--^--^--v--o
+// | | | | | | | | | | | | | | | | | | | |
+// o--^--^-----^-----------v--|--|--|--|--|--|--|--|--|--|--|--v--|--v-----v--|--v--|--v--^--o
+// | | | | | | | | | | | | | | | | | |
+// o--v--|--^--|--^-----------v--|--|--|--|--|--|--|--v--|--|-----|--^--------|-----v--^--v--o
+// | | | | | | | | | | | | | | | | |
+// o--^--v--|--|--|--^-----------v--|--|--|--|--|--v-----|--|-----|--v--------|--^-----v-----o
+// | | | | | | | | | | | | | | |
+// o--v-----v--|--|--|--^-----------v--|--|--|--|--------|--v-----|--^--^-----|--|--^--------o
+// | | | | | | | | | | | | | | |
+// o--^--^-----v--|--|--|--------------v--|--|--|--------v--------|--|--|-----v--v--v--------o
+// | | | | | | | | | | |
+// o--v--|--^-----v--|--|-----------------v--|--|--^--------------v--|--v--------------------o
+// | | | | | | | |
+// o--^--v--|--------v--|--------------------v--|--v-----------------v-----------------------o
+// | | | |
+// o--v-----v-----------v-----------------------v--------------------------------------------o
+//
+// [[0,1],[2,3],[4,5],[6,7],[8,9],[10,11],[12,13],[14,15]]
+// [[0,2],[4,6],[8,10],[12,14],[1,3],[5,7],[9,11],[13,15]]
+// [[0,4],[8,12],[1,5],[9,13],[2,6],[10,14],[3,7],[11,15]]
+// [[0,8],[1,9],[2,10],[3,11],[4,12],[5,13],[6,14],[7,15]]
+// [[5,10],[6,9],[3,12],[13,14],[7,11],[1,2],[4,8]]
+// [[1,4],[7,13],[2,8],[11,14],[5,6],[9,10]]
+// [[2,4],[11,13],[3,8],[7,12]]
+// [[6,8],[10,12],[3,5],[7,9]]
+// [[3,4],[5,6],[7,8],[9,10],[11,12]]
+// [[6,7],[8,9]]
+
+/* *INDENT-ON* */
+/* clang-format on */
+
+#define SORT_NETWORK_16(TYPE, CMP, begin) \
do { \
SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
SORT_CMP_SWAP(TYPE, CMP, begin[2], begin[3]); \
@@ -1949,49 +2347,49 @@ static int lcklist_detach_locked(MDBX_env *env) {
case 1: \
break; \
case 2: \
- SORT_BITONIC_2(TYPE, CMP, begin); \
+ SORT_CMP_SWAP(TYPE, CMP, begin[0], begin[1]); \
break; \
case 3: \
- SORT_BITONIC_3(TYPE, CMP, begin); \
+ SORT_NETWORK_3(TYPE, CMP, begin); \
break; \
case 4: \
- SORT_BITONIC_4(TYPE, CMP, begin); \
+ SORT_NETWORK_4(TYPE, CMP, begin); \
break; \
case 5: \
- SORT_BITONIC_5(TYPE, CMP, begin); \
+ SORT_NETWORK_5(TYPE, CMP, begin); \
break; \
case 6: \
- SORT_BITONIC_6(TYPE, CMP, begin); \
+ SORT_NETWORK_6(TYPE, CMP, begin); \
break; \
case 7: \
- SORT_BITONIC_7(TYPE, CMP, begin); \
+ SORT_NETWORK_7(TYPE, CMP, begin); \
break; \
case 8: \
- SORT_BITONIC_8(TYPE, CMP, begin); \
+ SORT_NETWORK_8(TYPE, CMP, begin); \
break; \
case 9: \
- SORT_BITONIC_9(TYPE, CMP, begin); \
+ SORT_NETWORK_9(TYPE, CMP, begin); \
break; \
case 10: \
- SORT_BITONIC_10(TYPE, CMP, begin); \
+ SORT_NETWORK_10(TYPE, CMP, begin); \
break; \
case 11: \
- SORT_BITONIC_11(TYPE, CMP, begin); \
+ SORT_NETWORK_11(TYPE, CMP, begin); \
break; \
case 12: \
- SORT_BITONIC_12(TYPE, CMP, begin); \
+ SORT_NETWORK_12(TYPE, CMP, begin); \
break; \
case 13: \
- SORT_BITONIC_13(TYPE, CMP, begin); \
+ SORT_NETWORK_13(TYPE, CMP, begin); \
break; \
case 14: \
- SORT_BITONIC_14(TYPE, CMP, begin); \
+ SORT_NETWORK_14(TYPE, CMP, begin); \
break; \
case 15: \
- SORT_BITONIC_15(TYPE, CMP, begin); \
+ SORT_NETWORK_15(TYPE, CMP, begin); \
break; \
case 16: \
- SORT_BITONIC_16(TYPE, CMP, begin); \
+ SORT_NETWORK_16(TYPE, CMP, begin); \
break; \
}
@@ -2080,8 +2478,10 @@ static int lcklist_detach_locked(MDBX_env *env) {
} \
} \
\
- for (TYPE *scan = begin + 1; scan < end; ++scan) \
- assert(CMP(scan[-1], scan[0])); \
+ if (mdbx_audit_enabled()) { \
+ for (TYPE *scan = begin + 1; scan < end; ++scan) \
+ assert(CMP(scan[-1], scan[0])); \
+ } \
}
/*------------------------------------------------------------------------------
@@ -2120,11 +2520,13 @@ static int lcklist_detach_locked(MDBX_env *env) {
++first; \
} \
\
- for (TYPE_LIST *scan = begin; scan < first; ++scan) \
- assert(CMP(*scan, item)); \
- for (TYPE_LIST *scan = first; scan < end; ++scan) \
- assert(!CMP(*scan, item)); \
- (void)begin, (void)end; \
+ if (mdbx_audit_enabled()) { \
+ for (TYPE_LIST *scan = begin; scan < first; ++scan) \
+ assert(CMP(*scan, item)); \
+ for (TYPE_LIST *scan = first; scan < end; ++scan) \
+ assert(!CMP(*scan, item)); \
+ (void)begin, (void)end; \
+ } \
\
return first; \
}
@@ -2774,26 +3176,32 @@ static const char *__mdbx_strerr(int errnum) {
"MDBX_VERSION_MISMATCH: DB version mismatch libmdbx",
"MDBX_INVALID: File is not an MDBX file",
"MDBX_MAP_FULL: Environment mapsize limit reached",
- "MDBX_DBS_FULL: Too may DBI (maxdbs reached)",
+ "MDBX_DBS_FULL: Too may DBI-handles (maxdbs reached)",
"MDBX_READERS_FULL: Too many readers (maxreaders reached)",
NULL /* MDBX_TLS_FULL (-30789): unused in MDBX */,
- "MDBX_TXN_FULL: Transaction has too many dirty pages, "
- "i.e transaction too big",
- "MDBX_CURSOR_FULL: Internal error - cursor stack limit reached",
- "MDBX_PAGE_FULL: Internal error - page has no more space",
- "MDBX_MAP_RESIZED: Database contents grew beyond environment mapsize",
- "MDBX_INCOMPATIBLE: Operation and DB incompatible, or DB flags changed",
- "MDBX_BAD_RSLOT: Invalid reuse of reader locktable slot",
- "MDBX_BAD_TXN: Transaction must abort, has a child, or is invalid",
- "MDBX_BAD_VALSIZE: Unsupported size of key/DB name/data, or wrong "
- "DUPFIXED size",
- "MDBX_BAD_DBI: The specified DBI handle was closed/changed unexpectedly",
- "MDBX_PROBLEM: Unexpected problem - txn should abort",
- "MDBX_BUSY: Another write transaction is running or "
- "environment is already used while opening with MDBX_EXCLUSIVE flag",
+ "MDBX_TXN_FULL: Transaction has too many dirty pages,"
+ " i.e transaction too big",
+ "MDBX_CURSOR_FULL: Internal error - Cursor stack limit reached",
+ "MDBX_PAGE_FULL: Internal error - Page has no more space",
+ "MDBX_MAP_RESIZED: Database contents grew beyond environment mapsize"
+ " and engine was unable to extend mapping,"
+ " e.g. since address space is unavailable or busy",
+ "MDBX_INCOMPATIBLE: Environment or database is not compatible"
+ " with the requested operation or the specified flags",
+ "MDBX_BAD_RSLOT: Invalid reuse of reader locktable slot,"
+ " e.g. read-transaction already run for current thread",
+ "MDBX_BAD_TXN: Transaction is not valid for requested operation,"
+ " e.g. had errored and be must aborted, has a child, or is invalid",
+ "MDBX_BAD_VALSIZE: Invalid size or alignment of key or data"
+ " for target database, either invalid subDB name",
+ "MDBX_BAD_DBI: The specified DBI-handle is invalid"
+ " or changed by another thread/transaction",
+ "MDBX_PROBLEM: Unexpected internal error, transaction should be aborted",
+ "MDBX_BUSY: Another write transaction is running,"
+ " or environment is already used while opening with MDBX_EXCLUSIVE flag",
};
- if (errnum >= MDBX_KEYEXIST && errnum <= MDBX_LAST_ERRCODE) {
+ if (errnum >= MDBX_KEYEXIST && errnum <= MDBX_LAST_LMDB_ERRCODE) {
int i = errnum - MDBX_KEYEXIST;
return tbl[i];
}
@@ -2802,21 +3210,27 @@ static const char *__mdbx_strerr(int errnum) {
case MDBX_SUCCESS:
return "MDBX_SUCCESS: Successful";
case MDBX_EMULTIVAL:
- return "MDBX_EMULTIVAL: Unable to update multi-value for the given key";
+ return "MDBX_EMULTIVAL: The specified key has"
+ " more than one associated value";
case MDBX_EBADSIGN:
- return "MDBX_EBADSIGN: Wrong signature of a runtime object(s)";
+ return "MDBX_EBADSIGN: Wrong signature of a runtime object(s),"
+ " e.g. memory corruption or double-free";
case MDBX_WANNA_RECOVERY:
- return "MDBX_WANNA_RECOVERY: Database should be recovered, but this could "
- "NOT be done in a read-only mode";
+ return "MDBX_WANNA_RECOVERY: Database should be recovered,"
+ " but this could NOT be done automatically for now"
+ " since it opened in read-only mode";
case MDBX_EKEYMISMATCH:
- return "MDBX_EKEYMISMATCH: The given key value is mismatched to the "
- "current cursor position";
+ return "MDBX_EKEYMISMATCH: The given key value is mismatched to the"
+ " current cursor position";
case MDBX_TOO_LARGE:
- return "MDBX_TOO_LARGE: Database is too large for current system, "
- "e.g. could NOT be mapped into RAM";
+ return "MDBX_TOO_LARGE: Database is too large for current system,"
+ " e.g. could NOT be mapped into RAM";
case MDBX_THREAD_MISMATCH:
- return "MDBX_THREAD_MISMATCH: A thread has attempted to use a not "
- "owned object, e.g. a transaction that started by another thread";
+ return "MDBX_THREAD_MISMATCH: A thread has attempted to use a not"
+ " owned object, e.g. a transaction that started by another thread";
+ case MDBX_TXN_OVERLAPPING:
+ return "MDBX_TXN_OVERLAPPING: Overlapping read and write transactions for"
+ " the current thread";
default:
return NULL;
}
@@ -4924,8 +5338,7 @@ done:
}
/* Copy the used portions of a non-overflow page. */
-__hot static void mdbx_page_copy(MDBX_page *dst, MDBX_page *src,
- unsigned psize) {
+__hot static void mdbx_page_copy(MDBX_page *dst, MDBX_page *src, size_t psize) {
STATIC_ASSERT(UINT16_MAX > MAX_PAGESIZE - PAGEHDRSZ);
STATIC_ASSERT(MIN_PAGESIZE > PAGEHDRSZ + NODESIZE * 4);
if (!IS_LEAF2(src)) {
@@ -4933,12 +5346,13 @@ __hot static void mdbx_page_copy(MDBX_page *dst, MDBX_page *src,
/* If page isn't full, just copy the used portion. Adjust
* alignment so memcpy may copy words instead of bytes. */
- if (unused > sizeof(void *) * 42) {
+ if (unused >= MDBX_CACHELINE_SIZE * 2) {
lower = roundup_powerof2(lower + PAGEHDRSZ, sizeof(void *));
upper = (upper + PAGEHDRSZ) & ~(sizeof(void *) - 1);
memcpy(dst, src, lower);
- memcpy((char *)dst + upper, (char *)src + upper, psize - upper);
- return;
+ dst = (void *)((char *)dst + upper);
+ src = (void *)((char *)src + upper);
+ psize -= upper;
}
}
memcpy(dst, src, psize);
@@ -5408,6 +5822,7 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
mdbx_assert(env, (flags & ~(MDBX_TXN_BEGIN_FLAGS | MDBX_TXN_SPILLS |
MDBX_WRITEMAP)) == 0);
+ const size_t tid = mdbx_thread_self();
if (flags & MDBX_RDONLY) {
txn->mt_flags =
MDBX_RDONLY | (env->me_flags & (MDBX_NOTLS | MDBX_WRITEMAP));
@@ -5430,7 +5845,6 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
return MDBX_BAD_RSLOT;
} else if (env->me_lck) {
unsigned slot, nreaders;
- const size_t tid = mdbx_thread_self();
mdbx_assert(env, env->me_lck->mti_magic_and_version == MDBX_LOCK_MAGIC);
mdbx_assert(env, env->me_lck->mti_os_and_format == MDBX_LOCK_FORMAT);
@@ -5484,7 +5898,7 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
safe64_reset(&r->mr_txnid, true);
if (slot == nreaders)
env->me_lck->mti_numreaders = ++nreaders;
- r->mr_tid = tid;
+ r->mr_tid = (env->me_flags & MDBX_NOTLS) ? 0 : tid;
r->mr_pid = env->me_pid;
mdbx_rdt_unlock(env);
@@ -5506,7 +5920,9 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
safe64_write(&r->mr_txnid, snap);
mdbx_jitter4testing(false);
mdbx_assert(env, r->mr_pid == mdbx_getpid());
- mdbx_assert(env, r->mr_tid == mdbx_thread_self());
+ mdbx_assert(
+ env, r->mr_tid ==
+ ((env->me_flags & MDBX_NOTLS) ? 0 : mdbx_thread_self()));
mdbx_assert(env, r->mr_txnid.inconsistent == snap);
mdbx_compiler_barrier();
env->me_lck->mti_readers_refresh_flag = true;
@@ -5533,7 +5949,7 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
if (unlikely(txn->mt_txnid == 0 ||
txn->mt_txnid >= SAFE64_INVALID_THRESHOLD)) {
mdbx_error("%s", "environment corrupted by died writer, must shutdown!");
- rc = MDBX_WANNA_RECOVERY;
+ rc = MDBX_CORRUPTED;
goto bailout;
}
mdbx_assert(env, txn->mt_txnid >= *env->me_oldest);
@@ -5543,6 +5959,22 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
/* paranoia is appropriate here */ *env->me_oldest);
txn->mt_numdbs = env->me_numdbs;
} else {
+ if (unlikely(txn->mt_owner == tid))
+ return MDBX_BUSY;
+ MDBX_lockinfo *const lck = env->me_lck;
+ if (lck && (env->me_flags & MDBX_NOTLS) == 0 &&
+ (mdbx_runtime_flags & MDBX_DBG_LEGACY_OVERLAP) == 0) {
+ const unsigned snap_nreaders = lck->mti_numreaders;
+ for (unsigned i = 0; i < snap_nreaders; ++i) {
+ if (lck->mti_readers[i].mr_pid == env->me_pid &&
+ unlikely(lck->mti_readers[i].mr_tid == tid)) {
+ const txnid_t txnid = safe64_read(&lck->mti_readers[i].mr_txnid);
+ if (txnid >= MIN_TXNID && txnid < SAFE64_INVALID_THRESHOLD)
+ return MDBX_TXN_OVERLAPPING;
+ }
+ }
+ }
+
/* Not yet touching txn == env->me_txn0, it may be active */
mdbx_jitter4testing(false);
rc = mdbx_txn_lock(env, F_ISSET(flags, MDBX_TRYTXN));
@@ -5641,7 +6073,7 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
#if defined(MDBX_USE_VALGRIND) || defined(__SANITIZE_ADDRESS__)
mdbx_txn_valgrind(env, txn);
#endif
- txn->mt_owner = mdbx_thread_self();
+ txn->mt_owner = tid;
return MDBX_SUCCESS;
}
bailout:
@@ -5772,16 +6204,16 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
size = env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + 1);
size += tsize = sizeof(MDBX_txn);
} else if (flags & MDBX_RDONLY) {
- if (env->me_txn0 && unlikely(env->me_txn0->mt_owner == mdbx_thread_self()))
- return MDBX_BUSY;
+ if (env->me_txn0 &&
+ unlikely(env->me_txn0->mt_owner == mdbx_thread_self()) &&
+ (mdbx_runtime_flags & MDBX_DBG_LEGACY_OVERLAP) == 0)
+ return MDBX_TXN_OVERLAPPING;
size = env->me_maxdbs * (sizeof(MDBX_db) + 1);
size += tsize = sizeof(MDBX_txn);
} else {
/* Reuse preallocated write txn. However, do not touch it until
* mdbx_txn_renew0() succeeds, since it currently may be active. */
txn = env->me_txn0;
- if (unlikely(txn->mt_owner == mdbx_thread_self()))
- return MDBX_BUSY;
goto renew;
}
if (unlikely((txn = mdbx_malloc(size)) == NULL)) {
@@ -8923,14 +9355,10 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) {
env->me_poison_edge = bytes2pgno(env, env->me_dxb_mmap.limit);
#endif /* MDBX_USE_VALGRIND || __SANITIZE_ADDRESS__ */
- /* NOTE: AddressSanitizer (at least GCC 7.x, 8.x) could generate
- * false-positive alarm here. I have no other explanation for this
- * except due to an internal ASAN error, as the problem is reproduced
- * in a single-threaded application under the active assert() above. */
const unsigned meta_clash_mask = mdbx_meta_eq_mask(env);
if (meta_clash_mask) {
mdbx_error("meta-pages are clashed: mask 0x%d", meta_clash_mask);
- return MDBX_WANNA_RECOVERY;
+ return MDBX_CORRUPTED;
}
while (1) {
@@ -9960,88 +10388,91 @@ static int __hot mdbx_cmp_memnr(const MDBX_val *a, const MDBX_val *b) {
* If no entry larger or equal to the key is found, returns NULL. */
static MDBX_node *__hot mdbx_node_search(MDBX_cursor *mc, MDBX_val *key,
int *exactp) {
- int low, high;
- int rc = 0;
MDBX_page *mp = mc->mc_pg[mc->mc_top];
- MDBX_node *node = nullptr;
- MDBX_val nodekey;
- MDBX_cmp_func *cmp;
+ const int nkeys = page_numkeys(mp);
DKBUF;
- const unsigned nkeys = page_numkeys(mp);
-
mdbx_debug("searching %u keys in %s %spage %" PRIaPGNO, nkeys,
IS_LEAF(mp) ? "leaf" : "branch", IS_SUBP(mp) ? "sub-" : "",
mp->mp_pgno);
- low = IS_LEAF(mp) ? 0 : 1;
- high = nkeys - 1;
- cmp = mc->mc_dbx->md_cmp;
-
- /* Branch pages have no data, so if using integer keys,
- * alignment is guaranteed. Use faster mdbx_cmp_int_ai.
- */
- if (cmp == mdbx_cmp_int_align2 && IS_BRANCH(mp))
- cmp = mdbx_cmp_int_align4;
+ int low = IS_LEAF(mp) ? 0 : 1;
+ int high = nkeys - 1;
+ *exactp = 0;
+ if (unlikely(high < low)) {
+ mc->mc_ki[mc->mc_top] = 0;
+ return NULL;
+ }
- unsigned i = 0;
- if (IS_LEAF2(mp)) {
+ int rc = 0, i = 0;
+ MDBX_cmp_func *cmp = mc->mc_dbx->md_cmp;
+ MDBX_val nodekey;
+ if (unlikely(IS_LEAF2(mp))) {
mdbx_cassert(mc, mp->mp_leaf2_ksize == mc->mc_db->md_xsize);
nodekey.iov_len = mp->mp_leaf2_ksize;
- node = (MDBX_node *)(intptr_t)-1; /* fake */
- while (low <= high) {
+ do {
i = (low + high) >> 1;
nodekey.iov_base = page_leaf2key(mp, i, nodekey.iov_len);
mdbx_cassert(mc, (char *)mp + mc->mc_txn->mt_env->me_psize >=
(char *)nodekey.iov_base + nodekey.iov_len);
rc = cmp(key, &nodekey);
mdbx_debug("found leaf index %u [%s], rc = %i", i, DKEY(&nodekey), rc);
- if (rc == 0)
+ if (unlikely(rc == 0)) {
+ *exactp = 1;
break;
- if (rc > 0)
- low = i + 1;
- else
- high = i - 1;
- }
- } else {
- while (low <= high) {
- i = (low + high) >> 1;
+ }
+ low = (rc < 0) ? low : i + 1;
+ high = (rc < 0) ? i - 1 : high;
+ } while (likely(low <= high));
- node = page_node(mp, i);
- nodekey.iov_len = node_ks(node);
- nodekey.iov_base = node_key(node);
- mdbx_cassert(mc, (char *)mp + mc->mc_txn->mt_env->me_psize >=
- (char *)nodekey.iov_base + nodekey.iov_len);
+ /* Found entry is less than the key. */
+ /* Skip to get the smallest entry larger than key. */
+ i += rc > 0;
- rc = cmp(key, &nodekey);
- if (IS_LEAF(mp))
- mdbx_debug("found leaf index %u [%s], rc = %i", i, DKEY(&nodekey), rc);
- else
- mdbx_debug("found branch index %u [%s -> %" PRIaPGNO "], rc = %i", i,
- DKEY(&nodekey), node_pgno(node), rc);
- if (rc == 0)
- break;
- if (rc > 0)
- low = i + 1;
- else
- high = i - 1;
- }
+ /* store the key index */
+ mc->mc_ki[mc->mc_top] = (indx_t)i;
+ return (i < nkeys)
+ ? /* fake for LEAF2 */ (MDBX_node *)(intptr_t)-1
+ : /* There is no entry larger or equal to the key. */ NULL;
}
- if (rc > 0) /* Found entry is less than the key. */
- i++; /* Skip to get the smallest entry larger than key. */
+ if (cmp == mdbx_cmp_int_align2 && IS_BRANCH(mp))
+ /* Branch pages have no data, so if using integer keys,
+ * alignment is guaranteed. Use faster mdbx_cmp_int_align4(). */
+ cmp = mdbx_cmp_int_align4;
+
+ MDBX_node *node;
+ do {
+ i = (low + high) >> 1;
+
+ node = page_node(mp, i);
+ nodekey.iov_len = node_ks(node);
+ nodekey.iov_base = node_key(node);
+ mdbx_cassert(mc, (char *)mp + mc->mc_txn->mt_env->me_psize >=
+ (char *)nodekey.iov_base + nodekey.iov_len);
+
+ rc = cmp(key, &nodekey);
+ if (IS_LEAF(mp))
+ mdbx_debug("found leaf index %u [%s], rc = %i", i, DKEY(&nodekey), rc);
+ else
+ mdbx_debug("found branch index %u [%s -> %" PRIaPGNO "], rc = %i", i,
+ DKEY(&nodekey), node_pgno(node), rc);
+ if (unlikely(rc == 0)) {
+ *exactp = 1;
+ break;
+ }
+ low = (rc < 0) ? low : i + 1;
+ high = (rc < 0) ? i - 1 : high;
+ } while (likely(low <= high));
+
+ /* Found entry is less than the key. */
+ /* Skip to get the smallest entry larger than key. */
+ i += rc > 0;
- if (exactp)
- *exactp = (rc == 0 && nkeys > 0);
/* store the key index */
- mdbx_cassert(mc, i <= UINT16_MAX);
mc->mc_ki[mc->mc_top] = (indx_t)i;
- if (i >= nkeys)
- /* There is no entry larger or equal to the key. */
- return NULL;
-
- /* page_node is fake for LEAF2 */
- return IS_LEAF2(mp) ? node : page_node(mp, i);
+ return (i < nkeys) ? page_node(mp, i)
+ : /* There is no entry larger or equal to the key. */ NULL;
}
#if 0 /* unused for now */
@@ -10113,6 +10544,10 @@ __hot static int mdbx_page_get(MDBX_cursor *mc, pgno_t pgno, MDBX_page **ret,
MDBX_page *p = NULL;
int level;
mdbx_assert(env, ((txn->mt_flags ^ env->me_flags) & MDBX_WRITEMAP) == 0);
+ const uint16_t illegal_bits = (txn->mt_flags & MDBX_RDONLY)
+ ? P_LOOSE | P_SUBP | P_META | P_DIRTY
+ : P_LOOSE | P_SUBP | P_META;
+ const uint64_t txnid = txn->mt_txnid;
if (unlikely((txn->mt_flags & (MDBX_RDONLY | MDBX_WRITEMAP)) == 0)) {
level = 1;
do {
@@ -10141,21 +10576,18 @@ dirty:
goto corrupted;
}
- if (unlikely((p->mp_flags & (P_LOOSE | P_SUBP | P_META | P_DIRTY)) != 0 ||
- p->mp_txnid > mc->mc_txn->mt_txnid)) {
- if (unlikely((mc->mc_txn->mt_flags & MDBX_RDONLY) != 0 ||
- (p->mp_flags & (P_LOOSE | P_SUBP | P_META | P_DIRTY)) !=
- P_DIRTY)) {
- mdbx_error("invalid page's flags (0x%x) or txnid %" PRIaTXN
- " > (actual) %" PRIaTXN " (expected)",
- p->mp_flags, p->mp_txnid, mc->mc_txn->mt_txnid);
- goto corrupted;
- }
+ if (unlikely((p->mp_flags & illegal_bits) != 0 ||
+ p->mp_txnid > ((p->mp_flags & P_DIRTY) ? UINT64_MAX : txnid))) {
+ mdbx_error("invalid page's flags (0x%x) or txnid %" PRIaTXN
+ " > (actual) %" PRIaTXN " (expected)",
+ p->mp_flags, p->mp_txnid, mc->mc_txn->mt_txnid);
+ goto corrupted;
}
- if (unlikely(!IS_OVERFLOW(p) && (p->mp_upper < p->mp_lower ||
- ((p->mp_lower | p->mp_upper) & 1) != 0 ||
- PAGEHDRSZ + p->mp_upper > env->me_psize))) {
+ if (unlikely((p->mp_upper < p->mp_lower ||
+ ((p->mp_lower | p->mp_upper) & 1) != 0 ||
+ PAGEHDRSZ + p->mp_upper > env->me_psize) &&
+ !IS_OVERFLOW(p))) {
mdbx_error("invalid page lower(%u)/upper(%u), pg-limit %u", p->mp_lower,
p->mp_upper, page_space(env));
goto corrupted;
@@ -10167,9 +10599,8 @@ dirty:
return err;
}
+ *(lvl ? lvl : &level) = level;
*ret = p;
- if (lvl)
- *lvl = level;
return MDBX_SUCCESS;
corrupted:
@@ -10759,8 +11190,11 @@ static int mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
int rc;
MDBX_page *mp;
MDBX_node *node = NULL;
+ int stub_exactp;
DKBUF;
+ exactp = exactp ? exactp : &stub_exactp;
+
if ((mc->mc_db->md_flags & MDBX_INTEGERKEY) &&
unlikely(key->iov_len != sizeof(uint32_t) &&
key->iov_len != sizeof(uint64_t))) {
@@ -10793,8 +11227,7 @@ static int mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
/* Probably happens rarely, but first node on the page
* was the one we wanted. */
mc->mc_ki[mc->mc_top] = 0;
- if (exactp)
- *exactp = 1;
+ *exactp = 1;
goto set1;
}
if (rc > 0) {
@@ -10812,8 +11245,7 @@ static int mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
/* last node was the one we wanted */
mdbx_cassert(mc, nkeys >= 1 && nkeys <= UINT16_MAX + 1);
mc->mc_ki[mc->mc_top] = (indx_t)(nkeys - 1);
- if (exactp)
- *exactp = 1;
+ *exactp = 1;
goto set1;
}
if (rc < 0) {
@@ -10829,8 +11261,7 @@ static int mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
rc = mc->mc_dbx->md_cmp(key, &nodekey);
if (rc == 0) {
/* current node was the one we wanted */
- if (exactp)
- *exactp = 1;
+ *exactp = 1;
goto set1;
}
}
@@ -10854,7 +11285,7 @@ static int mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
if (!mc->mc_top) {
/* There are no other pages */
mc->mc_ki[mc->mc_top] = 0;
- if (op == MDBX_SET_RANGE && !exactp) {
+ if (op == MDBX_SET_RANGE && exactp == &stub_exactp) {
rc = 0;
goto set1;
} else
@@ -10873,7 +11304,7 @@ static int mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
set2:
node = mdbx_node_search(mc, key, exactp);
- if (exactp != NULL && !*exactp) {
+ if (exactp != &stub_exactp && !*exactp) {
/* MDBX_SET specified and not an exact match. */
return MDBX_NOTFOUND;
}
@@ -11297,18 +11728,28 @@ int mdbx_cursor_put(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
return MDBX_BAD_VALSIZE;
}
- if ((mc->mc_db->md_flags & MDBX_INTEGERKEY) &&
- unlikely(key->iov_len != sizeof(uint32_t) &&
- key->iov_len != sizeof(uint64_t))) {
- mdbx_cassert(mc, !"key-size is invalid for MDBX_INTEGERKEY");
- return MDBX_BAD_VALSIZE;
+ if ((mc->mc_db->md_flags & MDBX_INTEGERKEY)) {
+ if (unlikely(key->iov_len != sizeof(uint32_t) &&
+ key->iov_len != sizeof(uint64_t))) {
+ mdbx_cassert(mc, !"key-size is invalid for MDBX_INTEGERKEY");
+ return MDBX_BAD_VALSIZE;
+ }
+ if (unlikely(3 & (uintptr_t)key->iov_base)) {
+ mdbx_cassert(mc, !"key-alignment is invalid for MDBX_INTEGERKEY");
+ return MDBX_BAD_VALSIZE;
+ }
}
- if ((mc->mc_db->md_flags & MDBX_INTEGERDUP) &&
- unlikely(data->iov_len != sizeof(uint32_t) &&
- data->iov_len != sizeof(uint64_t))) {
- mdbx_cassert(mc, !"data-size is invalid MDBX_INTEGERDUP");
- return MDBX_BAD_VALSIZE;
+ if ((mc->mc_db->md_flags & MDBX_INTEGERDUP)) {
+ if (unlikely(data->iov_len != sizeof(uint32_t) &&
+ data->iov_len != sizeof(uint64_t))) {
+ mdbx_cassert(mc, !"data-size is invalid for MDBX_INTEGERDUP");
+ return MDBX_BAD_VALSIZE;
+ }
+ if (unlikely(3 & (uintptr_t)data->iov_base)) {
+ mdbx_cassert(mc, !"data-alignment is invalid for MDBX_INTEGERDUP");
+ return MDBX_BAD_VALSIZE;
+ }
}
}
@@ -11611,9 +12052,9 @@ int mdbx_cursor_put(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
}
/* Back up original data item */
+ memcpy(dkey.iov_base = fp + 1, olddata.iov_base,
+ dkey.iov_len = olddata.iov_len);
dupdata_flag = 1;
- dkey.iov_len = olddata.iov_len;
- dkey.iov_base = memcpy(fp + 1, olddata.iov_base, olddata.iov_len);
/* Make sub-page header for the dup items, with dummy body */
fp->mp_flags = P_LEAF | P_DIRTY | P_SUBP;
@@ -12702,8 +13143,7 @@ static int mdbx_update_key(MDBX_cursor *mc, const MDBX_val *key) {
/* But even if no shift was needed, update ksize */
node_set_ks(node, key->iov_len);
- if (key->iov_len)
- memcpy(node_key(node), key->iov_base, key->iov_len);
+ memcpy(node_key(node), key->iov_base, key->iov_len);
return MDBX_SUCCESS;
}
@@ -14045,8 +14485,7 @@ static int mdbx_page_split(MDBX_cursor *mc, const MDBX_val *newkey,
mdbx_cassert(mc, mp->mp_upper >= ksize - sizeof(indx_t));
mp->mp_upper -= (indx_t)(ksize - sizeof(indx_t));
} else {
- if (x)
- memcpy(rp->mp_ptrs, split, x * ksize);
+ memcpy(rp->mp_ptrs, split, x * ksize);
ins = page_leaf2key(rp, x, ksize);
memcpy(ins, newkey->iov_base, ksize);
memcpy(ins + ksize, split + x * ksize, rsize - x * ksize);
@@ -15405,7 +15844,7 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
MDBX_cmp_func *datacmp) {
if (unlikely(!dbi || (user_flags & ~VALID_FLAGS) != 0))
return MDBX_EINVAL;
- *dbi = (MDBX_dbi)-1;
+ *dbi = 0;
int rc = check_txn(txn, MDBX_TXN_BLOCKED);
if (unlikely(rc != MDBX_SUCCESS))
@@ -16086,21 +16525,20 @@ int __cold mdbx_setup_debug(int loglevel, int flags, MDBX_debug_func *logger) {
#if !MDBX_DEBUG
(void)loglevel;
#else
- if (loglevel != -1)
+ if (loglevel != MDBX_LOG_DONTCHANGE)
mdbx_loglevel = (uint8_t)loglevel;
#endif
- if (flags != -1) {
-#if !MDBX_DEBUG
- flags &= MDBX_DBG_DUMP | MDBX_DBG_LEGACY_MULTIOPEN;
-#else
- flags &= MDBX_DBG_ASSERT | MDBX_DBG_AUDIT | MDBX_DBG_JITTER |
- MDBX_DBG_DUMP | MDBX_DBG_LEGACY_MULTIOPEN;
+ if (flags != MDBX_DBG_DONTCHANGE) {
+ flags &=
+#if MDBX_DEBUG
+ MDBX_DBG_ASSERT | MDBX_DBG_AUDIT | MDBX_DBG_JITTER |
#endif
+ MDBX_DBG_DUMP | MDBX_DBG_LEGACY_MULTIOPEN | MDBX_DBG_LEGACY_OVERLAP;
mdbx_runtime_flags = (uint8_t)flags;
}
- if (-1 != (intptr_t)logger)
+ if (logger != MDBX_LOGGER_DONTCHANGE)
mdbx_debug_logger = logger;
return rc;
}
@@ -17340,6 +17778,144 @@ __cold intptr_t mdbx_limits_txnsize_max(intptr_t pagesize) {
: (intptr_t)MAX_MAPSIZE;
}
+/*** Key-making functions to avoid custom comparators *************************/
+
+static __always_inline uint64_t double2key(const double *const ptr) {
+ STATIC_ASSERT(sizeof(double) == sizeof(int64_t));
+ const int64_t i64 = *(const int64_t *)ptr;
+ return (i64 >= 0) ? /* positive */ UINT64_C(0x8000000000000000) + i64
+ : /* negative */ (uint64_t)-i64;
+}
+
+static __always_inline uint32_t float2key(const float *const ptr) {
+ STATIC_ASSERT(sizeof(float) == sizeof(int32_t));
+ const int32_t i32 = *(const int32_t *)ptr;
+ return (i32 >= 0) ? /* positive */ UINT32_C(0x80000000) + i32
+ : /* negative */ (uint32_t)-i32;
+}
+
+uint64_t mdbx_key_from_double(const double ieee754_64bit) {
+ return double2key(&ieee754_64bit);
+}
+
+uint64_t mdbx_key_from_ptrdouble(const double *const ieee754_64bit) {
+ return double2key(ieee754_64bit);
+}
+
+uint32_t mdbx_key_from_float(const float ieee754_32bit) {
+ return float2key(&ieee754_32bit);
+}
+
+uint32_t mdbx_key_from_ptrfloat(const float *const ieee754_32bit) {
+ return float2key(ieee754_32bit);
+}
+
+#define IEEE754_DOUBLE_MANTISSA_SIZE 52
+#define IEEE754_DOUBLE_BIAS 0x3FF
+#define IEEE754_DOUBLE_MAX 0x7FF
+#define IEEE754_DOUBLE_IMPLICIT_LEAD UINT64_C(0x0010000000000000)
+#define IEEE754_DOUBLE_MANTISSA_MASK UINT64_C(0x000FFFFFFFFFFFFF)
+#define IEEE754_DOUBLE_MANTISSA_AMAX UINT64_C(0x001FFFFFFFFFFFFF)
+
+static __inline int clz64(uint64_t value) {
+#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_clzl)
+ if (sizeof(value) == sizeof(int))
+ return __builtin_clz(value);
+ if (sizeof(value) == sizeof(long))
+ return __builtin_clzl(value);
+#if (defined(__SIZEOF_LONG_LONG__) && __SIZEOF_LONG_LONG__ == 8) || \
+ __has_builtin(__builtin_clzll)
+ return __builtin_clzll(value);
+#endif /* have(long long) && long long == uint64_t */
+#endif /* GNU C */
+
+#if defined(_MSC_VER)
+ unsigned long index;
+#if defined(_M_AMD64) || defined(_M_ARM64) || defined(_M_X64)
+ _BitScanReverse64(&index, value);
+ return 63 - index;
+#else
+ if (value > UINT32_MAX) {
+ _BitScanReverse(&index, (uint32_t)(value >> 32));
+ return 31 - index;
+ }
+ _BitScanReverse(&index, (uint32_t)value);
+ return 63 - index;
+#endif
+#endif /* MSVC */
+
+ value |= value >> 1;
+ value |= value >> 2;
+ value |= value >> 4;
+ value |= value >> 8;
+ value |= value >> 16;
+ value |= value >> 32;
+ static const uint8_t debruijn_clz64[64] = {
+ 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2,
+ 9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1,
+ 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
+ 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0};
+ return debruijn_clz64[value * UINT64_C(0x03F79D71B4CB0A89) >> 58];
+}
+
+static uint64_t round_mantissa(const uint64_t u64, int shift) {
+ assert(shift < 0 && u64 > 0);
+ shift = -shift;
+ const unsigned half = 1 << (shift - 1);
+ const unsigned lsb = 1 & (unsigned)(u64 >> shift);
+ const unsigned tie2even = 1 ^ lsb;
+ return (u64 + half - tie2even) >> shift;
+}
+
+uint64_t mdbx_key_from_jsonInteger(const int64_t json_integer) {
+ const uint64_t biased_zero = UINT64_C(0x8000000000000000);
+ if (json_integer > 0) {
+ const uint64_t u64 = json_integer;
+ int shift = clz64(u64) - (64 - IEEE754_DOUBLE_MANTISSA_SIZE - 1);
+ uint64_t mantissa = u64 << shift;
+ if (unlikely(shift < 0)) {
+ mantissa = round_mantissa(u64, shift);
+ if (mantissa > IEEE754_DOUBLE_MANTISSA_AMAX)
+ mantissa = round_mantissa(u64, --shift);
+ }
+
+ assert(mantissa >= IEEE754_DOUBLE_IMPLICIT_LEAD &&
+ mantissa <= IEEE754_DOUBLE_MANTISSA_AMAX);
+ const uint64_t exponent =
+ IEEE754_DOUBLE_BIAS + IEEE754_DOUBLE_MANTISSA_SIZE - shift;
+ assert(exponent > 0 && exponent <= IEEE754_DOUBLE_MAX);
+ const uint64_t key = biased_zero +
+ (exponent << IEEE754_DOUBLE_MANTISSA_SIZE) +
+ (mantissa - IEEE754_DOUBLE_IMPLICIT_LEAD);
+ assert(key == mdbx_key_from_double((double)json_integer));
+ return key;
+ }
+
+ if (json_integer < 0) {
+ const uint64_t u64 = -json_integer;
+ int shift = clz64(u64) - (64 - IEEE754_DOUBLE_MANTISSA_SIZE - 1);
+ uint64_t mantissa = u64 << shift;
+ if (unlikely(shift < 0)) {
+ mantissa = round_mantissa(u64, shift);
+ if (mantissa > IEEE754_DOUBLE_MANTISSA_AMAX)
+ mantissa = round_mantissa(u64, --shift);
+ }
+
+ assert(mantissa >= IEEE754_DOUBLE_IMPLICIT_LEAD &&
+ mantissa <= IEEE754_DOUBLE_MANTISSA_AMAX);
+ const uint64_t exponent =
+ IEEE754_DOUBLE_BIAS + IEEE754_DOUBLE_MANTISSA_SIZE - shift;
+ assert(exponent > 0 && exponent <= IEEE754_DOUBLE_MAX);
+ const uint64_t key = biased_zero -
+ (exponent << IEEE754_DOUBLE_MANTISSA_SIZE) -
+ (mantissa - IEEE754_DOUBLE_IMPLICIT_LEAD);
+ assert(key == mdbx_key_from_double((double)json_integer));
+ return key;
+ }
+
+ return biased_zero;
+}
+
/*** Attribute support functions for Nexenta **********************************/
#ifdef MDBX_NEXENTA_ATTRS
diff --git a/libs/libmdbx/src/src/elements/defs.h b/libs/libmdbx/src/src/elements/defs.h
index 9e262e2fc2..dfbde2ea61 100644
--- a/libs/libmdbx/src/src/elements/defs.h
+++ b/libs/libmdbx/src/src/elements/defs.h
@@ -142,33 +142,33 @@
#endif /* __maybe_unused */
#if !defined(__noop) && !defined(_MSC_VER)
-# define __noop(...) do {} while(0)
+# define __noop(...) do {} while(0)
#endif /* __noop */
#ifndef __fallthrough
-# if __GNUC_PREREQ(7, 0) || __has_attribute(__fallthrough__)
-# define __fallthrough __attribute__((__fallthrough__))
-# else
-# define __fallthrough __noop()
-# endif
+# if __GNUC_PREREQ(7, 0) || __has_attribute(__fallthrough__)
+# define __fallthrough __attribute__((__fallthrough__))
+# else
+# define __fallthrough __noop()
+# endif
#endif /* __fallthrough */
#ifndef __unreachable
-# if __GNUC_PREREQ(4,5) || __has_builtin(__builtin_unreachable)
-# define __unreachable() __builtin_unreachable()
-# elif defined(_MSC_VER)
-# define __unreachable() __assume(0)
-# else
-# define __unreachable() __noop()
-# endif
+# if __GNUC_PREREQ(4,5) || __has_builtin(__builtin_unreachable)
+# define __unreachable() __builtin_unreachable()
+# elif defined(_MSC_VER)
+# define __unreachable() __assume(0)
+# else
+# define __unreachable() __noop()
+# endif
#endif /* __unreachable */
#ifndef __prefetch
-# if defined(__GNUC__) || defined(__clang__)
-# define __prefetch(ptr) __builtin_prefetch(ptr)
-# else
-# define __prefetch(ptr) __noop(ptr)
-# endif
+# if defined(__GNUC__) || defined(__clang__)
+# define __prefetch(ptr) __builtin_prefetch(ptr)
+# else
+# define __prefetch(ptr) __noop(ptr)
+# endif
#endif /* __prefetch */
#ifndef __noreturn
@@ -309,17 +309,6 @@
# endif
#endif /* unlikely */
-/* Workaround for Coverity Scan */
-#if defined(__COVERITY__) && __GNUC_PREREQ(7, 0) && !defined(__cplusplus)
-typedef float _Float32;
-typedef double _Float32x;
-typedef double _Float64;
-typedef long double _Float64x;
-typedef float _Float128 __attribute__((__mode__(__TF__)));
-typedef __complex__ float __cfloat128 __attribute__ ((__mode__ (__TC__)));
-typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
-#endif /* Workaround for Coverity Scan */
-
#ifndef __printf_args
# if defined(__GNUC__) || __has_attribute(__format__)
# define __printf_args(format_index, first_arg) \
diff --git a/libs/libmdbx/src/src/elements/internals.h b/libs/libmdbx/src/src/elements/internals.h
index 80e3500a98..62552de95e 100644
--- a/libs/libmdbx/src/src/elements/internals.h
+++ b/libs/libmdbx/src/src/elements/internals.h
@@ -1165,7 +1165,7 @@ MDBX_INTERNAL_FUNC void mdbx_rthc_thread_dtor(void *ptr);
((rc) != MDBX_RESULT_TRUE && (rc) != MDBX_RESULT_FALSE)
/* Internal error codes, not exposed outside libmdbx */
-#define MDBX_NO_ROOT (MDBX_LAST_ERRCODE + 10)
+#define MDBX_NO_ROOT (MDBX_LAST_LMDB_ERRCODE + 10)
/* Debugging output value of a cursor DBI: Negative in a sub-cursor. */
#define DDBI(mc) \
@@ -1318,3 +1318,14 @@ static __maybe_unused __inline void mdbx_jitter4testing(bool tiny) {
(void)tiny;
#endif
}
+
+static __pure_function __always_inline __maybe_unused bool
+is_powerof2(size_t x) {
+ return (x & (x - 1)) == 0;
+}
+
+static __pure_function __always_inline __maybe_unused size_t
+roundup_powerof2(size_t value, size_t granularity) {
+ assert(is_powerof2(granularity));
+ return (value + granularity - 1) & ~(granularity - 1);
+}
diff --git a/libs/libmdbx/src/src/elements/osal.c b/libs/libmdbx/src/src/elements/osal.c
index 158413d66a..7d93c0ccee 100644
--- a/libs/libmdbx/src/src/elements/osal.c
+++ b/libs/libmdbx/src/src/elements/osal.c
@@ -324,12 +324,13 @@ MDBX_INTERNAL_FUNC int mdbx_asprintf(char **strp, const char *fmt, ...) {
#ifndef mdbx_memalign_alloc
MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes,
void **result) {
+ assert(is_powerof2(alignment) && alignment >= sizeof(void *));
#if defined(_WIN32) || defined(_WIN64)
(void)alignment;
*result = VirtualAlloc(NULL, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
return *result ? MDBX_SUCCESS : MDBX_ENOMEM /* ERROR_OUTOFMEMORY */;
#elif defined(_ISOC11_SOURCE)
- *result = aligned_alloc(alignment, bytes);
+ *result = aligned_alloc(alignment, roundup_powerof2(bytes, alignment));
return *result ? MDBX_SUCCESS : errno;
#elif _POSIX_VERSION >= 200112L
*result = nullptr;
diff --git a/libs/libmdbx/src/test/pcrf/pcrf_test.c b/libs/libmdbx/src/test/pcrf/pcrf_test.c
index b16e79f8ee..2db58a023a 100644
--- a/libs/libmdbx/src/test/pcrf/pcrf_test.c
+++ b/libs/libmdbx/src/test/pcrf/pcrf_test.c
@@ -336,20 +336,22 @@ static void periodic_stat(void) {
prev_del_time = mdbx_del_time;
}
-// static void periodic_add_rec() {
-// for (int i = 0; i < 10240; i++) {
-// if (ids_count <= REC_COUNT) {
-// int64_t id = obj_id++;
-// create_record(id);
-// add_id_to_pool(id);
-// }
-// if (ids_count > REC_COUNT) {
-// int64_t id = get_id_from_pool();
-// delete_record(id);
-// }
-// }
-// periodic_stat();
-//}
+#if 0 /* unused */
+static void periodic_add_rec() {
+ for (int i = 0; i < 10240; i++) {
+ if (ids_count <= REC_COUNT) {
+ int64_t id = obj_id++;
+ create_record(id);
+ add_id_to_pool(id);
+ }
+ if (ids_count > REC_COUNT) {
+ int64_t id = get_id_from_pool();
+ delete_record(id);
+ }
+ }
+ periodic_stat();
+}
+#endif
int main(int argc, char **argv) {
(void)argc;
@@ -358,14 +360,12 @@ int main(int argc, char **argv) {
char filename[PATH_MAX];
int i;
- mkdir(opt_db_path, 0775);
-
strcpy(filename, opt_db_path);
- strcat(filename, "/mdbx.dat");
+ strcat(filename, MDBX_DATANAME);
remove(filename);
strcpy(filename, opt_db_path);
- strcat(filename, "/mdbx.lck");
+ strcat(filename, MDBX_LOCKNAME);
remove(filename);
puts("Open DB...");
@@ -394,14 +394,14 @@ int main(int argc, char **argv) {
id = get_id_from_pool();
delete_record(id);
}
- // for (i = 0; i < 50; i++) {
- // int64_t id = obj_id++;
- // create_record(id);
- // add_id_to_pool(id);
- // }
- // int64_t id = obj_id++;
- // create_record(id);
- // add_id_to_pool(id);
+ for (i = 0; i < 50; i++) {
+ int64_t id = obj_id++;
+ create_record(id);
+ add_id_to_pool(id);
+ }
+ int64_t id = obj_id++;
+ create_record(id);
+ add_id_to_pool(id);
int64_t now = getClockUs();
if ((now - t) > 10000000L) {
periodic_stat();