From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Vladimir Davydov Subject: [PATCH 3/7] Make tuple_extract_key support multikey indexes Date: Wed, 8 May 2019 20:22:35 +0300 Message-Id: In-Reply-To: References: In-Reply-To: References: To: tarantool-patches@freelists.org List-ID: Add multikey_idx argument to tuple_extract_key and forward it to tuple_field_by_part in the method implementation. For unikey indexes pass -1. We need this to support multikey indexes in Vinyl. We could of course introduce a separate set of methods for multikey indexes (something like tuple_extract_key_multikey), but that would look cumbersome and hardly result in any performance benefits, because passing -1 to a relatively cold function, such as key extractor, isn't a big deal. Besides, passing multikey_idx unconditionally is consistent with tuple_compare. --- src/box/index.cc | 2 +- src/box/key_def.h | 18 +++++++++++---- src/box/lua/key_def.c | 2 +- src/box/memtx_space.c | 2 +- src/box/request.c | 5 ++-- src/box/space.c | 2 +- src/box/sql.c | 10 ++++---- src/box/tuple_extract_key.cc | 54 ++++++++++++++++++++++++++++++-------------- src/box/vinyl.c | 12 +++++----- src/box/vy_run.c | 6 ++--- src/box/vy_stmt.c | 17 +++++++------- src/box/vy_stmt.h | 6 ++--- 12 files changed, 83 insertions(+), 53 deletions(-) diff --git a/src/box/index.cc b/src/box/index.cc index 2817d076..39b0ee46 100644 --- a/src/box/index.cc +++ b/src/box/index.cc @@ -156,7 +156,7 @@ box_tuple_extract_key(box_tuple_t *tuple, uint32_t space_id, uint32_t index_id, struct index *index = index_find(space, index_id); if (index == NULL) return NULL; - return tuple_extract_key(tuple, index->def->key_def, key_size); + return tuple_extract_key(tuple, index->def->key_def, -1, key_size); } static inline int diff --git a/src/box/key_def.h b/src/box/key_def.h index 5f65f501..8b94b3b6 100644 --- a/src/box/key_def.h +++ b/src/box/key_def.h @@ -145,11 +145,13 @@ typedef int (*tuple_compare_t)(struct tuple *tuple_a, /** @copydoc tuple_extract_key() */ typedef char *(*tuple_extract_key_t)(struct tuple *tuple, struct key_def *key_def, + int multikey_idx, uint32_t *key_size); /** @copydoc tuple_extract_key_raw() */ typedef char *(*tuple_extract_key_raw_t)(const char *data, const char *data_end, struct key_def *key_def, + int multikey_idx, uint32_t *key_size); /** @copydoc tuple_hash() */ typedef uint32_t (*tuple_hash_t)(struct tuple *tuple, @@ -531,10 +533,12 @@ key_part_cmp(const struct key_part *parts1, uint32_t part_count1, * Check if a key of @a tuple contains NULL. * @param tuple Tuple to check. * @param def Key def to check by. + * @param multikey_idx Multikey index hint. * @retval Does the key contain NULL or not? */ bool -tuple_key_contains_null(struct tuple *tuple, struct key_def *def); +tuple_key_contains_null(struct tuple *tuple, struct key_def *def, + int multikey_idx); /** * Check that tuple fields match with given key definition @@ -554,6 +558,7 @@ tuple_validate_key_parts(struct key_def *key_def, struct tuple *tuple); * has O(n) complexity, where n is the number of key parts. * @param tuple - tuple from which need to extract key * @param key_def - definition of key that need to extract + * @param multikey_idx - multikey index hint * @param key_size - here will be size of extracted key * * @retval not NULL Success @@ -561,9 +566,10 @@ tuple_validate_key_parts(struct key_def *key_def, struct tuple *tuple); */ static inline char * tuple_extract_key(struct tuple *tuple, struct key_def *key_def, - uint32_t *key_size) + int multikey_idx, uint32_t *key_size) { - return key_def->tuple_extract_key(tuple, key_def, key_size); + return key_def->tuple_extract_key(tuple, key_def, multikey_idx, + key_size); } /** @@ -574,6 +580,7 @@ tuple_extract_key(struct tuple *tuple, struct key_def *key_def, * @param data - msgpuck data from which need to extract key * @param data_end - pointer at the end of data * @param key_def - definition of key that need to extract + * @param multikey_idx - multikey index hint * @param key_size - here will be size of extracted key * * @retval not NULL Success @@ -581,10 +588,11 @@ tuple_extract_key(struct tuple *tuple, struct key_def *key_def, */ static inline char * tuple_extract_key_raw(const char *data, const char *data_end, - struct key_def *key_def, uint32_t *key_size) + struct key_def *key_def, int multikey_idx, + uint32_t *key_size) { return key_def->tuple_extract_key_raw(data, data_end, key_def, - key_size); + multikey_idx, key_size); } /** diff --git a/src/box/lua/key_def.c b/src/box/lua/key_def.c index 72bb05c4..28d40478 100644 --- a/src/box/lua/key_def.c +++ b/src/box/lua/key_def.c @@ -265,7 +265,7 @@ lbox_key_def_extract_key(struct lua_State *L) struct region *region = &fiber()->gc; size_t region_svp = region_used(region); uint32_t key_size; - char *key = tuple_extract_key(tuple, key_def, &key_size); + char *key = tuple_extract_key(tuple, key_def, -1, &key_size); tuple_unref(tuple); if (key == NULL) return luaT_error(L); diff --git a/src/box/memtx_space.c b/src/box/memtx_space.c index 4d5e7991..265bf923 100644 --- a/src/box/memtx_space.c +++ b/src/box/memtx_space.c @@ -445,7 +445,7 @@ memtx_space_execute_upsert(struct space *space, struct txn *txn, /* Extract the primary key from tuple. */ const char *key = tuple_extract_key_raw(request->tuple, request->tuple_end, - index->def->key_def, NULL); + index->def->key_def, -1, NULL); if (key == NULL) return -1; /* Cut array header */ diff --git a/src/box/request.c b/src/box/request.c index 9c684af7..8b84260a 100644 --- a/src/box/request.c +++ b/src/box/request.c @@ -92,7 +92,7 @@ request_create_from_tuple(struct request *request, struct space *space, uint32_t size, key_size; const char *data = tuple_data_range(old_tuple, &size); request->key = tuple_extract_key_raw(data, data + size, - space->index[0]->def->key_def, &key_size); + space->index[0]->def->key_def, -1, &key_size); if (request->key == NULL) return -1; request->key_end = request->key + key_size; @@ -125,7 +125,8 @@ request_rebind_to_primary_key(struct request *request, struct space *space, struct index *pk = space_index(space, 0); assert(pk != NULL); uint32_t key_len; - char *key = tuple_extract_key(found_tuple, pk->def->key_def, &key_len); + char *key = tuple_extract_key(found_tuple, pk->def->key_def, -1, + &key_len); assert(key != NULL); request->key = key; request->key_end = key + key_len; diff --git a/src/box/space.c b/src/box/space.c index edfc5d60..9a266604 100644 --- a/src/box/space.c +++ b/src/box/space.c @@ -320,7 +320,7 @@ space_before_replace(struct space *space, struct txn *txn, break; index = pk; key = tuple_extract_key_raw(request->tuple, request->tuple_end, - index->def->key_def, NULL); + index->def->key_def, -1, NULL); if (key == NULL) return -1; part_count = mp_decode_array(&key); diff --git a/src/box/sql.c b/src/box/sql.c index 7a20d86e..c3f404ee 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -480,7 +480,7 @@ int tarantoolsqlEphemeralDelete(BtCursor *pCur) char *key; uint32_t key_size; key = tuple_extract_key(pCur->last_tuple, - pCur->iter->index->def->key_def, + pCur->iter->index->def->key_def, -1, &key_size); if (key == NULL) return SQL_TARANTOOL_DELETE_FAIL; @@ -506,7 +506,7 @@ int tarantoolsqlDelete(BtCursor *pCur, u8 flags) int rc; key = tuple_extract_key(pCur->last_tuple, - pCur->iter->index->def->key_def, + pCur->iter->index->def->key_def, -1, &key_size); if (key == NULL) return SQL_TARANTOOL_DELETE_FAIL; @@ -561,7 +561,7 @@ int tarantoolsqlEphemeralClearTable(BtCursor *pCur) uint32_t key_size; while (iterator_next(it, &tuple) == 0 && tuple != NULL) { - key = tuple_extract_key(tuple, it->index->def->key_def, + key = tuple_extract_key(tuple, it->index->def->key_def, -1, &key_size); if (space_ephemeral_delete(pCur->space, key) != 0) { iterator_delete(it); @@ -594,7 +594,7 @@ int tarantoolsqlClearTable(struct space *space, uint32_t *tuple_count) if (iter == NULL) return SQL_TARANTOOL_ITERATOR_FAIL; while (iterator_next(iter, &tuple) == 0 && tuple != NULL) { - request.key = tuple_extract_key(tuple, pk->def->key_def, + request.key = tuple_extract_key(tuple, pk->def->key_def, -1, &key_size); request.key_end = request.key + key_size; rc = box_process_rw(&request, space, &unused); @@ -801,7 +801,7 @@ out: #ifndef NDEBUG /* Sanity check. */ original_size = region_used(&fiber()->gc); - key = tuple_extract_key(tuple, key_def, &key_size); + key = tuple_extract_key(tuple, key_def, -1, &key_size); if (key != NULL) { int new_rc = sqlVdbeRecordCompareMsgpack(key, unpacked); region_truncate(&fiber()->gc, original_size); diff --git a/src/box/tuple_extract_key.cc b/src/box/tuple_extract_key.cc index 7868378d..15e43aae 100644 --- a/src/box/tuple_extract_key.cc +++ b/src/box/tuple_extract_key.cc @@ -37,8 +37,10 @@ key_def_contains_sequential_parts(const struct key_def *def) template static char * tuple_extract_key_sequential_raw(const char *data, const char *data_end, - struct key_def *key_def, uint32_t *key_size) + struct key_def *key_def, int multikey_idx, + uint32_t *key_size) { + (void)multikey_idx; assert(!has_optional_parts || key_def->is_nullable); assert(key_def_is_sequential(key_def)); assert(has_optional_parts == key_def->has_optional_parts); @@ -87,7 +89,7 @@ tuple_extract_key_sequential_raw(const char *data, const char *data_end, template static inline char * tuple_extract_key_sequential(struct tuple *tuple, struct key_def *key_def, - uint32_t *key_size) + int multikey_idx, uint32_t *key_size) { assert(key_def_is_sequential(key_def)); assert(!has_optional_parts || key_def->is_nullable); @@ -97,6 +99,7 @@ tuple_extract_key_sequential(struct tuple *tuple, struct key_def *key_def, return tuple_extract_key_sequential_raw(data, data_end, key_def, + multikey_idx, key_size); } @@ -105,17 +108,18 @@ tuple_extract_key_sequential(struct tuple *tuple, struct key_def *key_def, * @copydoc tuple_extract_key() */ template + bool has_json_paths, bool is_multikey> static char * tuple_extract_key_slowpath(struct tuple *tuple, struct key_def *key_def, - uint32_t *key_size) + int multikey_idx, uint32_t *key_size) { assert(has_json_paths == key_def->has_json_paths); assert(!has_optional_parts || key_def->is_nullable); assert(has_optional_parts == key_def->has_optional_parts); assert(contains_sequential_parts == key_def_contains_sequential_parts(key_def)); - assert(!key_def_is_multikey(key_def)); + assert(is_multikey == key_def_is_multikey(key_def)); + assert(!key_def_is_multikey(key_def) || multikey_idx >= 0); assert(mp_sizeof_nil() == 1); const char *data = tuple_data(tuple); uint32_t part_count = key_def->part_count; @@ -130,9 +134,13 @@ tuple_extract_key_slowpath(struct tuple *tuple, struct key_def *key_def, if (!has_json_paths) { field = tuple_field_raw(format, data, field_map, key_def->parts[i].fieldno); - } else { + } else if (!is_multikey) { field = tuple_field_raw_by_part(format, data, field_map, &key_def->parts[i], -1); + } else { + field = tuple_field_raw_by_part(format, data, field_map, + &key_def->parts[i], + multikey_idx); } if (has_optional_parts && field == NULL) { bsize += mp_sizeof_nil(); @@ -177,9 +185,13 @@ tuple_extract_key_slowpath(struct tuple *tuple, struct key_def *key_def, if (!has_json_paths) { field = tuple_field_raw(format, data, field_map, key_def->parts[i].fieldno); - } else { + } else if (!is_multikey) { field = tuple_field_raw_by_part(format, data, field_map, &key_def->parts[i], -1); + } else { + field = tuple_field_raw_by_part(format, data, field_map, + &key_def->parts[i], + multikey_idx); } if (has_optional_parts && field == NULL) { key_buf = mp_encode_nil(key_buf); @@ -230,12 +242,13 @@ tuple_extract_key_slowpath(struct tuple *tuple, struct key_def *key_def, template static char * tuple_extract_key_slowpath_raw(const char *data, const char *data_end, - struct key_def *key_def, uint32_t *key_size) + struct key_def *key_def, int multikey_idx, + uint32_t *key_size) { assert(has_json_paths == key_def->has_json_paths); assert(!has_optional_parts || key_def->is_nullable); assert(has_optional_parts == key_def->has_optional_parts); - assert(!key_def_is_multikey(key_def)); + assert(!key_def_is_multikey(key_def) || multikey_idx >= 0); assert(mp_sizeof_nil() == 1); /* allocate buffer with maximal possible size */ char *key = (char *) region_alloc(&fiber()->gc, data_end - data); @@ -311,8 +324,8 @@ tuple_extract_key_slowpath_raw(const char *data, const char *data_end, const char *src = field; const char *src_end = field_end; if (has_json_paths && part->path != NULL) { - if (tuple_go_to_path(&src, part->path, - part->path_len, -1) != 0) { + if (tuple_go_to_path(&src, part->path, part->path_len, + multikey_idx) != 0) { /* * The path must be correct as * it has already been validated @@ -361,7 +374,7 @@ key_def_set_extract_func_plain(struct key_def *def) } else { def->tuple_extract_key = tuple_extract_key_slowpath ; + has_optional_parts, false, false>; def->tuple_extract_key_raw = tuple_extract_key_slowpath_raw ; } @@ -372,9 +385,15 @@ static void key_def_set_extract_func_json(struct key_def *def) { assert(def->has_json_paths); - def->tuple_extract_key = tuple_extract_key_slowpath + if (key_def_is_multikey(def)) { + def->tuple_extract_key = tuple_extract_key_slowpath ; + has_optional_parts, true, true>; + } else { + def->tuple_extract_key = tuple_extract_key_slowpath + ; + } def->tuple_extract_key_raw = tuple_extract_key_slowpath_raw ; } @@ -411,16 +430,17 @@ key_def_set_extract_func(struct key_def *key_def) } bool -tuple_key_contains_null(struct tuple *tuple, struct key_def *def) +tuple_key_contains_null(struct tuple *tuple, struct key_def *def, + int multikey_idx) { - assert(!key_def_is_multikey(def)); struct tuple_format *format = tuple_format(tuple); const char *data = tuple_data(tuple); const uint32_t *field_map = tuple_field_map(tuple); for (struct key_part *part = def->parts, *end = part + def->part_count; part < end; ++part) { const char *field = tuple_field_raw_by_part(format, data, - field_map, part, -1); + field_map, part, + multikey_idx); if (field == NULL || mp_typeof(*field) == MP_NIL) return true; } diff --git a/src/box/vinyl.c b/src/box/vinyl.c index 6ffbecd9..eddbdbed 100644 --- a/src/box/vinyl.c +++ b/src/box/vinyl.c @@ -1344,7 +1344,7 @@ vy_get_by_secondary_tuple(struct vy_lsm *lsm, struct vy_tx *tx, struct vy_entry key; if (vy_stmt_is_key(entry.stmt)) { key.stmt = vy_stmt_extract_key(entry.stmt, lsm->pk_in_cmp_def, - lsm->env->key_format); + lsm->env->key_format, -1); if (key.stmt == NULL) return -1; } else { @@ -1601,10 +1601,10 @@ vy_check_is_unique_secondary(struct vy_tx *tx, const struct vy_read_view **rv, if (!lsm->check_is_unique) return 0; if (lsm->key_def->is_nullable && - tuple_key_contains_null(stmt, lsm->key_def)) + tuple_key_contains_null(stmt, lsm->key_def, -1)) return 0; struct tuple *key = vy_stmt_extract_key(stmt, lsm->key_def, - lsm->env->key_format); + lsm->env->key_format, -1); if (key == NULL) return -1; struct tuple *found; @@ -2149,7 +2149,7 @@ vy_upsert(struct vy_env *env, struct vy_tx *tx, struct txn_stmt *stmt, */ /* Find the old tuple using the primary key. */ struct tuple *key = vy_stmt_extract_key_raw(tuple, tuple_end, - pk->key_def, pk->env->key_format); + pk->key_def, pk->env->key_format, -1); if (key == NULL) return -1; int rc = vy_get(pk, tx, vy_tx_read_view(tx), key, &stmt->old_tuple); @@ -4064,7 +4064,7 @@ vy_build_on_replace(struct trigger *trigger, void *event) /* Forward the statement to the new LSM tree. */ if (stmt->old_tuple != NULL) { struct tuple *delete = vy_stmt_extract_key(stmt->old_tuple, - lsm->cmp_def, lsm->env->key_format); + lsm->cmp_def, lsm->env->key_format, -1); if (delete == NULL) goto err; vy_stmt_set_type(delete, IPROTO_DELETE); @@ -4219,7 +4219,7 @@ vy_build_recover_stmt(struct vy_lsm *lsm, struct vy_lsm *pk, struct tuple *old_tuple = old.stmt; if (old_tuple != NULL) { delete = vy_stmt_extract_key(old_tuple, lsm->cmp_def, - lsm->env->key_format); + lsm->env->key_format, -1); if (delete == NULL) return -1; vy_stmt_set_type(delete, IPROTO_DELETE); diff --git a/src/box/vy_run.c b/src/box/vy_run.c index b15a96e9..409c3d96 100644 --- a/src/box/vy_run.c +++ b/src/box/vy_run.c @@ -2167,7 +2167,7 @@ vy_run_writer_start_page(struct vy_run_writer *writer, const char *key = vy_stmt_is_key(first_entry.stmt) ? tuple_data(first_entry.stmt) : tuple_extract_key(first_entry.stmt, - writer->cmp_def, NULL); + writer->cmp_def, -1, NULL); if (key == NULL) return -1; if (run->info.page_count == 0) { @@ -2321,7 +2321,7 @@ vy_run_writer_commit(struct vy_run_writer *writer) const char *key = vy_stmt_is_key(writer->last.stmt) ? tuple_data(writer->last.stmt) : tuple_extract_key(writer->last.stmt, - writer->cmp_def, NULL); + writer->cmp_def, -1, NULL); if (key == NULL) goto out; @@ -2431,7 +2431,7 @@ vy_run_rebuild_index(struct vy_run *run, const char *dir, goto close_err; } key = vy_stmt_is_key(tuple) ? tuple_data(tuple) : - tuple_extract_key(tuple, cmp_def, NULL); + tuple_extract_key(tuple, cmp_def, -1, NULL); if (prev_tuple != NULL) tuple_unref(prev_tuple); prev_tuple = tuple; diff --git a/src/box/vy_stmt.c b/src/box/vy_stmt.c index c8088d34..847b6196 100644 --- a/src/box/vy_stmt.c +++ b/src/box/vy_stmt.c @@ -489,11 +489,12 @@ out: struct tuple * vy_stmt_extract_key(struct tuple *stmt, struct key_def *key_def, - struct tuple_format *format) + struct tuple_format *format, int multikey_idx) { struct region *region = &fiber()->gc; size_t region_svp = region_used(region); - const char *key_raw = tuple_extract_key(stmt, key_def, NULL); + const char *key_raw = tuple_extract_key(stmt, key_def, + multikey_idx, NULL); if (key_raw == NULL) return NULL; uint32_t part_count = mp_decode_array(&key_raw); @@ -506,13 +507,13 @@ vy_stmt_extract_key(struct tuple *stmt, struct key_def *key_def, struct tuple * vy_stmt_extract_key_raw(const char *data, const char *data_end, - struct key_def *key_def, - struct tuple_format *format) + struct key_def *key_def, struct tuple_format *format, + int multikey_idx) { struct region *region = &fiber()->gc; size_t region_svp = region_used(region); - const char *key_raw = tuple_extract_key_raw(data, data_end, - key_def, NULL); + const char *key_raw = tuple_extract_key_raw(data, data_end, key_def, + multikey_idx, NULL); if (key_raw == NULL) return NULL; uint32_t part_count = mp_decode_array(&key_raw); @@ -622,7 +623,7 @@ vy_stmt_encode_primary(struct tuple *value, struct key_def *key_def, case IPROTO_DELETE: extracted = vy_stmt_is_key(value) ? tuple_data_range(value, &size) : - tuple_extract_key(value, key_def, &size); + tuple_extract_key(value, key_def, -1, &size); if (extracted == NULL) return -1; request.key = extracted; @@ -666,7 +667,7 @@ vy_stmt_encode_secondary(struct tuple *value, struct key_def *cmp_def, uint32_t size; const char *extracted = vy_stmt_is_key(value) ? tuple_data_range(value, &size) : - tuple_extract_key(value, cmp_def, &size); + tuple_extract_key(value, cmp_def, -1, &size); if (extracted == NULL) return -1; if (type == IPROTO_REPLACE || type == IPROTO_INSERT) { diff --git a/src/box/vy_stmt.h b/src/box/vy_stmt.h index 49fa1602..929e537a 100644 --- a/src/box/vy_stmt.h +++ b/src/box/vy_stmt.h @@ -606,7 +606,7 @@ vy_key_from_msgpack(struct tuple_format *format, const char *key) */ struct tuple * vy_stmt_extract_key(struct tuple *stmt, struct key_def *key_def, - struct tuple_format *format); + struct tuple_format *format, int multikey_idx); /** * Extract the key from msgpack by the given key definition @@ -615,8 +615,8 @@ vy_stmt_extract_key(struct tuple *stmt, struct key_def *key_def, */ struct tuple * vy_stmt_extract_key_raw(const char *data, const char *data_end, - struct key_def *key_def, - struct tuple_format *format); + struct key_def *key_def, struct tuple_format *format, + int multikey_idx); /** * Add a statement hash to a bloom filter builder. -- 2.11.0