mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-02 00:34:13 +08:00
mdbx: добавление eq_fast()
для сравнений на (не)равенство.
Цель в том, чтобы уменьшить кол-во условных и безусловных переходов при сравнениях равно/неравно, в том числе избегать вызовов задаваемых кастомных компаратаров и memcmp() для коротких ключей/значений.
This commit is contained in:
parent
2322138a8e
commit
f53dc70038
92
src/core.c
92
src/core.c
@ -15236,12 +15236,31 @@ __hot static int cmp_lenfast(const MDBX_val *a, const MDBX_val *b) {
|
|||||||
: memcmp(a->iov_base, b->iov_base, a->iov_len);
|
: memcmp(a->iov_base, b->iov_base, a->iov_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool unsure_equal(MDBX_cmp_func cmp, const MDBX_val *a,
|
__hot static bool eq_fast_slowpath(const uint8_t *a, const uint8_t *b,
|
||||||
const MDBX_val *b) {
|
size_t l) {
|
||||||
/* checking for the use of a known good comparator
|
if (likely(l > 3)) {
|
||||||
* or/otherwise for a full byte-to-byte match */
|
if (MDBX_UNALIGNED_OK >= 4 && likely(l < 9))
|
||||||
return cmp == cmp_lenfast || cmp == cmp_lexical || cmp == cmp_reverse ||
|
return ((unaligned_peek_u32(1, a) - unaligned_peek_u32(1, b)) |
|
||||||
cmp == cmp_int_unaligned || cmp_lenfast(a, b) == 0;
|
(unaligned_peek_u32(1, a + l - 4) -
|
||||||
|
unaligned_peek_u32(1, b + l - 4))) == 0;
|
||||||
|
if (MDBX_UNALIGNED_OK >= 8 && sizeof(size_t) > 7 && likely(l < 17))
|
||||||
|
return ((unaligned_peek_u64(1, a) - unaligned_peek_u64(1, b)) |
|
||||||
|
(unaligned_peek_u64(1, a + l - 8) -
|
||||||
|
unaligned_peek_u64(1, b + l - 8))) == 0;
|
||||||
|
return memcmp(a, b, l) == 0;
|
||||||
|
}
|
||||||
|
if (likely(l)) {
|
||||||
|
STATIC_ASSERT(sizeof(int) > 2);
|
||||||
|
const unsigned a3 = a[0] << 16 | a[l >> 1] << 8 | a[l - 1];
|
||||||
|
const unsigned b3 = b[0] << 16 | b[l >> 1] << 8 | b[l - 1];
|
||||||
|
return a3 == b3;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __always_inline bool eq_fast(const MDBX_val *a, const MDBX_val *b) {
|
||||||
|
return unlikely(a->iov_len == b->iov_len) &&
|
||||||
|
eq_fast_slowpath(a->iov_base, b->iov_base, a->iov_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search for key within a page, using binary search.
|
/* Search for key within a page, using binary search.
|
||||||
@ -17099,25 +17118,21 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
|
|||||||
flags -= MDBX_ALLDUPS;
|
flags -= MDBX_ALLDUPS;
|
||||||
rc = MDBX_NOTFOUND;
|
rc = MDBX_NOTFOUND;
|
||||||
exact = false;
|
exact = false;
|
||||||
} else /* checking for early exit without dirtying pages */
|
} else if (!(flags & (MDBX_RESERVE | MDBX_MULTIPLE))) {
|
||||||
if (!(flags & (MDBX_RESERVE | MDBX_MULTIPLE)) &&
|
/* checking for early exit without dirtying pages */
|
||||||
unlikely(mc->mc_dbx->md_dcmp(data, &olddata) == 0)) {
|
if (unlikely(eq_fast(data, &olddata))) {
|
||||||
if (!mc->mc_xcursor)
|
cASSERT(mc, mc->mc_dbx->md_dcmp(data, &olddata) == 0);
|
||||||
/* the same data, nothing to update */
|
if (mc->mc_xcursor) {
|
||||||
return MDBX_SUCCESS;
|
if (flags & MDBX_NODUPDATA)
|
||||||
if (flags & MDBX_NODUPDATA)
|
return MDBX_KEYEXIST;
|
||||||
return MDBX_KEYEXIST;
|
if (flags & MDBX_APPENDDUP)
|
||||||
if (flags & MDBX_APPENDDUP)
|
return MDBX_EKEYMISMATCH;
|
||||||
return MDBX_EKEYMISMATCH;
|
|
||||||
if (likely(unsure_equal(mc->mc_dbx->md_dcmp, data, &olddata)))
|
|
||||||
/* data is match exactly byte-to-byte, nothing to update */
|
|
||||||
return MDBX_SUCCESS;
|
|
||||||
else {
|
|
||||||
/* The data has differences, but the user-provided comparator
|
|
||||||
* considers them equal. So continue update since called without.
|
|
||||||
* Continue to update since was called without MDBX_NODUPDATA. */
|
|
||||||
}
|
}
|
||||||
|
/* the same data, nothing to update */
|
||||||
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
cASSERT(mc, mc->mc_dbx->md_dcmp(data, &olddata) != 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (unlikely(rc != MDBX_NOTFOUND))
|
} else if (unlikely(rc != MDBX_NOTFOUND))
|
||||||
return rc;
|
return rc;
|
||||||
@ -17322,28 +17337,21 @@ static __hot int cursor_put_nochecklen(MDBX_cursor *mc, const MDBX_val *key,
|
|||||||
|
|
||||||
/* Was a single item before, must convert now */
|
/* Was a single item before, must convert now */
|
||||||
if (!(node_flags(node) & F_DUPDATA)) {
|
if (!(node_flags(node) & F_DUPDATA)) {
|
||||||
|
|
||||||
/* does data match? */
|
/* does data match? */
|
||||||
const int cmp = mc->mc_dbx->md_dcmp(data, &olddata);
|
if (flags & MDBX_APPENDDUP) {
|
||||||
if ((flags & MDBX_APPENDDUP) && unlikely(cmp <= 0))
|
const int cmp = mc->mc_dbx->md_dcmp(data, &olddata);
|
||||||
return MDBX_EKEYMISMATCH;
|
cASSERT(mc, cmp != 0 || eq_fast(data, &olddata));
|
||||||
if (cmp == 0) {
|
if (unlikely(cmp <= 0))
|
||||||
|
return MDBX_EKEYMISMATCH;
|
||||||
|
} else if (eq_fast(data, &olddata)) {
|
||||||
|
cASSERT(mc, mc->mc_dbx->md_dcmp(data, &olddata) == 0);
|
||||||
if (flags & MDBX_NODUPDATA)
|
if (flags & MDBX_NODUPDATA)
|
||||||
return MDBX_KEYEXIST;
|
return MDBX_KEYEXIST;
|
||||||
if (likely(unsure_equal(mc->mc_dbx->md_dcmp, data, &olddata))) {
|
/* data is match exactly byte-to-byte, nothing to update */
|
||||||
/* data is match exactly byte-to-byte, nothing to update */
|
rc = MDBX_SUCCESS;
|
||||||
if (unlikely(flags & MDBX_MULTIPLE)) {
|
if (likely((flags & MDBX_MULTIPLE) == 0))
|
||||||
rc = MDBX_SUCCESS;
|
return rc;
|
||||||
goto continue_multiple;
|
goto continue_multiple;
|
||||||
}
|
|
||||||
return MDBX_SUCCESS;
|
|
||||||
} else {
|
|
||||||
/* The data has differences, but the user-provided comparator
|
|
||||||
* considers them equal. So continue update since called without.
|
|
||||||
* Continue to update since was called without MDBX_NODUPDATA. */
|
|
||||||
}
|
|
||||||
cASSERT(mc, node_size(key, data) <= env->me_leaf_nodemax);
|
|
||||||
goto current;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Just overwrite the current item */
|
/* Just overwrite the current item */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user