From 330852f972800b8cf16658a8e2afec64cc8bb9c5 Mon Sep 17 00:00:00 2001 From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Date: Fri, 8 Dec 2017 17:32:31 +0300 Subject: [PATCH] tuple: move tuple_extract_key functions to a separate .cc file Needed for #2048 --- src/CMakeLists.txt | 1 + src/box/CMakeLists.txt | 1 + src/box/index.h | 14 +++ src/box/key_def.cc | 1 + src/box/key_def.h | 39 +++++++ src/box/tuple.c | 194 ---------------------------------- src/box/tuple.h | 59 ----------- src/box/tuple_extract_key.cc | 197 +++++++++++++++++++++++++++++++++++ src/box/tuple_extract_key.h | 50 +++++++++ 9 files changed, 303 insertions(+), 253 deletions(-) create mode 100644 src/box/tuple_extract_key.cc create mode 100644 src/box/tuple_extract_key.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e5acef7389..b947a67c09 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -185,6 +185,7 @@ set(api_headers ${CMAKE_SOURCE_DIR}/src/box/tuple.h ${CMAKE_SOURCE_DIR}/src/box/tuple_format.h ${CMAKE_SOURCE_DIR}/src/box/tuple_compare.h + ${CMAKE_SOURCE_DIR}/src/box/tuple_extract_key.h ${CMAKE_SOURCE_DIR}/src/box/schema_def.h ${CMAKE_SOURCE_DIR}/src/box/box.h ${CMAKE_SOURCE_DIR}/src/box/index.h diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index e420fe3e05..ad7f910fc0 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -35,6 +35,7 @@ add_library(tuple STATIC tuple_format.c tuple_update.c tuple_compare.cc + tuple_extract_key.cc tuple_hash.cc tuple_dictionary.c key_def.cc diff --git a/src/box/index.h b/src/box/index.h index 74b1c9ae94..3c478c6d6e 100644 --- a/src/box/index.h +++ b/src/box/index.h @@ -195,6 +195,20 @@ ssize_t box_index_count(uint32_t space_id, uint32_t index_id, int type, const char *key, const char *key_end); +/** + * Extract key from tuple according to key definition of given + * index. Returned buffer is allocated on box_txn_alloc() with + * this key. + * @param tuple Tuple from which need to extract key. + * @param space_id Space identifier. + * @param index_id Index identifier. + * @retval not NULL Success + * @retval NULL Memory Allocation error + */ +char * +box_tuple_extract_key(const box_tuple_t *tuple, uint32_t space_id, + uint32_t index_id, uint32_t *key_size); + /** \endcond public */ /** diff --git a/src/box/key_def.cc b/src/box/key_def.cc index cf74e3e512..87b623013c 100644 --- a/src/box/key_def.cc +++ b/src/box/key_def.cc @@ -30,6 +30,7 @@ */ #include "key_def.h" #include "tuple_compare.h" +#include "tuple_extract_key.h" #include "tuple_hash.h" #include "column_mask.h" #include "schema_def.h" diff --git a/src/box/key_def.h b/src/box/key_def.h index 5982f5a470..b9c642b37b 100644 --- a/src/box/key_def.h +++ b/src/box/key_def.h @@ -383,6 +383,45 @@ key_part_check_compatibility(const struct key_part *old_parts, const struct key_part *new_parts, uint32_t new_part_count); +/** + * Extract key from tuple by given key definition and return + * buffer allocated on box_txn_alloc with this key. This function + * 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 key_size - here will be size of extracted key + * + * @retval not NULL Success + * @retval NULL Memory allocation error + */ +static inline char * +tuple_extract_key(const struct tuple *tuple, const struct key_def *key_def, + uint32_t *key_size) +{ + return key_def->tuple_extract_key(tuple, key_def, key_size); +} + +/** + * Extract key from raw msgpuck by given key definition and return + * buffer allocated on box_txn_alloc with this key. + * This function has O(n*m) complexity, where n is the number of key parts + * and m is the tuple size. + * @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 key_size - here will be size of extracted key + * + * @retval not NULL Success + * @retval NULL Memory allocation error + */ +static inline char * +tuple_extract_key_raw(const char *data, const char *data_end, + const struct key_def *key_def, uint32_t *key_size) +{ + return key_def->tuple_extract_key_raw(data, data_end, key_def, + key_size); +} + #if defined(__cplusplus) } /* extern "C" */ #endif /* defined(__cplusplus) */ diff --git a/src/box/tuple.c b/src/box/tuple.c index 40a091c133..d4760f3b15 100644 --- a/src/box/tuple.c +++ b/src/box/tuple.c @@ -184,200 +184,6 @@ tuple_next(struct tuple_iterator *it) return NULL; } -/** - * Optimized version of tuple_extract_key_raw() for sequential key defs - * @copydoc tuple_extract_key_raw() - */ -static char * -tuple_extract_key_sequential_raw(const char *data, const char *data_end, - const struct key_def *key_def, - uint32_t *key_size) -{ - assert(key_def_is_sequential(key_def)); - const char *field_start = data; - uint32_t bsize = mp_sizeof_array(key_def->part_count); - - mp_decode_array(&field_start); - const char *field_end = field_start; - - for (uint32_t i = 0; i < key_def->part_count; i++) - mp_next(&field_end); - bsize += field_end - field_start; - - assert(!data_end || (field_end - field_start <= data_end - data)); - (void) data_end; - - char *key = (char *) region_alloc(&fiber()->gc, bsize); - if (key == NULL) { - diag_set(OutOfMemory, bsize, "region", - "tuple_extract_key_raw_sequential"); - return NULL; - } - char *key_buf = mp_encode_array(key, key_def->part_count); - memcpy(key_buf, field_start, field_end - field_start); - - if (key_size != NULL) - *key_size = bsize; - return key; -} - -/** - * Optimized version of tuple_extract_key() for sequential key defs - * @copydoc tuple_extract_key() - */ -static inline char * -tuple_extract_key_sequential(const struct tuple *tuple, - const struct key_def *key_def, - uint32_t *key_size) -{ - assert(key_def_is_sequential(key_def)); - const char *data = tuple_data(tuple); - return tuple_extract_key_sequential_raw(data, NULL, key_def, key_size); -} - -/** - * General-purpose implementation of tuple_extract_key() - * @copydoc tuple_extract_key() - */ -static char * -tuple_extract_key_slowpath(const struct tuple *tuple, - const struct key_def *key_def, uint32_t *key_size) -{ - const char *data = tuple_data(tuple); - uint32_t part_count = key_def->part_count; - uint32_t bsize = mp_sizeof_array(part_count); - const struct tuple_format *format = tuple_format(tuple); - const uint32_t *field_map = tuple_field_map(tuple); - - /* Calculate the key size. */ - for (uint32_t i = 0; i < part_count; ++i) { - const char *field = - tuple_field_raw(format, data, field_map, - key_def->parts[i].fieldno); - const char *end = field; - /* - * Skip sequential part in order to minimize - * tuple_field_raw() calls. - */ - for (; i < key_def->part_count - 1; i++) { - if (key_def->parts[i].fieldno + 1 != - key_def->parts[i + 1].fieldno) { - /* End of sequential part */ - break; - } - mp_next(&end); - } - mp_next(&end); - bsize += end - field; - } - - char *key = (char *) region_alloc(&fiber()->gc, bsize); - if (key == NULL) { - diag_set(OutOfMemory, bsize, "region", "tuple_extract_key"); - return NULL; - } - char *key_buf = mp_encode_array(key, part_count); - for (uint32_t i = 0; i < part_count; ++i) { - const char *field = - tuple_field_raw(format, data, field_map, - key_def->parts[i].fieldno); - const char *end = field; - /* - * Skip sequential part in order to minimize - * tuple_field_raw() calls - */ - for (; i < key_def->part_count - 1; i++) { - if (key_def->parts[i].fieldno + 1 != - key_def->parts[i + 1].fieldno) { - /* End of sequential part */ - break; - } - mp_next(&end); - } - mp_next(&end); - bsize = end - field; - memcpy(key_buf, field, bsize); - key_buf += bsize; - } - if (key_size != NULL) - *key_size = key_buf - key; - return key; -} - -/** - * General-purpose version of tuple_extract_key_raw() - * @copydoc tuple_extract_key_raw() - */ -static char * -tuple_extract_key_slowpath_raw(const char *data, const char *data_end, - const struct key_def *key_def, - uint32_t *key_size) -{ - /* allocate buffer with maximal possible size */ - char *key = (char *) region_alloc(&fiber()->gc, data_end - data); - if (key == NULL) { - diag_set(OutOfMemory, data_end - data, "region", - "tuple_extract_key_raw"); - return NULL; - } - char *key_buf = mp_encode_array(key, key_def->part_count); - const char *field0 = data; - mp_decode_array(&field0); - const char *field0_end = field0; - mp_next(&field0_end); - const char *field = field0; - const char *field_end = field0_end; - uint32_t current_fieldno = 0; - for (uint32_t i = 0; i < key_def->part_count; i++) { - uint32_t fieldno = key_def->parts[i].fieldno; - for (; i < key_def->part_count - 1; i++) { - if (key_def->parts[i].fieldno + 1 != - key_def->parts[i + 1].fieldno) - break; - } - if (fieldno < current_fieldno) { - /* Rewind. */ - field = field0; - field_end = field0_end; - current_fieldno = 0; - } - - while (current_fieldno < fieldno) { - /* search first field of key in tuple raw data */ - field = field_end; - mp_next(&field_end); - current_fieldno++; - } - - while (current_fieldno < key_def->parts[i].fieldno) { - /* search the last field in subsequence */ - mp_next(&field_end); - current_fieldno++; - } - memcpy(key_buf, field, field_end - field); - key_buf += field_end - field; - assert(key_buf - key <= data_end - data); - } - if (key_size != NULL) - *key_size = (uint32_t)(key_buf - key); - return key; -} - -/** - * Initialize tuple_extract_key() and tuple_extract_key_raw() - */ -void -tuple_extract_key_set(struct key_def *key_def) -{ - if (key_def_is_sequential(key_def)) { - key_def->tuple_extract_key = tuple_extract_key_sequential; - key_def->tuple_extract_key_raw = tuple_extract_key_sequential_raw; - } else { - key_def->tuple_extract_key = tuple_extract_key_slowpath; - key_def->tuple_extract_key_raw = tuple_extract_key_slowpath_raw; - } -} - int tuple_init(field_name_hash_f hash) { diff --git a/src/box/tuple.h b/src/box/tuple.h index 27c475056a..6ebedf5f26 100644 --- a/src/box/tuple.h +++ b/src/box/tuple.h @@ -285,20 +285,6 @@ box_tuple_t * box_tuple_upsert(const box_tuple_t *tuple, const char *expr, const char *expr_end); -/** - * Extract key from tuple according to key definition of given index. - * Returned buffer is allocated on box_txn_alloc() with this key. - * This function has O(n) complexity, where n is the number of key parts. - * @param tuple tuple from which need to extract key - * @param space_id space identifier - * @param index_id index identifier - * @retval not NULL Success - * @retval NULL Memory allocation error - */ -char * -box_tuple_extract_key(const box_tuple_t *tuple, uint32_t space_id, - uint32_t index_id, uint32_t *key_size); - /** \endcond public */ /** @@ -409,51 +395,6 @@ tuple_snprint(char *buf, int size, const struct tuple *tuple); const char * tuple_str(const struct tuple *tuple); -/** - * Initialize key extraction functions in the key_def - * @param key_def key definition - */ -void -tuple_extract_key_set(struct key_def *key_def); - -/* Extract key from tuple by given key definition and return - * buffer allocated on box_txn_alloc with this key. This function - * 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 key_size - here will be size of extracted key - * - * @retval not NULL Success - * @retval NULL Memory allocation error - */ -static inline char * -tuple_extract_key(const struct tuple *tuple, const struct key_def *key_def, - uint32_t *key_size) -{ - return key_def->tuple_extract_key(tuple, key_def, key_size); -} - -/** - * Extract key from raw msgpuck by given key definition and return - * buffer allocated on box_txn_alloc with this key. - * This function has O(n*m) complexity, where n is the number of key parts - * and m is the tuple size. - * @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 key_size - here will be size of extracted key - * - * @retval not NULL Success - * @retval NULL Memory allocation error - */ -static inline char * -tuple_extract_key_raw(const char *data, const char *data_end, - const struct key_def *key_def, uint32_t *key_size) -{ - return key_def->tuple_extract_key_raw(data, data_end, key_def, - key_size); -} - /** * Get the format of the tuple. * @param tuple Tuple. diff --git a/src/box/tuple_extract_key.cc b/src/box/tuple_extract_key.cc new file mode 100644 index 0000000000..a83e9dfc42 --- /dev/null +++ b/src/box/tuple_extract_key.cc @@ -0,0 +1,197 @@ +#include "tuple_extract_key.h" +#include "tuple.h" +#include "fiber.h" + +/** + * Optimized version of tuple_extract_key_raw() for sequential key defs + * @copydoc tuple_extract_key_raw() + */ +static char * +tuple_extract_key_sequential_raw(const char *data, const char *data_end, + const struct key_def *key_def, + uint32_t *key_size) +{ + assert(key_def_is_sequential(key_def)); + const char *field_start = data; + uint32_t bsize = mp_sizeof_array(key_def->part_count); + + mp_decode_array(&field_start); + const char *field_end = field_start; + + for (uint32_t i = 0; i < key_def->part_count; i++) + mp_next(&field_end); + bsize += field_end - field_start; + + assert(!data_end || (field_end - field_start <= data_end - data)); + (void) data_end; + + char *key = (char *) region_alloc(&fiber()->gc, bsize); + if (key == NULL) { + diag_set(OutOfMemory, bsize, "region", + "tuple_extract_key_raw_sequential"); + return NULL; + } + char *key_buf = mp_encode_array(key, key_def->part_count); + memcpy(key_buf, field_start, field_end - field_start); + + if (key_size != NULL) + *key_size = bsize; + return key; +} + +/** + * Optimized version of tuple_extract_key() for sequential key defs + * @copydoc tuple_extract_key() + */ +static inline char * +tuple_extract_key_sequential(const struct tuple *tuple, + const struct key_def *key_def, + uint32_t *key_size) +{ + assert(key_def_is_sequential(key_def)); + const char *data = tuple_data(tuple); + return tuple_extract_key_sequential_raw(data, NULL, key_def, key_size); +} + +/** + * General-purpose implementation of tuple_extract_key() + * @copydoc tuple_extract_key() + */ +static char * +tuple_extract_key_slowpath(const struct tuple *tuple, + const struct key_def *key_def, uint32_t *key_size) +{ + const char *data = tuple_data(tuple); + uint32_t part_count = key_def->part_count; + uint32_t bsize = mp_sizeof_array(part_count); + const struct tuple_format *format = tuple_format(tuple); + const uint32_t *field_map = tuple_field_map(tuple); + + /* Calculate the key size. */ + for (uint32_t i = 0; i < part_count; ++i) { + const char *field = + tuple_field_raw(format, data, field_map, + key_def->parts[i].fieldno); + const char *end = field; + /* + * Skip sequential part in order to minimize + * tuple_field_raw() calls. + */ + for (; i < key_def->part_count - 1; i++) { + if (key_def->parts[i].fieldno + 1 != + key_def->parts[i + 1].fieldno) { + /* End of sequential part */ + break; + } + mp_next(&end); + } + mp_next(&end); + bsize += end - field; + } + + char *key = (char *) region_alloc(&fiber()->gc, bsize); + if (key == NULL) { + diag_set(OutOfMemory, bsize, "region", "tuple_extract_key"); + return NULL; + } + char *key_buf = mp_encode_array(key, part_count); + for (uint32_t i = 0; i < part_count; ++i) { + const char *field = + tuple_field_raw(format, data, field_map, + key_def->parts[i].fieldno); + const char *end = field; + /* + * Skip sequential part in order to minimize + * tuple_field_raw() calls + */ + for (; i < key_def->part_count - 1; i++) { + if (key_def->parts[i].fieldno + 1 != + key_def->parts[i + 1].fieldno) { + /* End of sequential part */ + break; + } + mp_next(&end); + } + mp_next(&end); + bsize = end - field; + memcpy(key_buf, field, bsize); + key_buf += bsize; + } + if (key_size != NULL) + *key_size = key_buf - key; + return key; +} + +/** + * General-purpose version of tuple_extract_key_raw() + * @copydoc tuple_extract_key_raw() + */ +static char * +tuple_extract_key_slowpath_raw(const char *data, const char *data_end, + const struct key_def *key_def, + uint32_t *key_size) +{ + /* allocate buffer with maximal possible size */ + char *key = (char *) region_alloc(&fiber()->gc, data_end - data); + if (key == NULL) { + diag_set(OutOfMemory, data_end - data, "region", + "tuple_extract_key_raw"); + return NULL; + } + char *key_buf = mp_encode_array(key, key_def->part_count); + const char *field0 = data; + mp_decode_array(&field0); + const char *field0_end = field0; + mp_next(&field0_end); + const char *field = field0; + const char *field_end = field0_end; + uint32_t current_fieldno = 0; + for (uint32_t i = 0; i < key_def->part_count; i++) { + uint32_t fieldno = key_def->parts[i].fieldno; + for (; i < key_def->part_count - 1; i++) { + if (key_def->parts[i].fieldno + 1 != + key_def->parts[i + 1].fieldno) + break; + } + if (fieldno < current_fieldno) { + /* Rewind. */ + field = field0; + field_end = field0_end; + current_fieldno = 0; + } + + while (current_fieldno < fieldno) { + /* search first field of key in tuple raw data */ + field = field_end; + mp_next(&field_end); + current_fieldno++; + } + + while (current_fieldno < key_def->parts[i].fieldno) { + /* search the last field in subsequence */ + mp_next(&field_end); + current_fieldno++; + } + memcpy(key_buf, field, field_end - field); + key_buf += field_end - field; + assert(key_buf - key <= data_end - data); + } + if (key_size != NULL) + *key_size = (uint32_t)(key_buf - key); + return key; +} + +/** + * Initialize tuple_extract_key() and tuple_extract_key_raw() + */ +void +tuple_extract_key_set(struct key_def *key_def) +{ + if (key_def_is_sequential(key_def)) { + key_def->tuple_extract_key = tuple_extract_key_sequential; + key_def->tuple_extract_key_raw = tuple_extract_key_sequential_raw; + } else { + key_def->tuple_extract_key = tuple_extract_key_slowpath; + key_def->tuple_extract_key_raw = tuple_extract_key_slowpath_raw; + } +} diff --git a/src/box/tuple_extract_key.h b/src/box/tuple_extract_key.h new file mode 100644 index 0000000000..8a34659576 --- /dev/null +++ b/src/box/tuple_extract_key.h @@ -0,0 +1,50 @@ +#ifndef TARANTOOL_BOX_TUPLE_EXTRACT_KEY_H_INCLUDED +#define TARANTOOL_BOX_TUPLE_EXTRACT_KEY_H_INCLUDED +/* + * Copyright 2010-2016, Tarantool AUTHORS, please see AUTHORS file. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#if defined(__cplusplus) +extern "C" { +#endif /* defined(__cplusplus) */ + +struct key_def; + +/** + * Initialize key extraction functions in the key_def + * @param key_def key definition + */ +void +tuple_extract_key_set(struct key_def *key_def); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif /* defined(__cplusplus) */ + +#endif /* TARANTOOL_BOX_TUPLE_EXTRACT_KEY_H_INCLUDED */ -- GitLab