mdbx: add MDBX_EPSILON support for mdbx_estimate_range().

Change-Id: I2d89a9f20bfa16c8f35a4381709bc54f86f0ff67
This commit is contained in:
Leonid Yuriev 2019-05-23 23:17:35 +03:00
parent b4002a8484
commit e26b7501eb
3 changed files with 93 additions and 55 deletions

1
mdbx.h
View File

@ -1737,6 +1737,7 @@ LIBMDBX_API int mdbx_estimate_move(const MDBX_cursor *cursor, MDBX_val *key,
* [out] distance_items A pointer to store range estimation result.
*
* Returns A non-zero error value on failure and 0 on success. */
#define MDBX_EPSILON ((MDBX_val *)((ptrdiff_t)-1))
LIBMDBX_API int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi,
MDBX_val *begin_key, MDBX_val *begin_data,
MDBX_val *end_key, MDBX_val *end_data,

View File

@ -1155,7 +1155,7 @@ typedef struct MDBX_node {
#define LEAF2KEY(p, i, ks) ((char *)(p) + PAGEHDRSZ + ((i) * (ks)))
/* Set the node's key into keyptr, if requested. */
#define MDBX_GET_KEY(node, keyptr) \
#define MDBX_GET_MAYNULL_KEYPTR(node, keyptr) \
do { \
if ((keyptr) != NULL) { \
(keyptr)->iov_len = NODEKSZ(node); \
@ -1164,7 +1164,7 @@ typedef struct MDBX_node {
} while (0)
/* Set the node's key into key. */
#define MDBX_GET_KEY2(node, key) \
#define MDBX_GET_KEYVALUE(node, key) \
do { \
key.iov_len = NODEKSZ(node); \
key.iov_base = NODEKEY(node); \

View File

@ -5097,7 +5097,7 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta,
/* LY: check mapsize limits */
const uint64_t mapsize_min =
page.mp_meta.mm_geo.lower * (uint64_t)page.mp_meta.mm_psize;
STATIC_ASSERT(MAX_MAPSIZE < SSIZE_MAX - MAX_PAGESIZE);
STATIC_ASSERT(MAX_MAPSIZE < PTRDIFF_MAX - MAX_PAGESIZE);
STATIC_ASSERT(MIN_MAPSIZE < MAX_MAPSIZE);
if (mapsize_min < MIN_MAPSIZE || mapsize_min > MAX_MAPSIZE) {
mdbx_notice("meta[%u] has invalid min-mapsize (%" PRIu64 "), skip it",
@ -5511,7 +5511,7 @@ int __cold mdbx_env_get_maxkeysize(MDBX_env *env) {
(((pagesize)-PAGEHDRSZ) / sizeof(pgno_t) - 1)
static void __cold mdbx_setup_pagesize(MDBX_env *env, const size_t pagesize) {
STATIC_ASSERT(SSIZE_MAX > MAX_MAPSIZE);
STATIC_ASSERT(PTRDIFF_MAX > MAX_MAPSIZE);
STATIC_ASSERT(MIN_PAGESIZE > sizeof(MDBX_page));
mdbx_ensure(env, mdbx_is_power2(pagesize));
mdbx_ensure(env, pagesize >= MIN_PAGESIZE);
@ -6345,7 +6345,7 @@ static int __cold mdbx_setup_lck(MDBX_env *env, char *lck_pathname,
} else {
if (env->me_flags & MDBX_EXCLUSIVE)
return MDBX_BUSY;
if (size > SSIZE_MAX || (size & (env->me_os_psize - 1)) ||
if (size > PTRDIFF_MAX || (size & (env->me_os_psize - 1)) ||
size < env->me_os_psize) {
mdbx_notice("lck-file has invalid size %" PRIu64 " bytes", size);
return MDBX_PROBLEM;
@ -7547,7 +7547,7 @@ static int mdbx_cursor_next(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
mdbx_cursor_next(&mc->mc_xcursor->mx_cursor, data, NULL, MDBX_NEXT);
if (op != MDBX_NEXT || rc != MDBX_NOTFOUND) {
if (likely(rc == MDBX_SUCCESS))
MDBX_GET_KEY(leaf, key);
MDBX_GET_MAYNULL_KEYPTR(leaf, key);
return rc;
}
}
@ -7583,8 +7583,10 @@ skip:
mp->mp_pgno, NUMKEYS(mp), mc->mc_ki[mc->mc_top]);
if (IS_LEAF2(mp)) {
key->iov_len = mc->mc_db->md_xsize;
key->iov_base = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->iov_len);
if (likely(key)) {
key->iov_len = mc->mc_db->md_xsize;
key->iov_base = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->iov_len);
}
return MDBX_SUCCESS;
}
@ -7607,7 +7609,7 @@ skip:
}
}
MDBX_GET_KEY(leaf, key);
MDBX_GET_MAYNULL_KEYPTR(leaf, key);
return MDBX_SUCCESS;
}
@ -7638,7 +7640,7 @@ static int mdbx_cursor_prev(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
mdbx_cursor_prev(&mc->mc_xcursor->mx_cursor, data, NULL, MDBX_PREV);
if (op != MDBX_PREV || rc != MDBX_NOTFOUND) {
if (likely(rc == MDBX_SUCCESS)) {
MDBX_GET_KEY(leaf, key);
MDBX_GET_MAYNULL_KEYPTR(leaf, key);
mc->mc_flags &= ~C_EOF;
}
return rc;
@ -7673,8 +7675,10 @@ static int mdbx_cursor_prev(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
mp->mp_pgno, NUMKEYS(mp), mc->mc_ki[mc->mc_top]);
if (IS_LEAF2(mp)) {
key->iov_len = mc->mc_db->md_xsize;
key->iov_base = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->iov_len);
if (likely(key)) {
key->iov_len = mc->mc_db->md_xsize;
key->iov_base = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->iov_len);
}
return MDBX_SUCCESS;
}
@ -7697,7 +7701,7 @@ static int mdbx_cursor_prev(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
}
}
MDBX_GET_KEY(leaf, key);
MDBX_GET_MAYNULL_KEYPTR(leaf, key);
return MDBX_SUCCESS;
}
@ -7734,7 +7738,7 @@ __hot static int mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
nodekey.iov_base = LEAF2KEY(mp, 0, nodekey.iov_len);
} else {
leaf = NODEPTR(mp, 0);
MDBX_GET_KEY2(leaf, nodekey);
MDBX_GET_KEYVALUE(leaf, nodekey);
}
rc = mc->mc_dbx->md_cmp(key, &nodekey);
if (unlikely(rc == 0)) {
@ -7753,7 +7757,7 @@ __hot static int mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
nodekey.iov_base = LEAF2KEY(mp, nkeys - 1, nodekey.iov_len);
} else {
leaf = NODEPTR(mp, nkeys - 1);
MDBX_GET_KEY2(leaf, nodekey);
MDBX_GET_KEYVALUE(leaf, nodekey);
}
rc = mc->mc_dbx->md_cmp(key, &nodekey);
if (rc == 0) {
@ -7772,7 +7776,7 @@ __hot static int mdbx_cursor_set(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
LEAF2KEY(mp, mc->mc_ki[mc->mc_top], nodekey.iov_len);
} else {
leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
MDBX_GET_KEY2(leaf, nodekey);
MDBX_GET_KEYVALUE(leaf, nodekey);
}
rc = mc->mc_dbx->md_cmp(key, &nodekey);
if (rc == 0) {
@ -7894,7 +7898,7 @@ set1:
/* The key already matches in all other cases */
if (op == MDBX_SET_RANGE || op == MDBX_SET_KEY)
MDBX_GET_KEY(leaf, key);
MDBX_GET_MAYNULL_KEYPTR(leaf, key);
mdbx_debug("==> cursor placed on key [%s], data [%s]", DKEY(key), DVAL(data));
return rc;
@ -7940,7 +7944,7 @@ static int mdbx_cursor_first(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data) {
return rc;
}
}
MDBX_GET_KEY(leaf, key);
MDBX_GET_MAYNULL_KEYPTR(leaf, key);
return MDBX_SUCCESS;
}
@ -7986,7 +7990,7 @@ static int mdbx_cursor_last(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data) {
}
}
MDBX_GET_KEY(leaf, key);
MDBX_GET_MAYNULL_KEYPTR(leaf, key);
return MDBX_SUCCESS;
}
@ -8024,7 +8028,7 @@ int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
key->iov_base = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->iov_len);
} else {
MDBX_node *leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
MDBX_GET_KEY(leaf, key);
MDBX_GET_MAYNULL_KEYPTR(leaf, key);
if (data) {
if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
if (unlikely(!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED))) {
@ -8136,7 +8140,7 @@ int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data,
{
MDBX_node *leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
MDBX_GET_KEY(leaf, key);
MDBX_GET_MAYNULL_KEYPTR(leaf, key);
rc = mdbx_node_read(mc, leaf, data);
break;
}
@ -8770,7 +8774,7 @@ new_sub:
}
}
}
mdbx_cassert(mc, mc->mc_xcursor->mx_db.md_entries < SIZE_MAX);
mdbx_cassert(mc, mc->mc_xcursor->mx_db.md_entries < PTRDIFF_MAX);
ecount = (size_t)mc->mc_xcursor->mx_db.md_entries;
if (flags & MDBX_APPENDDUP)
xflags |= MDBX_APPEND;
@ -9615,8 +9619,8 @@ int mdbx_cursor_count(MDBX_cursor *mc, size_t *countp) {
if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
mdbx_cassert(mc, mc->mc_xcursor && (mc->mc_xcursor->mx_cursor.mc_flags &
C_INITIALIZED));
*countp = unlikely(mc->mc_xcursor->mx_db.md_entries > SIZE_MAX)
? SIZE_MAX
*countp = unlikely(mc->mc_xcursor->mx_db.md_entries > PTRDIFF_MAX)
? PTRDIFF_MAX
: (size_t)mc->mc_xcursor->mx_db.md_entries;
}
}
@ -13405,10 +13409,13 @@ int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
if (unlikely(!txn || !size_items))
return MDBX_EINVAL;
if (unlikely(!begin_key && begin_data))
if (unlikely(begin_data && (begin_key == NULL || begin_key == MDBX_EPSILON)))
return MDBX_EINVAL;
if (unlikely(!end_key && end_data))
if (unlikely(end_data && (end_key == NULL || end_key == MDBX_EPSILON)))
return MDBX_EINVAL;
if (unlikely(begin_key == MDBX_EPSILON && end_key == MDBX_EPSILON))
return MDBX_EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
@ -13442,35 +13449,65 @@ int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *begin_key,
}
MDBX_val stub = {0, 0};
rc = mdbx_cursor_first(&begin.outer, &stub, &stub);
} else if (end_key && !begin_data && !end_data &&
(begin_key == end_key || mdbx_is_samedata(begin_key, end_key))) {
/* LY: single key case */
int exact = 0;
rc = mdbx_cursor_set(&begin.outer, begin_key, NULL, MDBX_SET, &exact);
if (unlikely(rc != MDBX_SUCCESS)) {
*size_items = 0;
return (rc == MDBX_NOTFOUND) ? MDBX_SUCCESS : rc;
if (unlikely(end_key == MDBX_EPSILON)) {
/* LY: FIRST..+epsilon case */
return (rc == MDBX_SUCCESS)
? mdbx_cursor_count(&begin.outer, (size_t *)size_items)
: rc;
}
*size_items = 1;
if (begin.outer.mc_xcursor != NULL) {
MDBX_node *leaf = NODEPTR(begin.outer.mc_pg[begin.outer.mc_top],
begin.outer.mc_ki[begin.outer.mc_top]);
if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
/* LY: return the number of duplicates for given key */
mdbx_tassert(txn, begin.outer.mc_xcursor == &begin.inner &&
(begin.inner.mx_cursor.mc_flags & C_INITIALIZED));
*size_items =
(sizeof(*size_items) >= sizeof(begin.inner.mx_db.md_entries) ||
begin.inner.mx_db.md_entries <= SIZE_MAX)
? (size_t)begin.inner.mx_db.md_entries
: SIZE_MAX;
}
}
return MDBX_SUCCESS;
} else {
rc = mdbx_cursor_set(&begin.outer, begin_key, begin_data,
begin_data ? MDBX_GET_BOTH_RANGE : MDBX_SET_RANGE,
NULL);
bool step_backward = false;
if (unlikely(begin_key == MDBX_EPSILON)) {
if (end_key == NULL) {
/* LY: -epsilon..LAST case */
MDBX_val stub = {0, 0};
rc = mdbx_cursor_last(&begin.outer, &stub, &stub);
return (rc == MDBX_SUCCESS)
? mdbx_cursor_count(&begin.outer, (size_t *)size_items)
: rc;
}
/* LY: -epsilon..value case */
assert(end_key != MDBX_EPSILON);
begin_key = end_key;
step_backward = true;
} else if (unlikely(end_key == MDBX_EPSILON)) {
/* LY: value..+epsilon case */
assert(begin_key != MDBX_EPSILON);
end_key = begin_key;
}
if (end_key && !begin_data && !end_data &&
(begin_key == end_key || mdbx_is_samedata(begin_key, end_key))) {
/* LY: single key case */
int exact = 0;
rc = mdbx_cursor_set(&begin.outer, begin_key, NULL, MDBX_SET, &exact);
if (unlikely(step_backward) && rc == MDBX_SUCCESS)
rc = mdbx_cursor_prev(&begin.outer, NULL, NULL, MDBX_PREV_NODUP);
if (unlikely(rc != MDBX_SUCCESS)) {
*size_items = 0;
return (rc == MDBX_NOTFOUND) ? MDBX_SUCCESS : rc;
}
*size_items = 1;
if (begin.outer.mc_xcursor != NULL) {
MDBX_node *leaf = NODEPTR(begin.outer.mc_pg[begin.outer.mc_top],
begin.outer.mc_ki[begin.outer.mc_top]);
if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
/* LY: return the number of duplicates for given key */
mdbx_tassert(txn,
begin.outer.mc_xcursor == &begin.inner &&
(begin.inner.mx_cursor.mc_flags & C_INITIALIZED));
*size_items =
(sizeof(*size_items) >= sizeof(begin.inner.mx_db.md_entries) ||
begin.inner.mx_db.md_entries <= PTRDIFF_MAX)
? (size_t)begin.inner.mx_db.md_entries
: PTRDIFF_MAX;
}
}
return MDBX_SUCCESS;
} else {
rc = mdbx_cursor_set(&begin.outer, begin_key, begin_data,
begin_data ? MDBX_GET_BOTH_RANGE : MDBX_SET_RANGE,
NULL);
}
}
if (unlikely(rc != MDBX_SUCCESS)) {
@ -13728,9 +13765,9 @@ int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
(cx.inner.mx_cursor.mc_flags & C_INITIALIZED));
*values_count =
(sizeof(*values_count) >= sizeof(cx.inner.mx_db.md_entries) ||
cx.inner.mx_db.md_entries <= SIZE_MAX)
cx.inner.mx_db.md_entries <= PTRDIFF_MAX)
? (size_t)cx.inner.mx_db.md_entries
: SIZE_MAX;
: PTRDIFF_MAX;
}
}
}