diff --git a/src/box/lua/space.cc b/src/box/lua/space.cc index 498e04e55dda..b6e409532b06 100644 --- a/src/box/lua/space.cc +++ b/src/box/lua/space.cc @@ -566,8 +566,13 @@ lbox_fillspace(struct lua_State *L, struct space *space, int i) lua_setfield(L, -2, "hint"); } - lua_pushnil(L); - lua_setfield(L, -2, "fast_offset"); + if (space_is_memtx(space) && index_def->type == TREE) { + lua_pushboolean(L, index_opts->fast_offset); + lua_setfield(L, -2, "fast_offset"); + } else { + lua_pushnil(L); + lua_setfield(L, -2, "fast_offset"); + } if (index_opts->func_id > 0) { lua_pushstring(L, "func"); diff --git a/src/box/memtx_engine.cc b/src/box/memtx_engine.cc index c7567f74d5e2..862487bb0526 100644 --- a/src/box/memtx_engine.cc +++ b/src/box/memtx_engine.cc @@ -2014,6 +2014,8 @@ memtx_index_def_change_requires_rebuild(struct index *index, return true; if (old_def->opts.hint != new_def->opts.hint) return true; + if (old_def->opts.fast_offset != new_def->opts.fast_offset) + return true; const struct key_def *old_cmp_def, *new_cmp_def; if (index_depends_on_pk(index)) { diff --git a/src/box/memtx_space.c b/src/box/memtx_space.c index a8bfff113f50..4f6cd0104ad9 100644 --- a/src/box/memtx_space.c +++ b/src/box/memtx_space.c @@ -761,11 +761,6 @@ memtx_space_check_index_def(struct space *space, struct index_def *index_def) { struct key_def *key_def = index_def->key_def; - if (index_def->opts.fast_offset) { - diag_set(ClientError, ER_UNSUPPORTED, "memtx", - "logarithmic select with offset"); - return -1; - } if (key_def->is_nullable) { if (index_def->iid == 0) { diag_set(ClientError, ER_NULLABLE_PRIMARY, @@ -787,6 +782,13 @@ memtx_space_check_index_def(struct space *space, struct index_def *index_def) "HASH index must be unique"); return -1; } + if (index_def->opts.fast_offset) { + diag_set(ClientError, ER_MODIFY_INDEX, + index_def->name, space_name(space), + "HASH index does not support " + "logarithmic select with offset"); + return -1; + } if (key_def->is_multikey) { diag_set(ClientError, ER_MODIFY_INDEX, index_def->name, space_name(space), @@ -816,6 +818,13 @@ memtx_space_check_index_def(struct space *space, struct index_def *index_def) "RTREE index can not be unique"); return -1; } + if (index_def->opts.fast_offset) { + diag_set(ClientError, ER_MODIFY_INDEX, + index_def->name, space_name(space), + "RTREE index does not support " + "logarithmic select with offset"); + return -1; + } if (key_def->parts[0].type != FIELD_TYPE_ARRAY) { diag_set(ClientError, ER_MODIFY_INDEX, index_def->name, space_name(space), @@ -849,6 +858,13 @@ memtx_space_check_index_def(struct space *space, struct index_def *index_def) "BITSET can not be unique"); return -1; } + if (index_def->opts.fast_offset) { + diag_set(ClientError, ER_MODIFY_INDEX, + index_def->name, space_name(space), + "BITSET index does not support " + "logarithmic select with offset"); + return -1; + } if (key_def->parts[0].type != FIELD_TYPE_UNSIGNED && key_def->parts[0].type != FIELD_TYPE_STRING && key_def->parts[0].type != FIELD_TYPE_VARBINARY) { diff --git a/src/box/memtx_tree.cc b/src/box/memtx_tree.cc index 9779074e579b..da873954f7c6 100644 --- a/src/box/memtx_tree.cc +++ b/src/box/memtx_tree.cc @@ -122,21 +122,35 @@ memtx_tree_data_is_equal(const struct memtx_tree_data_common *a, #define BPS_TREE_NO_DEBUG 1 #define bps_tree_arg_t struct key_def * -#define BPS_TREE_NAMESPACE NS_NO_HINT #define bps_tree_elem_t struct memtx_tree_data #define bps_tree_key_t struct memtx_tree_key_data * +#define BPS_TREE_NAMESPACE NS_NO_HINT +#include "salad/bps_tree.h" +#undef BPS_TREE_NAMESPACE + +#define BPS_TREE_NAMESPACE NS_FAST_OFFSET_NO_HINT +#define BPS_INNER_CARD #include "salad/bps_tree.h" +#undef BPS_TREE_NAMESPACE +#undef BPS_INNER_CARD #undef BPS_TREE_NAMESPACE #undef bps_tree_elem_t #undef bps_tree_key_t -#define BPS_TREE_NAMESPACE NS_USE_HINT #define bps_tree_elem_t struct memtx_tree_data #define bps_tree_key_t struct memtx_tree_key_data * +#define BPS_TREE_NAMESPACE NS_USE_HINT #include "salad/bps_tree.h" +#undef BPS_TREE_NAMESPACE + +#define BPS_TREE_NAMESPACE NS_FAST_OFFSET_USE_HINT +#define BPS_INNER_CARD +#include "salad/bps_tree.h" +#undef BPS_TREE_NAMESPACE +#undef BPS_INNER_CARD #undef BPS_TREE_NAMESPACE #undef bps_tree_elem_t @@ -153,46 +167,74 @@ memtx_tree_data_is_equal(const struct memtx_tree_data_common *a, using namespace NS_NO_HINT; using namespace NS_USE_HINT; +using namespace NS_FAST_OFFSET_NO_HINT; +using namespace NS_FAST_OFFSET_USE_HINT; -template +template struct memtx_tree_selector; template <> -struct memtx_tree_selector : NS_NO_HINT::memtx_tree {}; +struct memtx_tree_selector : NS_NO_HINT::memtx_tree {}; template <> -struct memtx_tree_selector : NS_USE_HINT::memtx_tree {}; +struct memtx_tree_selector : NS_USE_HINT::memtx_tree {}; -template -using memtx_tree_t = struct memtx_tree_selector; +template <> +struct memtx_tree_selector : NS_FAST_OFFSET_NO_HINT::memtx_tree {}; -template +template <> +struct memtx_tree_selector : NS_FAST_OFFSET_USE_HINT::memtx_tree {}; + +template +using memtx_tree_t = struct memtx_tree_selector; + +template struct memtx_tree_view_selector; template <> -struct memtx_tree_view_selector : NS_NO_HINT::memtx_tree_view {}; +struct memtx_tree_view_selector : NS_NO_HINT::memtx_tree_view {}; template <> -struct memtx_tree_view_selector : NS_USE_HINT::memtx_tree_view {}; +struct memtx_tree_view_selector : NS_USE_HINT::memtx_tree_view {}; -template -using memtx_tree_view_t = struct memtx_tree_view_selector; +template <> +struct memtx_tree_view_selector : + NS_FAST_OFFSET_NO_HINT::memtx_tree_view {}; -template +template <> +struct memtx_tree_view_selector : + NS_FAST_OFFSET_USE_HINT::memtx_tree_view {}; + +template +using memtx_tree_view_t = + struct memtx_tree_view_selector; + +template struct memtx_tree_iterator_selector; template <> -struct memtx_tree_iterator_selector { +struct memtx_tree_iterator_selector { using type = NS_NO_HINT::memtx_tree_iterator; }; template <> -struct memtx_tree_iterator_selector { +struct memtx_tree_iterator_selector { using type = NS_USE_HINT::memtx_tree_iterator; }; -template -using memtx_tree_iterator_t = typename memtx_tree_iterator_selector::type; +template <> +struct memtx_tree_iterator_selector { + using type = NS_FAST_OFFSET_NO_HINT::memtx_tree_iterator; +}; + +template <> +struct memtx_tree_iterator_selector { + using type = NS_FAST_OFFSET_USE_HINT::memtx_tree_iterator; +}; + +template +using memtx_tree_iterator_t = + typename memtx_tree_iterator_selector::type; static void invalidate_tree_iterator(NS_NO_HINT::memtx_tree_iterator *itr) @@ -206,14 +248,26 @@ invalidate_tree_iterator(NS_USE_HINT::memtx_tree_iterator *itr) *itr = NS_USE_HINT::memtx_tree_invalid_iterator(); } -template +static void +invalidate_tree_iterator(NS_FAST_OFFSET_NO_HINT::memtx_tree_iterator *itr) +{ + *itr = NS_FAST_OFFSET_NO_HINT::memtx_tree_invalid_iterator(); +} + +static void +invalidate_tree_iterator(NS_FAST_OFFSET_USE_HINT::memtx_tree_iterator *itr) +{ + *itr = NS_FAST_OFFSET_USE_HINT::memtx_tree_invalid_iterator(); +} + +template struct memtx_tree_index { struct index base; - memtx_tree_t tree; + memtx_tree_t tree; struct memtx_tree_data *build_array; size_t build_array_size, build_array_alloc_size; struct memtx_gc_task gc_task; - memtx_tree_iterator_t gc_iterator; + memtx_tree_iterator_t gc_iterator; }; /* {{{ Utilities. *************************************************/ @@ -239,7 +293,7 @@ memtx_tree_qcompare(const void* a, const void *b, void *c) } /* {{{ MemtxTree Iterators ****************************************/ -template +template struct tree_iterator { struct iterator base; @@ -263,7 +317,7 @@ struct tree_iterator { * One need not care about the iterator's position: it will * automatically get adjusted on iterator->next call. */ - memtx_tree_iterator_t tree_iterator; + memtx_tree_iterator_t tree_iterator; enum iterator_type type; struct memtx_tree_key_data after_data; struct memtx_tree_key_data key_data; @@ -287,17 +341,23 @@ struct tree_iterator { struct mempool *pool; }; -static_assert(sizeof(struct tree_iterator) <= MEMTX_ITERATOR_SIZE, - "sizeof(struct tree_iterator) must be less than or equal " - "to MEMTX_ITERATOR_SIZE"); -static_assert(sizeof(struct tree_iterator) <= MEMTX_ITERATOR_SIZE, - "sizeof(struct tree_iterator) must be less than or equal " - "to MEMTX_ITERATOR_SIZE"); +static_assert(sizeof(struct tree_iterator) <= MEMTX_ITERATOR_SIZE, + "sizeof(struct tree_iterator) must be less than or " + "equal to MEMTX_ITERATOR_SIZE"); +static_assert(sizeof(struct tree_iterator) <= MEMTX_ITERATOR_SIZE, + "sizeof(struct tree_iterator) must be less than or " + "equal to MEMTX_ITERATOR_SIZE"); +static_assert(sizeof(struct tree_iterator) <= MEMTX_ITERATOR_SIZE, + "sizeof(struct tree_iterator) must be less than or " + "equal to MEMTX_ITERATOR_SIZE"); +static_assert(sizeof(struct tree_iterator) <= MEMTX_ITERATOR_SIZE, + "sizeof(struct tree_iterator) must be less than or " + "equal to MEMTX_ITERATOR_SIZE"); /** Set last fetched tuple. */ -template +template static inline void -tree_iterator_set_last_tuple(struct tree_iterator *it, +tree_iterator_set_last_tuple(struct tree_iterator *it, struct tuple *tuple) { assert(tuple != NULL); @@ -308,9 +368,9 @@ tree_iterator_set_last_tuple(struct tree_iterator *it, } /** Set hint of last fetched tuple. */ -template +template static inline void -tree_iterator_set_last_hint(struct tree_iterator *it, hint_t hint) +tree_iterator_set_last_hint(struct tree_iterator *it, hint_t hint) { if (!USE_HINT) return; @@ -332,9 +392,9 @@ tree_iterator_set_last_hint(struct tree_iterator *it, hint_t hint) * Prerequisites: last is not NULL and last->tuple is not NULL. * Use set_last_tuple and set_last_hint manually to free occupied resources. */ -template +template static inline void -tree_iterator_set_last(struct tree_iterator *it, +tree_iterator_set_last(struct tree_iterator *it, struct memtx_tree_data *last) { assert(last != NULL && last->tuple != NULL); @@ -342,23 +402,23 @@ tree_iterator_set_last(struct tree_iterator *it, tree_iterator_set_last_hint(it, last->hint); } -template +template static void tree_iterator_free(struct iterator *iterator); -template -static inline struct tree_iterator * +template +static inline struct tree_iterator * get_tree_iterator(struct iterator *it) { - assert(it->free == &tree_iterator_free); - return (struct tree_iterator *) it; + assert(it->free == (&tree_iterator_free)); + return (struct tree_iterator *) it; } -template +template static void tree_iterator_free(struct iterator *iterator) { - struct tree_iterator *it = get_tree_iterator(iterator); + struct tree_iterator *it = get_tree_iterator(iterator); if (it->last.tuple != NULL) tuple_unref(it->last.tuple); if (it->last_func_key != NULL) @@ -370,10 +430,10 @@ tree_iterator_free(struct iterator *iterator) * If the iterator's underlying tuple does not match its last tuple, it needs * to be repositioned. */ -template +template static void -tree_iterator_prev_reposition(struct tree_iterator *iterator, - struct memtx_tree_index *index) +tree_iterator_prev_reposition(struct tree_iterator *iterator, + struct memtx_tree_index *index) { bool exact = false; iterator->tree_iterator = @@ -393,16 +453,16 @@ tree_iterator_prev_reposition(struct tree_iterator *iterator, assert(exact || in_txn() == NULL || !memtx_tx_manager_use_mvcc_engine); } -template +template static int tree_iterator_next_base(struct iterator *iterator, struct tuple **ret) { struct space *space; struct index *index_base; index_weak_ref_get_checked(&iterator->index_ref, &space, &index_base); - struct memtx_tree_index *index = - (struct memtx_tree_index *)index_base; - struct tree_iterator *it = get_tree_iterator(iterator); + struct memtx_tree_index *index = + (struct memtx_tree_index *)index_base; + struct tree_iterator *it = get_tree_iterator(iterator); assert(it->last.tuple != NULL); struct memtx_tree_data *check = memtx_tree_iterator_get_elem(&index->tree, &it->tree_iterator); @@ -418,7 +478,7 @@ tree_iterator_next_base(struct iterator *iterator, struct tuple **ret) if (*ret == NULL) { iterator->next_internal = exhausted_iterator_next; } else { - tree_iterator_set_last(it, res); + tree_iterator_set_last(it, res); struct txn *txn = in_txn(); bool is_multikey = index_base->def->key_def->is_multikey; uint32_t mk_index = is_multikey ? (uint32_t)res->hint : 0; @@ -438,16 +498,16 @@ tree_iterator_next_base(struct iterator *iterator, struct tuple **ret) return 0; } -template +template static int tree_iterator_prev_base(struct iterator *iterator, struct tuple **ret) { struct space *space; struct index *index_base; index_weak_ref_get_checked(&iterator->index_ref, &space, &index_base); - struct memtx_tree_index *index = - (struct memtx_tree_index *)index_base; - struct tree_iterator *it = get_tree_iterator(iterator); + struct memtx_tree_index *index = + (struct memtx_tree_index *)index_base; + struct tree_iterator *it = get_tree_iterator(iterator); assert(it->last.tuple != NULL); struct memtx_tree_data *check = memtx_tree_iterator_get_elem(&index->tree, &it->tree_iterator); @@ -462,7 +522,7 @@ tree_iterator_prev_base(struct iterator *iterator, struct tuple **ret) if (*ret == NULL) { iterator->next_internal = exhausted_iterator_next; } else { - tree_iterator_set_last(it, res); + tree_iterator_set_last(it, res); struct txn *txn = in_txn(); bool is_multikey = index_base->def->key_def->is_multikey; uint32_t mk_index = is_multikey ? (uint32_t)res->hint : 0; @@ -486,16 +546,16 @@ tree_iterator_prev_base(struct iterator *iterator, struct tuple **ret) return 0; } -template +template static int tree_iterator_next_equal_base(struct iterator *iterator, struct tuple **ret) { struct space *space; struct index *index_base; index_weak_ref_get_checked(&iterator->index_ref, &space, &index_base); - struct memtx_tree_index *index = - (struct memtx_tree_index *)index_base; - struct tree_iterator *it = get_tree_iterator(iterator); + struct memtx_tree_index *index = + (struct memtx_tree_index *)index_base; + struct tree_iterator *it = get_tree_iterator(iterator); assert(it->last.tuple != NULL); struct memtx_tree_data *check = memtx_tree_iterator_get_elem(&index->tree, &it->tree_iterator); @@ -528,7 +588,7 @@ tree_iterator_next_equal_base(struct iterator *iterator, struct tuple **ret) it->key_data.part_count); /*********MVCC TRANSACTION MANAGER STORY GARBAGE COLLECTION BOUND END**********/ } else { - tree_iterator_set_last(it, res); + tree_iterator_set_last(it, res); struct txn *txn = in_txn(); bool is_multikey = index_base->def->key_def->is_multikey; uint32_t mk_index = is_multikey ? (uint32_t)res->hint : 0; @@ -547,16 +607,16 @@ tree_iterator_next_equal_base(struct iterator *iterator, struct tuple **ret) return 0; } -template +template static int tree_iterator_prev_equal_base(struct iterator *iterator, struct tuple **ret) { struct space *space; struct index *index_base; index_weak_ref_get_checked(&iterator->index_ref, &space, &index_base); - struct memtx_tree_index *index = - (struct memtx_tree_index *)index_base; - struct tree_iterator *it = get_tree_iterator(iterator); + struct memtx_tree_index *index = + (struct memtx_tree_index *)index_base; + struct tree_iterator *it = get_tree_iterator(iterator); assert(it->last.tuple != NULL); struct memtx_tree_data *check = memtx_tree_iterator_get_elem(&index->tree, &it->tree_iterator); @@ -587,7 +647,7 @@ tree_iterator_prev_equal_base(struct iterator *iterator, struct tuple **ret) it->key_data.part_count); /*********MVCC TRANSACTION MANAGER STORY GARBAGE COLLECTION BOUND END**********/ } else { - tree_iterator_set_last(it, res); + tree_iterator_set_last(it, res); struct txn *txn = in_txn(); bool is_multikey = index_base->def->key_def->is_multikey; uint32_t mk_index = is_multikey ? (uint32_t)res->hint : 0; @@ -611,12 +671,12 @@ tree_iterator_prev_equal_base(struct iterator *iterator, struct tuple **ret) } #define WRAP_ITERATOR_METHOD(name) \ -template \ +template \ static int \ name(struct iterator *iterator, struct tuple **ret) \ { \ do { \ - int rc = name##_base(iterator, ret); \ + int rc = name##_base(iterator, ret); \ if (rc != 0 || \ iterator->next_internal == exhausted_iterator_next) \ return rc; \ @@ -632,27 +692,31 @@ WRAP_ITERATOR_METHOD(tree_iterator_prev_equal); #undef WRAP_ITERATOR_METHOD -template +template static void -tree_iterator_set_next_method(struct tree_iterator *it) +tree_iterator_set_next_method(struct tree_iterator *it) { assert(it->last.tuple != NULL); switch (it->type) { case ITER_EQ: - it->base.next_internal = tree_iterator_next_equal; + it->base.next_internal = + tree_iterator_next_equal; break; case ITER_REQ: - it->base.next_internal = tree_iterator_prev_equal; + it->base.next_internal = + tree_iterator_prev_equal; break; case ITER_LT: case ITER_LE: case ITER_PP: - it->base.next_internal = tree_iterator_prev; + it->base.next_internal = + tree_iterator_prev; break; case ITER_GE: case ITER_GT: case ITER_NP: - it->base.next_internal = tree_iterator_next; + it->base.next_internal = + tree_iterator_next; break; default: /* The type was checked in initIterator */ @@ -726,7 +790,7 @@ prepare_start_prefix_iterator(struct memtx_tree_key_data *start_data, return true; } -template +template static int tree_iterator_start(struct iterator *iterator, struct tuple **ret) { @@ -736,11 +800,12 @@ tree_iterator_start(struct iterator *iterator, struct tuple **ret) struct space *space; struct index *index_base; index_weak_ref_get_checked(&iterator->index_ref, &space, &index_base); - struct memtx_tree_index *index = - (struct memtx_tree_index *)index_base; - struct tree_iterator *it = get_tree_iterator(iterator); + struct memtx_tree_index *index = + (struct memtx_tree_index *)index_base; + struct tree_iterator *it = + get_tree_iterator(iterator); iterator->next_internal = exhausted_iterator_next; - memtx_tree_t *tree = &index->tree; + memtx_tree_t *tree = &index->tree; struct txn *txn = in_txn(); struct key_def *cmp_def = index->base.def->cmp_def; struct memtx_tree_key_data start_data = @@ -882,16 +947,16 @@ tree_iterator_start(struct iterator *iterator, struct tuple **ret) /* {{{ MemtxTree **********************************************************/ -template +template static void -memtx_tree_index_free(struct memtx_tree_index *index) +memtx_tree_index_free(struct memtx_tree_index *index) { memtx_tree_destroy(&index->tree); free(index->build_array); free(index); } -template +template static void memtx_tree_index_gc_run(struct memtx_gc_task *task, bool *done) { @@ -905,10 +970,10 @@ memtx_tree_index_gc_run(struct memtx_gc_task *task, bool *done) enum { YIELD_LOOPS = 10 }; #endif - struct memtx_tree_index *index = container_of(task, - struct memtx_tree_index, gc_task); - memtx_tree_t *tree = &index->tree; - memtx_tree_iterator_t *itr = &index->gc_iterator; + using index_t = struct memtx_tree_index; + index_t *index = container_of(task, index_t, gc_task); + memtx_tree_t *tree = &index->tree; + memtx_tree_iterator_t *itr = &index->gc_iterator; unsigned int loops = 0; while (!memtx_tree_iterator_is_invalid(itr)) { @@ -924,32 +989,32 @@ memtx_tree_index_gc_run(struct memtx_gc_task *task, bool *done) *done = true; } -template +template static void memtx_tree_index_gc_free(struct memtx_gc_task *task) { - struct memtx_tree_index *index = container_of(task, - struct memtx_tree_index, gc_task); + using index_t = struct memtx_tree_index; + index_t *index = container_of(task, index_t, gc_task); memtx_tree_index_free(index); } -template +template static struct memtx_gc_task_vtab * get_memtx_tree_index_gc_vtab() { static memtx_gc_task_vtab tab = { - .run = memtx_tree_index_gc_run, - .free = memtx_tree_index_gc_free, + .run = memtx_tree_index_gc_run, + .free = memtx_tree_index_gc_free, }; return &tab; }; -template +template static void memtx_tree_index_destroy(struct index *base) { - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; struct memtx_engine *memtx = (struct memtx_engine *)base->engine; if (base->def->iid == 0) { /* @@ -957,7 +1022,8 @@ memtx_tree_index_destroy(struct index *base) * in the index, which may take a while. Schedule a * background task in order not to block tx thread. */ - index->gc_task.vtab = get_memtx_tree_index_gc_vtab(); + index->gc_task.vtab = + get_memtx_tree_index_gc_vtab(); index->gc_iterator = memtx_tree_first(&index->tree); memtx_engine_schedule_gc(memtx, &index->gc_task); } else { @@ -969,12 +1035,12 @@ memtx_tree_index_destroy(struct index *base) } } -template +template static void memtx_tree_index_update_def(struct index *base) { - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; struct index_def *def = base->def; /* * We use extended key def for non-unique and nullable @@ -995,37 +1061,37 @@ memtx_tree_index_depends_on_pk(struct index *base) return !def->opts.is_unique || def->key_def->is_nullable; } -template +template static ssize_t memtx_tree_index_size(struct index *base) { - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; struct space *space = space_by_id(base->def->space_id); /* Substract invisible count. */ return memtx_tree_size(&index->tree) - memtx_tx_index_invisible_count(in_txn(), space, base); } -template +template static ssize_t memtx_tree_index_bsize(struct index *base) { - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; return memtx_tree_mem_used(&index->tree); } -template +template static int memtx_tree_index_random(struct index *base, uint32_t rnd, struct tuple **result) { - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; struct txn *txn = in_txn(); struct space *space = space_by_id(base->def->space_id); bool is_multikey = base->def->key_def->is_multikey; - if (memtx_tree_index_size(base) == 0) { + if (memtx_tree_index_size(base) == 0) { *result = NULL; memtx_tx_track_gap(txn, space, base, NULL, ITER_GE, NULL, 0); return 0; @@ -1045,25 +1111,25 @@ memtx_tree_index_random(struct index *base, uint32_t rnd, struct tuple **result) return memtx_prepare_result_tuple(space, result); } -template +template static ssize_t memtx_tree_index_count(struct index *base, enum iterator_type type, const char *key, uint32_t part_count) { if (type == ITER_ALL) - return memtx_tree_index_size(base); /* optimization */ + return memtx_tree_index_size(base); return generic_index_count(base, type, key, part_count); } -template +template static int memtx_tree_index_get_internal(struct index *base, const char *key, uint32_t part_count, struct tuple **result) { assert(base->def->opts.is_unique && part_count == base->def->key_def->part_count); - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; struct key_def *cmp_def = memtx_tree_cmp_def(&index->tree); struct txn *txn = in_txn(); struct space *space = space_by_id(base->def->space_id); @@ -1122,17 +1188,17 @@ tree_iterator_position_impl(struct memtx_tree_data *last, /** * Implementation of iterator position for general and multikey indexes. */ -template +template static int tree_iterator_position(struct iterator *it, const char **pos, uint32_t *size) { static_assert(!IS_MULTIKEY || USE_HINT, "Multikey index actually uses hint."); - struct memtx_tree_index *index = - (struct memtx_tree_index *) + struct memtx_tree_index *index = + (struct memtx_tree_index *) index_weak_ref_get_index_checked(&it->index_ref); - struct tree_iterator *tree_it = - get_tree_iterator(it); + struct tree_iterator *tree_it = + get_tree_iterator(it); return tree_iterator_position_impl( &tree_it->last, index->base.def, pos, size); } @@ -1185,24 +1251,26 @@ tree_iterator_position_func_impl(struct memtx_tree_data *last, /** * Implementation of iterator position for functional indexes. */ +template static int tree_iterator_position_func(struct iterator *it, const char **pos, uint32_t *size) { struct index *index = index_weak_ref_get_index_checked(&it->index_ref); - struct tree_iterator *tree_it = get_tree_iterator(it); + struct tree_iterator *tree_it = + get_tree_iterator(it); return tree_iterator_position_func_impl(&tree_it->last, index->def, pos, size); } -template +template static int memtx_tree_index_replace(struct index *base, struct tuple *old_tuple, struct tuple *new_tuple, enum dup_replace_mode mode, struct tuple **result, struct tuple **successor) { - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; struct key_def *key_def = base->def->key_def; struct key_def *cmp_def = memtx_tree_cmp_def(&index->tree); if (new_tuple != NULL && @@ -1255,8 +1323,9 @@ memtx_tree_index_replace(struct index *base, struct tuple *old_tuple, * In case of replacement, all old tuple entries are deleted * by all it's multikey indexes. */ +template static int -memtx_tree_index_replace_multikey_one(struct memtx_tree_index *index, +memtx_tree_index_replace_multikey_one(struct memtx_tree_index *index, struct tuple *old_tuple, struct tuple *new_tuple, enum dup_replace_mode mode, hint_t hint, struct memtx_tree_data *replaced_data, @@ -1302,10 +1371,12 @@ memtx_tree_index_replace_multikey_one(struct memtx_tree_index *index, * overridden with new_tuple, but they definitely present) and * delete operation is fault-tolerant. */ +template static void -memtx_tree_index_replace_multikey_rollback(struct memtx_tree_index *index, - struct tuple *new_tuple, struct tuple *replaced_tuple, - int err_multikey_idx) +memtx_tree_index_replace_multikey_rollback( + struct memtx_tree_index *index, + struct tuple *new_tuple, struct tuple *replaced_tuple, + int err_multikey_idx) { struct key_def *key_def = index->base.def->key_def; struct memtx_tree_data data; @@ -1381,13 +1452,14 @@ memtx_tree_index_replace_multikey_rollback(struct memtx_tree_index *index, * to compare - we also look at b+* tree value that has the tuple * pointer, and delete old tuple entries only. */ +template static int memtx_tree_index_replace_multikey(struct index *base, struct tuple *old_tuple, struct tuple *new_tuple, enum dup_replace_mode mode, struct tuple **result, struct tuple **successor) { - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; /* MUTLIKEY doesn't support successor for now. */ *successor = NULL; @@ -1476,8 +1548,9 @@ func_key_undo_new(struct region *region) * insertions for functional index. Routine uses given list to * return a given index object in it's original state. */ +template static void -memtx_tree_func_index_replace_rollback(struct memtx_tree_index *index, +memtx_tree_func_index_replace_rollback(struct memtx_tree_index *index, struct rlist *old_keys, struct rlist *new_keys) { @@ -1502,6 +1575,7 @@ memtx_tree_func_index_replace_rollback(struct memtx_tree_index *index, * original key_hint(s) pointers in case of failure and release * the now useless hints of old items in case of success. */ +template static int memtx_tree_func_index_replace(struct index *base, struct tuple *old_tuple, struct tuple *new_tuple, enum dup_replace_mode mode, @@ -1511,8 +1585,8 @@ memtx_tree_func_index_replace(struct index *base, struct tuple *old_tuple, *successor = NULL; struct memtx_engine *memtx = (struct memtx_engine *)base->engine; - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; struct index_def *index_def = index->base.def; assert(index_def->key_def->for_func_index); /* Make sure that key_def is not multikey - we rely on it below. */ @@ -1640,14 +1714,14 @@ memtx_tree_func_index_replace(struct index *base, struct tuple *old_tuple, return rc; } -template +template static struct iterator * memtx_tree_index_create_iterator(struct index *base, enum iterator_type type, const char *key, uint32_t part_count, const char *pos) { - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; struct memtx_engine *memtx = (struct memtx_engine *)base->engine; struct key_def *cmp_def = memtx_tree_cmp_def(&index->tree); @@ -1684,27 +1758,31 @@ memtx_tree_index_create_iterator(struct index *base, enum iterator_type type, return NULL; }); - struct tree_iterator *it = (struct tree_iterator *) - mempool_alloc(&memtx->iterator_pool); + struct tree_iterator *it = + (struct tree_iterator *) + mempool_alloc(&memtx->iterator_pool); if (it == NULL) { - diag_set(OutOfMemory, sizeof(struct tree_iterator), + diag_set(OutOfMemory, sizeof(struct tree_iterator), "memtx_tree_index", "iterator"); return NULL; } iterator_create(&it->base, base); it->pool = &memtx->iterator_pool; - it->base.next_internal = tree_iterator_start; + it->base.next_internal = tree_iterator_start; it->base.next = memtx_iterator_next; it->base.advance = generic_iterator_advance; - it->base.free = tree_iterator_free; + it->base.free = tree_iterator_free; if (base->def->key_def->for_func_index) { assert(USE_HINT); - it->base.position = tree_iterator_position_func; + it->base.position = tree_iterator_position_func; } else if (base->def->key_def->is_multikey) { assert(USE_HINT); - it->base.position = tree_iterator_position; + it->base.position = + tree_iterator_position; } else { - it->base.position = tree_iterator_position; + it->base.position = + tree_iterator_position; } it->type = type; it->key_data.key = key; @@ -1728,22 +1806,22 @@ memtx_tree_index_create_iterator(struct index *base, enum iterator_type type, return (struct iterator *)it; } -template +template static void memtx_tree_index_begin_build(struct index *base) { - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; assert(memtx_tree_size(&index->tree) == 0); (void)index; } -template +template static int memtx_tree_index_reserve(struct index *base, uint32_t size_hint) { - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; if (size_hint < index->build_array_alloc_size) return 0; struct memtx_tree_data *tmp = @@ -1759,10 +1837,10 @@ memtx_tree_index_reserve(struct index *base, uint32_t size_hint) return 0; } -template +template /** Initialize the next element of the index build_array. */ static int -memtx_tree_index_build_array_append(struct memtx_tree_index *index, +memtx_tree_index_build_array_append(struct memtx_tree_index *index, struct tuple *tuple, hint_t hint) { if (index->build_array == NULL) { @@ -1798,23 +1876,25 @@ memtx_tree_index_build_array_append(struct memtx_tree_index *index, return 0; } -template +template static int memtx_tree_index_build_next(struct index *base, struct tuple *tuple) { if (tuple_key_is_excluded(tuple, base->def->key_def, MULTIKEY_NONE)) return 0; - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; struct key_def *cmp_def = memtx_tree_cmp_def(&index->tree); return memtx_tree_index_build_array_append(index, tuple, tuple_hint(tuple, cmp_def)); } +template static int memtx_tree_index_build_next_multikey(struct index *base, struct tuple *tuple) { - struct memtx_tree_index *index = (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; struct key_def *cmp_def = memtx_tree_cmp_def(&index->tree); uint32_t multikey_count = tuple_multikey_count(tuple, cmp_def); for (uint32_t multikey_idx = 0; multikey_idx < multikey_count; @@ -1829,12 +1909,13 @@ memtx_tree_index_build_next_multikey(struct index *base, struct tuple *tuple) return 0; } +template static int memtx_tree_func_index_build_next(struct index *base, struct tuple *tuple) { struct memtx_engine *memtx = (struct memtx_engine *)base->engine; - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; struct index_def *index_def = index->base.def; assert(index_def->key_def->for_func_index); /* Make sure that key_def is not multikey - we rely on it below. */ @@ -1875,10 +1956,10 @@ memtx_tree_func_index_build_next(struct index *base, struct tuple *tuple) * of equal tuples (in terms of index's cmp_def and have same * tuple pointer). The build_array is expected to be sorted. */ -template +template static void memtx_tree_index_build_array_deduplicate( - struct memtx_tree_index *index) + struct memtx_tree_index *index) { if (index->build_array_size == 0) return; @@ -1911,12 +1992,12 @@ memtx_tree_index_build_array_deduplicate( index->build_array_size = w_idx + 1; } -template +template static void memtx_tree_index_end_build(struct index *base) { - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; struct key_def *cmp_def = memtx_tree_cmp_def(&index->tree); struct memtx_engine *memtx = (struct memtx_engine *)base->engine; tt_sort(index->build_array, index->build_array_size, @@ -1930,7 +2011,8 @@ memtx_tree_index_end_build(struct index *base) * the following memtx_tree_build assumes that * all keys are unique. */ - memtx_tree_index_build_array_deduplicate(index); + memtx_tree_index_build_array_deduplicate + (index); } memtx_tree_build(&index->tree, index->build_array, index->build_array_size); @@ -1942,27 +2024,27 @@ memtx_tree_index_end_build(struct index *base) } /** Read view implementation. */ -template +template struct tree_read_view { /** Base class. */ struct index_read_view base; /** Read view index. Ref counter incremented. */ - struct memtx_tree_index *index; + struct memtx_tree_index *index; /** BPS tree read view. */ - memtx_tree_view_t tree_view; + memtx_tree_view_t tree_view; /** Used for clarifying read view tuples. */ struct memtx_tx_snapshot_cleaner cleaner; }; /** Read view iterator implementation. */ -template +template struct tree_read_view_iterator { /** Base class. */ struct index_read_view_iterator_base base; /** Iterator key. */ struct memtx_tree_key_data key_data; /** BPS tree iterator. */ - memtx_tree_iterator_t tree_iterator; + memtx_tree_iterator_t tree_iterator; /** * Data that was fetched last. Is NULL only if there was no data * fetched. Otherwise, tuple pointer is not NULL, even if iterator @@ -1971,21 +2053,29 @@ struct tree_read_view_iterator { struct memtx_tree_data *last; }; -static_assert(sizeof(struct tree_read_view_iterator) <= +static_assert(sizeof(struct tree_read_view_iterator) <= INDEX_READ_VIEW_ITERATOR_SIZE, - "sizeof(struct tree_read_view_iterator) must be less than " - "or equal to INDEX_READ_VIEW_ITERATOR_SIZE"); -static_assert(sizeof(struct tree_read_view_iterator) <= + "sizeof(struct tree_read_view_iterator) must be " + "less than or equal to INDEX_READ_VIEW_ITERATOR_SIZE"); +static_assert(sizeof(struct tree_read_view_iterator) <= INDEX_READ_VIEW_ITERATOR_SIZE, - "sizeof(struct tree_read_view_iterator) must be less than " - "or equal to INDEX_READ_VIEW_ITERATOR_SIZE"); + "sizeof(struct tree_read_view_iterator) must be " + "less than or equal to INDEX_READ_VIEW_ITERATOR_SIZE"); +static_assert(sizeof(struct tree_read_view_iterator) <= + INDEX_READ_VIEW_ITERATOR_SIZE, + "sizeof(struct tree_read_view_iterator) must be " + "less than or equal to INDEX_READ_VIEW_ITERATOR_SIZE"); +static_assert(sizeof(struct tree_read_view_iterator) <= + INDEX_READ_VIEW_ITERATOR_SIZE, + "sizeof(struct tree_read_view_iterator) must be " + "less than or equal to INDEX_READ_VIEW_ITERATOR_SIZE"); -template +template static void tree_read_view_free(struct index_read_view *base) { - struct tree_read_view *rv = - (struct tree_read_view *)base; + struct tree_read_view *rv = + (struct tree_read_view *)base; memtx_tree_view_destroy(&rv->tree_view); index_unref(&rv->index->base); memtx_tx_snapshot_cleaner_destroy(&rv->cleaner); @@ -2012,15 +2102,15 @@ tree_read_view_get_raw(struct index_read_view *rv, } /** Implementation of next_raw index_read_view_iterator callback. */ -template +template static int tree_read_view_iterator_next_raw(struct index_read_view_iterator *iterator, struct read_view_tuple *result) { - struct tree_read_view_iterator *it = - (struct tree_read_view_iterator *)iterator; - struct tree_read_view *rv = - (struct tree_read_view *)it->base.index; + struct tree_read_view_iterator *it = + (struct tree_read_view_iterator *)iterator; + struct tree_read_view *rv = + (struct tree_read_view *)it->base.index; while (true) { struct memtx_tree_data *res = @@ -2043,12 +2133,12 @@ tree_read_view_iterator_next_raw(struct index_read_view_iterator *iterator, } /** Positions the iterator to the given key. */ -template +template static int -tree_read_view_iterator_start(struct tree_read_view_iterator *it, - enum iterator_type type, - const char *key, uint32_t part_count, - const char *pos) +tree_read_view_iterator_start( + struct tree_read_view_iterator *it, + enum iterator_type type, const char *key, uint32_t part_count, + const char *pos) { assert(type == ITER_ALL); assert(key == NULL); @@ -2058,16 +2148,17 @@ tree_read_view_iterator_start(struct tree_read_view_iterator *it, (void)key; (void)part_count; (void)pos; - struct tree_read_view *rv = - (struct tree_read_view *)it->base.index; - it->base.next_raw = tree_read_view_iterator_next_raw; + struct tree_read_view *rv = + (struct tree_read_view *)it->base.index; + it->base.next_raw = + tree_read_view_iterator_next_raw; it->tree_iterator = memtx_tree_view_first(&rv->tree_view); return 0; } -template +template static void -tree_read_view_reset_key_def(struct tree_read_view *rv) +tree_read_view_reset_key_def(struct tree_read_view *rv) { rv->tree_view.common.arg = NULL; } @@ -2077,13 +2168,13 @@ tree_read_view_reset_key_def(struct tree_read_view *rv) /** * Implementation of iterator position for general and multikey read views. */ -template +template static int tree_read_view_iterator_position(struct index_read_view_iterator *it, const char **pos, uint32_t *size) { - struct tree_read_view_iterator *tree_it = - (struct tree_read_view_iterator *)it; + struct tree_read_view_iterator *tree_it = + (struct tree_read_view_iterator *)it; return tree_iterator_position_impl( tree_it->last, it->base.index->def, pos, size); } @@ -2091,19 +2182,20 @@ tree_read_view_iterator_position(struct index_read_view_iterator *it, /** * Implementation of iterator position for functional index read views. */ +template static int tree_read_view_iterator_position_func(struct index_read_view_iterator *it, const char **pos, uint32_t *size) { - struct tree_read_view_iterator *tree_it = - (struct tree_read_view_iterator *)it; + struct tree_read_view_iterator *tree_it = + (struct tree_read_view_iterator *)it; return tree_iterator_position_func_impl(tree_it->last, it->base.index->def, pos, size); } /** Implementation of create_iterator index_read_view callback. */ -template +template static int tree_read_view_create_iterator(struct index_read_view *base, enum iterator_type type, @@ -2111,20 +2203,22 @@ tree_read_view_create_iterator(struct index_read_view *base, const char *pos, struct index_read_view_iterator *iterator) { - struct tree_read_view_iterator *it = - (struct tree_read_view_iterator *)iterator; + struct tree_read_view_iterator *it = + (struct tree_read_view_iterator *) + iterator; it->base.index = base; it->base.destroy = generic_index_read_view_iterator_destroy; it->base.next_raw = exhausted_index_read_view_iterator_next_raw; - if (it->base.index->def->key_def->for_func_index) - it->base.position = - tree_read_view_iterator_position_func; - else if (it->base.index->def->key_def->is_multikey) - it->base.position = - tree_read_view_iterator_position; - else - it->base.position = - tree_read_view_iterator_position; + if (it->base.index->def->key_def->for_func_index) { + it->base.position = tree_read_view_iterator_position_func + ; + } else if (it->base.index->def->key_def->is_multikey) { + it->base.position = tree_read_view_iterator_position + ; + } else { + it->base.position = tree_read_view_iterator_position + ; + } it->key_data.key = NULL; it->key_data.part_count = 0; if (USE_HINT) @@ -2135,19 +2229,21 @@ tree_read_view_create_iterator(struct index_read_view *base, } /** Implementation of create_read_view index callback. */ -template +template static struct index_read_view * memtx_tree_index_create_read_view(struct index *base) { static const struct index_read_view_vtab vtab = { - .free = tree_read_view_free, + .free = tree_read_view_free, .get_raw = tree_read_view_get_raw, - .create_iterator = tree_read_view_create_iterator, + .create_iterator = tree_read_view_create_iterator + , }; - struct memtx_tree_index *index = - (struct memtx_tree_index *)base; - struct tree_read_view *rv = - (struct tree_read_view *)xmalloc(sizeof(*rv)); + struct memtx_tree_index *index = + (struct memtx_tree_index *)base; + struct tree_read_view *rv = + (struct tree_read_view *)xmalloc( + sizeof(*rv)); index_read_view_create(&rv->base, &vtab, base->def); struct space *space = space_by_id(base->def->space_id); assert(space != NULL); @@ -2165,35 +2261,40 @@ memtx_tree_index_create_read_view(struct index *base) * recovery from snapshoot in case of func_index (because * key defintion is not completely initialized at that moment). */ -static const struct index_vtab memtx_tree_disabled_index_vtab = { - /* .destroy = */ memtx_tree_index_destroy, - /* .commit_create = */ generic_index_commit_create, - /* .abort_create = */ generic_index_abort_create, - /* .commit_modify = */ generic_index_commit_modify, - /* .commit_drop = */ generic_index_commit_drop, - /* .update_def = */ generic_index_update_def, - /* .depends_on_pk = */ generic_index_depends_on_pk, - /* .def_change_requires_rebuild = */ - generic_index_def_change_requires_rebuild, - /* .size = */ generic_index_size, - /* .bsize = */ generic_index_bsize, - /* .min = */ generic_index_min, - /* .max = */ generic_index_max, - /* .random = */ generic_index_random, - /* .count = */ generic_index_count, - /* .get_internal = */ generic_index_get_internal, - /* .get = */ generic_index_get, - /* .replace = */ disabled_index_replace, - /* .create_iterator = */ generic_index_create_iterator, - /* .create_read_view = */ generic_index_create_read_view, - /* .stat = */ generic_index_stat, - /* .compact = */ generic_index_compact, - /* .reset_stat = */ generic_index_reset_stat, - /* .begin_build = */ generic_index_begin_build, - /* .reserve = */ generic_index_reserve, - /* .build_next = */ disabled_index_build_next, - /* .end_build = */ generic_index_end_build, -}; +template +static const struct index_vtab * +get_memtx_tree_disabled_index_vtab(void) { + static const struct index_vtab vtab = { + /* .destroy = */ memtx_tree_index_destroy, + /* .commit_create = */ generic_index_commit_create, + /* .abort_create = */ generic_index_abort_create, + /* .commit_modify = */ generic_index_commit_modify, + /* .commit_drop = */ generic_index_commit_drop, + /* .update_def = */ generic_index_update_def, + /* .depends_on_pk = */ generic_index_depends_on_pk, + /* .def_change_requires_rebuild = */ + generic_index_def_change_requires_rebuild, + /* .size = */ generic_index_size, + /* .bsize = */ generic_index_bsize, + /* .min = */ generic_index_min, + /* .max = */ generic_index_max, + /* .random = */ generic_index_random, + /* .count = */ generic_index_count, + /* .get_internal = */ generic_index_get_internal, + /* .get = */ generic_index_get, + /* .replace = */ disabled_index_replace, + /* .create_iterator = */ generic_index_create_iterator, + /* .create_read_view = */ generic_index_create_read_view, + /* .stat = */ generic_index_stat, + /* .compact = */ generic_index_compact, + /* .reset_stat = */ generic_index_reset_stat, + /* .begin_build = */ generic_index_begin_build, + /* .reserve = */ generic_index_reserve, + /* .build_next = */ disabled_index_build_next, + /* .end_build = */ generic_index_end_build, + }; + return &vtab; +} /** Type of index in terms of different vtabs. */ enum memtx_tree_vtab_type { @@ -2213,7 +2314,7 @@ enum memtx_tree_vtab_type { * Get index vtab by @a TYPE and @a USE_HINT, template version. * USE_HINT == false is only allowed for general index type. */ -template +template static const struct index_vtab * get_memtx_tree_index_vtab(void) { @@ -2221,55 +2322,69 @@ get_memtx_tree_index_vtab(void) "Multikey and func indexes must use hints"); if (TYPE == MEMTX_TREE_VTAB_DISABLED) - return &memtx_tree_disabled_index_vtab; + return get_memtx_tree_disabled_index_vtab(); const bool is_mk = TYPE == MEMTX_TREE_VTAB_MULTIKEY; const bool is_func = TYPE == MEMTX_TREE_VTAB_FUNC; static const struct index_vtab vtab = { - /* .destroy = */ memtx_tree_index_destroy, + /* .destroy = */ + memtx_tree_index_destroy, /* .commit_create = */ generic_index_commit_create, /* .abort_create = */ generic_index_abort_create, /* .commit_modify = */ generic_index_commit_modify, /* .commit_drop = */ generic_index_commit_drop, - /* .update_def = */ memtx_tree_index_update_def, + /* .update_def = */ + memtx_tree_index_update_def, /* .depends_on_pk = */ memtx_tree_index_depends_on_pk, /* .def_change_requires_rebuild = */ memtx_index_def_change_requires_rebuild, - /* .size = */ memtx_tree_index_size, - /* .bsize = */ memtx_tree_index_bsize, + /* .size = */ memtx_tree_index_size, + /* .bsize = */ memtx_tree_index_bsize, /* .min = */ generic_index_min, /* .max = */ generic_index_max, - /* .random = */ memtx_tree_index_random, - /* .count = */ memtx_tree_index_count, - /* .get_internal */ memtx_tree_index_get_internal, + /* .random = */ memtx_tree_index_random, + /* .count = */ memtx_tree_index_count, + /* .get_internal */ + memtx_tree_index_get_internal, /* .get = */ memtx_index_get, - /* .replace = */ is_mk ? memtx_tree_index_replace_multikey : - is_func ? memtx_tree_func_index_replace : - memtx_tree_index_replace, + /* .replace = */ is_mk ? memtx_tree_index_replace_multikey + : + is_func ? memtx_tree_func_index_replace + : + memtx_tree_index_replace + , /* .create_iterator = */ - memtx_tree_index_create_iterator, + memtx_tree_index_create_iterator, /* .create_read_view = */ - memtx_tree_index_create_read_view, + memtx_tree_index_create_read_view, /* .stat = */ generic_index_stat, /* .compact = */ generic_index_compact, /* .reset_stat = */ generic_index_reset_stat, - /* .begin_build = */ memtx_tree_index_begin_build, - /* .reserve = */ memtx_tree_index_reserve, - /* .build_next = */ is_mk ? memtx_tree_index_build_next_multikey : - is_func ? memtx_tree_func_index_build_next : - memtx_tree_index_build_next, - /* .end_build = */ memtx_tree_index_end_build, + /* .begin_build = */ + memtx_tree_index_begin_build, + /* .reserve = */ + memtx_tree_index_reserve, + /* .build_next = */ + is_mk ? memtx_tree_index_build_next_multikey + : + is_func ? memtx_tree_func_index_build_next + : + memtx_tree_index_build_next + , + /* .end_build = */ + memtx_tree_index_end_build, }; return &vtab; } -template +template static struct index * memtx_tree_index_new_tpl(struct memtx_engine *memtx, struct index_def *def, const struct index_vtab *vtab) { - struct memtx_tree_index *index = - (struct memtx_tree_index *) + struct memtx_tree_index *index = + (struct memtx_tree_index *) xcalloc(1, sizeof(*index)); index_create(&index->base, (struct engine *)memtx, vtab, def); @@ -2284,6 +2399,7 @@ memtx_tree_index_new_tpl(struct memtx_engine *memtx, struct index_def *def, return &index->base; } +template struct index * memtx_tree_index_new(struct memtx_engine *memtx, struct index_def *def) { @@ -2292,25 +2408,38 @@ memtx_tree_index_new(struct memtx_engine *memtx, struct index_def *def) if (def->key_def->for_func_index) { if (def->key_def->func_index_func != NULL) { vtab = get_memtx_tree_index_vtab - (); + (); use_hint = true; } else { vtab = get_memtx_tree_index_vtab - (); + (); } } else if (def->key_def->is_multikey) { - vtab = get_memtx_tree_index_vtab(); + vtab = get_memtx_tree_index_vtab + (); use_hint = true; } else if (def->opts.hint == INDEX_HINT_ON) { vtab = get_memtx_tree_index_vtab - (); + (); use_hint = true; } else { vtab = get_memtx_tree_index_vtab - (); + (); } - if (use_hint) - return memtx_tree_index_new_tpl(memtx, def, vtab); + if (use_hint) { + return memtx_tree_index_new_tpl + (memtx, def, vtab); + } else { + return memtx_tree_index_new_tpl + (memtx, def, vtab); + } +} + +struct index * +memtx_tree_index_new(struct memtx_engine *memtx, struct index_def *def) +{ + if (def->opts.fast_offset) + return memtx_tree_index_new(memtx, def); else - return memtx_tree_index_new_tpl(memtx, def, vtab); + return memtx_tree_index_new(memtx, def); } diff --git a/test/box-luatest/gh_8204_fast_offset_test.lua b/test/box-luatest/gh_8204_fast_offset_test.lua index 295ff7c4fa58..276ac2ac701e 100644 --- a/test/box-luatest/gh_8204_fast_offset_test.lua +++ b/test/box-luatest/gh_8204_fast_offset_test.lua @@ -24,10 +24,28 @@ g.test_option = function() g.server:exec(function() local s = box.schema.space.create('test', {engine = 'memtx'}) - -- Memtx does not support the fast_offset option. + -- Memtx TREE index supports the fast_offset option. + s:create_index('pk', {type = 'TREE', fast_offset = true}) + + -- Memtx HASH index does not support the fast_offset option. t.assert_error_msg_content_equals( - "memtx does not support logarithmic select with offset", - s.create_index, s, 'pk', {fast_offset = true}) + "Can't create or modify index 'sk' in space 'test': " .. + "HASH index does not support logarithmic select with offset", + s.create_index, s, 'sk', {type = 'HASH', fast_offset = true}) + + -- Memtx RTREE index does not support the fast_offset option. + t.assert_error_msg_content_equals( + "Can't create or modify index 'sk' in space 'test': " .. + "RTREE index does not support logarithmic select with offset", + s.create_index, s, 'sk', {type = 'RTREE', fast_offset = true, + unique = false}) + + -- Memtx BITSET index does not support the fast_offset option. + t.assert_error_msg_content_equals( + "Can't create or modify index 'sk' in space 'test': " .. + "BITSET index does not support logarithmic select with offset", + s.create_index, s, 'sk', {type = 'BITSET', fast_offset = true, + unique = false}) -- Can successfuly create all indexes with fast_offset = false. s:create_index('k0', {type = 'TREE', fast_offset = false}) @@ -37,6 +55,13 @@ g.test_option = function() s:create_index('k3', {type = 'BITSET', fast_offset = false, unique = false}) + -- The indexes have the fast_offset expected. + t.assert_equals(s.index.pk.fast_offset, true) + t.assert_equals(s.index.k0.fast_offset, false) + t.assert_equals(s.index.k1.fast_offset, nil) + t.assert_equals(s.index.k2.fast_offset, nil) + t.assert_equals(s.index.k3.fast_offset, nil) + s:drop() s = box.schema.space.create('test', {engine = 'vinyl'}) @@ -49,6 +74,9 @@ g.test_option = function() -- Can successfully create vinyl index with fast_offset = false. s:create_index('pk', {fast_offset = false}) + -- The index has the fast_offset expected. + t.assert_equals(s.index.pk.fast_offset, nil) + s:drop() end) end