From bfb5a7ca14b7f3c29c4b4e2d251d8b3d6165c2cb Mon Sep 17 00:00:00 2001 From: Konstantin Osipov <kostja@tarantool.org> Date: Tue, 5 Feb 2019 17:04:34 +0300 Subject: [PATCH] Move tuple_field_* getters from tuple_format.h to tuple.h. Initially tuple_field_* getters were placed in tuple_format.h to avoid including tuple_format.h in tuple.h. Now we include tuple_format.h in tuple.h anyway, so move the code where it belongs. Besides, there were a bunch of new getters added to tuple.h since then, so the code has rotten a bit. This is a preparation for an overhaul of tuple_field_* getters naming. --- src/box/tuple.c | 346 ++++++++++++++++++++++++++++++----------- src/box/tuple.h | 144 +++++++++++++++++ src/box/tuple_format.c | 157 ------------------- src/box/tuple_format.h | 144 ----------------- 4 files changed, 402 insertions(+), 389 deletions(-) diff --git a/src/box/tuple.c b/src/box/tuple.c index 9cdb464743..0770db66bb 100644 --- a/src/box/tuple.c +++ b/src/box/tuple.c @@ -48,26 +48,6 @@ enum { OBJSIZE_MIN = 16, }; -/** - * Container for big reference counters. Contains array of big - * reference counters, size of this array and number of non-zero - * big reference counters. When reference counter of tuple becomes - * more than 32767, field refs of this tuple becomes index of big - * reference counter in big reference counter array and field - * is_bigref is set true. The moment big reference becomes equal - * 32767 it is set to 0, refs of the tuple becomes 32767 and - * is_bigref becomes false. Big reference counter can be equal to - * 0 or be more than 32767. - */ -static struct bigref_list { - /** Free-list of big reference counters. */ - uint32_t *refs; - /** Capacity of the array. */ - uint16_t capacity; - /** Index of first free element. */ - uint16_t vacant_index; -} bigref_list; - static const double ALLOC_FACTOR = 1.05; /** @@ -156,13 +136,6 @@ tuple_validate_raw(struct tuple_format *format, const char *tuple) return 0; } -/** Initialize big references container. */ -static inline void -bigref_list_create(void) -{ - memset(&bigref_list, 0, sizeof(bigref_list)); -} - /** * Incremented on every snapshot and is used to distinguish tuples * which were created after start of a snapshot (these tuples can @@ -200,67 +173,7 @@ tuple_next(struct tuple_iterator *it) return NULL; } -int -tuple_init(field_name_hash_f hash) -{ - if (tuple_format_init() != 0) - return -1; - - field_name_hash = hash; - /* - * Create a format for runtime tuples - */ - tuple_format_runtime = tuple_format_new(&tuple_format_runtime_vtab, NULL, - NULL, 0, NULL, 0, 0, NULL, false, - false); - if (tuple_format_runtime == NULL) - return -1; - - /* Make sure this one stays around. */ - tuple_format_ref(tuple_format_runtime); - - small_alloc_create(&runtime_alloc, &cord()->slabc, OBJSIZE_MIN, - ALLOC_FACTOR); - - mempool_create(&tuple_iterator_pool, &cord()->slabc, - sizeof(struct tuple_iterator)); - - box_tuple_last = NULL; - - bigref_list_create(); - - if (coll_id_cache_init() != 0) - return -1; - - return 0; -} - -void -tuple_arena_create(struct slab_arena *arena, struct quota *quota, - uint64_t arena_max_size, uint32_t slab_size, - const char *arena_name) -{ - /* - * Ensure that quota is a multiple of slab_size, to - * have accurate value of quota_used_ratio. - */ - size_t prealloc = small_align(arena_max_size, slab_size); - - say_info("mapping %zu bytes for %s tuple arena...", prealloc, - arena_name); - - if (slab_arena_create(arena, quota, prealloc, slab_size, - MAP_PRIVATE) != 0) { - if (errno == ENOMEM) { - panic("failed to preallocate %zu bytes: Cannot "\ - "allocate memory, check option '%s_memory' in box.cfg(..)", prealloc, - arena_name); - } else { - panic_syserror("failed to preallocate %zu bytes for %s"\ - " tuple arena", prealloc, arena_name); - } - } -} +/** {{{ Bigref - allow tuple reference counter to be > 2^16 */ enum { BIGREF_FACTOR = 2, @@ -273,6 +186,33 @@ enum { BIGREF_MAX_CAPACITY = UINT16_MAX >> 1 }; +/** + * Container for big reference counters. Contains array of big + * reference counters, size of this array and number of non-zero + * big reference counters. When reference counter of tuple becomes + * more than 32767, field refs of this tuple becomes index of big + * reference counter in big reference counter array and field + * is_bigref is set true. The moment big reference becomes equal + * 32767 it is set to 0, refs of the tuple becomes 32767 and + * is_bigref becomes false. Big reference counter can be equal to + * 0 or be more than 32767. + */ +static struct bigref_list { + /** Free-list of big reference counters. */ + uint32_t *refs; + /** Capacity of the array. */ + uint16_t capacity; + /** Index of first free element. */ + uint16_t vacant_index; +} bigref_list; + +/** Initialize big references container. */ +static inline void +bigref_list_create(void) +{ + memset(&bigref_list, 0, sizeof(bigref_list)); +} + /** Destroy big references and free memory that was allocated. */ static inline void bigref_list_destroy(void) @@ -348,6 +288,70 @@ tuple_unref_slow(struct tuple *tuple) } } +/* }}} Bigref */ + +int +tuple_init(field_name_hash_f hash) +{ + if (tuple_format_init() != 0) + return -1; + + field_name_hash = hash; + /* + * Create a format for runtime tuples + */ + tuple_format_runtime = tuple_format_new(&tuple_format_runtime_vtab, NULL, + NULL, 0, NULL, 0, 0, NULL, false, + false); + if (tuple_format_runtime == NULL) + return -1; + + /* Make sure this one stays around. */ + tuple_format_ref(tuple_format_runtime); + + small_alloc_create(&runtime_alloc, &cord()->slabc, OBJSIZE_MIN, + ALLOC_FACTOR); + + mempool_create(&tuple_iterator_pool, &cord()->slabc, + sizeof(struct tuple_iterator)); + + box_tuple_last = NULL; + + bigref_list_create(); + + if (coll_id_cache_init() != 0) + return -1; + + return 0; +} + +void +tuple_arena_create(struct slab_arena *arena, struct quota *quota, + uint64_t arena_max_size, uint32_t slab_size, + const char *arena_name) +{ + /* + * Ensure that quota is a multiple of slab_size, to + * have accurate value of quota_used_ratio. + */ + size_t prealloc = small_align(arena_max_size, slab_size); + + say_info("mapping %zu bytes for %s tuple arena...", prealloc, + arena_name); + + if (slab_arena_create(arena, quota, prealloc, slab_size, + MAP_PRIVATE) != 0) { + if (errno == ENOMEM) { + panic("failed to preallocate %zu bytes: Cannot "\ + "allocate memory, check option '%s_memory' in box.cfg(..)", prealloc, + arena_name); + } else { + panic_syserror("failed to preallocate %zu bytes for %s"\ + " tuple arena", prealloc, arena_name); + } + } +} + void tuple_arena_destroy(struct slab_arena *arena) { @@ -373,6 +377,170 @@ tuple_free(void) bigref_list_destroy(); } +/* {{{ tuple_field_* getters */ + +/** + * Propagate @a field to MessagePack(field)[index]. + * @param[in][out] field Field to propagate. + * @param index 0-based index to propagate to. + * + * @retval 0 Success, the index was found. + * @retval -1 Not found. + */ +static inline int +tuple_field_go_to_index(const char **field, uint64_t index) +{ + enum mp_type type = mp_typeof(**field); + if (type == MP_ARRAY) { + uint32_t count = mp_decode_array(field); + if (index >= count) + return -1; + for (; index > 0; --index) + mp_next(field); + return 0; + } else if (type == MP_MAP) { + index += TUPLE_INDEX_BASE; + uint64_t count = mp_decode_map(field); + for (; count > 0; --count) { + type = mp_typeof(**field); + if (type == MP_UINT) { + uint64_t value = mp_decode_uint(field); + if (value == index) + return 0; + } else if (type == MP_INT) { + int64_t value = mp_decode_int(field); + if (value >= 0 && (uint64_t)value == index) + return 0; + } else { + /* Skip key. */ + mp_next(field); + } + /* Skip value. */ + mp_next(field); + } + } + return -1; +} + +/** + * Propagate @a field to MessagePack(field)[key]. + * @param[in][out] field Field to propagate. + * @param key Key to propagate to. + * @param len Length of @a key. + * + * @retval 0 Success, the index was found. + * @retval -1 Not found. + */ +static inline int +tuple_field_go_to_key(const char **field, const char *key, int len) +{ + enum mp_type type = mp_typeof(**field); + if (type != MP_MAP) + return -1; + uint64_t count = mp_decode_map(field); + for (; count > 0; --count) { + type = mp_typeof(**field); + if (type == MP_STR) { + uint32_t value_len; + const char *value = mp_decode_str(field, &value_len); + if (value_len == (uint)len && + memcmp(value, key, len) == 0) + return 0; + } else { + /* Skip key. */ + mp_next(field); + } + /* Skip value. */ + mp_next(field); + } + return -1; +} + +int +tuple_go_to_path(const char **data, const char *path, uint32_t path_len) +{ + int rc; + struct json_lexer lexer; + struct json_token token; + json_lexer_create(&lexer, path, path_len, TUPLE_INDEX_BASE); + while ((rc = json_lexer_next_token(&lexer, &token)) == 0) { + switch (token.type) { + case JSON_TOKEN_NUM: + rc = tuple_field_go_to_index(data, token.num); + break; + case JSON_TOKEN_STR: + rc = tuple_field_go_to_key(data, token.str, token.len); + break; + default: + assert(token.type == JSON_TOKEN_END); + return 0; + } + if (rc != 0) { + *data = NULL; + return 0; + } + } + return rc != 0 ? -1 : 0; +} + +const char * +tuple_field_raw_by_full_path(struct tuple_format *format, const char *tuple, + const uint32_t *field_map, const char *path, + uint32_t path_len, uint32_t path_hash) +{ + assert(path_len > 0); + uint32_t fieldno; + /* + * It is possible, that a field has a name as + * well-formatted JSON. For example 'a.b.c.d' or '[1]' can + * be field name. To save compatibility at first try to + * use the path as a field name. + */ + if (tuple_fieldno_by_name(format->dict, path, path_len, path_hash, + &fieldno) == 0) + return tuple_field_raw(format, tuple, field_map, fieldno); + struct json_lexer lexer; + struct json_token token; + json_lexer_create(&lexer, path, path_len, TUPLE_INDEX_BASE); + if (json_lexer_next_token(&lexer, &token) != 0) + return NULL; + switch(token.type) { + case JSON_TOKEN_NUM: { + fieldno = token.num; + break; + } + case JSON_TOKEN_STR: { + /* First part of a path is a field name. */ + uint32_t name_hash; + if (path_len == (uint32_t) token.len) { + name_hash = path_hash; + } else { + /* + * If a string is "field....", then its + * precalculated juajit hash can not be + * used. A tuple dictionary hashes only + * name, not path. + */ + name_hash = field_name_hash(token.str, token.len); + } + if (tuple_fieldno_by_name(format->dict, token.str, token.len, + name_hash, &fieldno) != 0) + return NULL; + break; + } + default: + assert(token.type == JSON_TOKEN_END); + return NULL; + } + return tuple_field_raw_by_path(format, tuple, field_map, fieldno, + path + lexer.offset, + path_len - lexer.offset, NULL); +} + +/* }}} tuple_field_* getters */ + +/* {{{ box_tuple_* */ + box_tuple_format_t * box_tuple_format_default(void) { @@ -559,6 +727,8 @@ box_tuple_new(box_tuple_format_t *format, const char *data, const char *end) return tuple_bless(ret); } +/* }}} box_tuple_* */ + int tuple_snprint(char *buf, int size, const struct tuple *tuple) { diff --git a/src/box/tuple.h b/src/box/tuple.h index ac2c4d685a..e803260cbd 100644 --- a/src/box/tuple.h +++ b/src/box/tuple.h @@ -498,6 +498,104 @@ tuple_field_count(const struct tuple *tuple) return mp_decode_array(&data); } +/** + * Retrieve msgpack data by JSON path. + * @param data[in, out] Pointer to msgpack with data. + * If the field cannot be retrieved be the + * specified path @path, it is overwritten + * with NULL. + * @param path The path to process. + * @param path_len The length of the @path. + * @retval 0 On success. + * @retval -1 In case of error in JSON path. + */ +int +tuple_go_to_path(const char **data, const char *path, uint32_t path_len); + +/** + * Get tuple field by field index and relative JSON path. + * @param format Tuple format. + * @param tuple MessagePack tuple's body. + * @param field_map Tuple field map. + * @param path Relative JSON path to field. + * @param path_len Length of @a path. + * @param offset_slot_hint The pointer to a variable that contains + * an offset slot. May be NULL. + * If specified AND value by pointer is + * not TUPLE_OFFSET_SLOT_NIL is used to + * access data in a single operation. + * Else it is initialized with offset_slot + * of format field by path. + */ +static inline const char * +tuple_field_raw_by_path(struct tuple_format *format, const char *tuple, + const uint32_t *field_map, uint32_t fieldno, + const char *path, uint32_t path_len, + int32_t *offset_slot_hint) +{ + int32_t offset_slot; + if (offset_slot_hint != NULL && + *offset_slot_hint != TUPLE_OFFSET_SLOT_NIL) { + offset_slot = *offset_slot_hint; + goto offset_slot_access; + } + if (likely(fieldno < format->index_field_count)) { + struct tuple_field *field; + if (path == NULL && fieldno == 0) { + mp_decode_array(&tuple); + return tuple; + } + field = tuple_format_field_by_path(format, fieldno, path, + path_len); + assert(field != NULL || path != NULL); + if (path != NULL && field == NULL) + goto parse; + offset_slot = field->offset_slot; + if (offset_slot == TUPLE_OFFSET_SLOT_NIL) + goto parse; + if (offset_slot_hint != NULL) + *offset_slot_hint = offset_slot; +offset_slot_access: + /* Indexed field */ + if (field_map[offset_slot] == 0) + return NULL; + tuple += field_map[offset_slot]; + } else { + uint32_t field_count; +parse: + ERROR_INJECT(ERRINJ_TUPLE_FIELD, return NULL); + field_count = mp_decode_array(&tuple); + if (unlikely(fieldno >= field_count)) + return NULL; + for (uint32_t k = 0; k < fieldno; k++) + mp_next(&tuple); + if (path != NULL && + unlikely(tuple_go_to_path(&tuple, path, + path_len) != 0)) + return NULL; + } + return tuple; +} + +/** + * Get a field at the specific position in this MessagePack array. + * Returns a pointer to MessagePack data. + * @param format tuple format + * @param tuple a pointer to MessagePack array + * @param field_map a pointer to the LAST element of field map + * @param field_no the index of field to return + * + * @returns field data if field exists or NULL + * @sa tuple_init_field_map() + */ +static inline const char * +tuple_field_raw(struct tuple_format *format, const char *tuple, + const uint32_t *field_map, uint32_t field_no) +{ + return tuple_field_raw_by_path(format, tuple, field_map, field_no, + NULL, 0, NULL); +} + /** * Get a field at the specific index in this tuple. * @param tuple tuple @@ -513,6 +611,52 @@ tuple_field(const struct tuple *tuple, uint32_t fieldno) tuple_field_map(tuple), fieldno); } +/** + * Get tuple field by full JSON path. + * Unlike tuple_field_raw_by_path this function works with full + * JSON paths, performing root field index resolve on its own. + * When the first JSON path token has JSON_TOKEN_STR type, routine + * uses tuple format dictionary to get field index by field name. + * @param format Tuple format. + * @param tuple MessagePack tuple's body. + * @param field_map Tuple field map. + * @param path Full JSON path to field. + * @param path_len Length of @a path. + * @param path_hash Hash of @a path. + * + * @retval field data if field exists or NULL + */ +const char * +tuple_field_raw_by_full_path(struct tuple_format *format, const char *tuple, + const uint32_t *field_map, const char *path, + uint32_t path_len, uint32_t path_hash); + +/** + * Get a tuple field pointed to by an index part. + * @param format Tuple format. + * @param tuple A pointer to MessagePack array. + * @param field_map A pointer to the LAST element of field map. + * @param part Index part to use. + * @retval Field data if the field exists or NULL. + */ +static inline const char * +tuple_field_raw_by_part(struct tuple_format *format, const char *data, + const uint32_t *field_map, struct key_part *part) +{ + if (unlikely(part->format_epoch != format->epoch)) { + assert(format->epoch != 0); + part->format_epoch = format->epoch; + /* + * Clear the offset slot cache, since it's stale. + * The cache will be reset by the lookup. + */ + part->offset_slot_cache = TUPLE_OFFSET_SLOT_NIL; + } + return tuple_field_raw_by_path(format, data, field_map, part->fieldno, + part->path, part->path_len, + &part->offset_slot_cache); +} + /** * Get a field refereed by index @part in tuple. * @param tuple Tuple to get the field from. diff --git a/src/box/tuple_format.c b/src/box/tuple_format.c index 31c7de211f..b26b367a16 100644 --- a/src/box/tuple_format.c +++ b/src/box/tuple_format.c @@ -1053,160 +1053,3 @@ box_tuple_format_unref(box_tuple_format_t *format) tuple_format_unref(format); } -/** - * Propagate @a field to MessagePack(field)[index]. - * @param[in][out] field Field to propagate. - * @param index 0-based index to propagate to. - * - * @retval 0 Success, the index was found. - * @retval -1 Not found. - */ -static inline int -tuple_field_go_to_index(const char **field, uint64_t index) -{ - enum mp_type type = mp_typeof(**field); - if (type == MP_ARRAY) { - uint32_t count = mp_decode_array(field); - if (index >= count) - return -1; - for (; index > 0; --index) - mp_next(field); - return 0; - } else if (type == MP_MAP) { - index += TUPLE_INDEX_BASE; - uint64_t count = mp_decode_map(field); - for (; count > 0; --count) { - type = mp_typeof(**field); - if (type == MP_UINT) { - uint64_t value = mp_decode_uint(field); - if (value == index) - return 0; - } else if (type == MP_INT) { - int64_t value = mp_decode_int(field); - if (value >= 0 && (uint64_t)value == index) - return 0; - } else { - /* Skip key. */ - mp_next(field); - } - /* Skip value. */ - mp_next(field); - } - } - return -1; -} - -/** - * Propagate @a field to MessagePack(field)[key]. - * @param[in][out] field Field to propagate. - * @param key Key to propagate to. - * @param len Length of @a key. - * - * @retval 0 Success, the index was found. - * @retval -1 Not found. - */ -static inline int -tuple_field_go_to_key(const char **field, const char *key, int len) -{ - enum mp_type type = mp_typeof(**field); - if (type != MP_MAP) - return -1; - uint64_t count = mp_decode_map(field); - for (; count > 0; --count) { - type = mp_typeof(**field); - if (type == MP_STR) { - uint32_t value_len; - const char *value = mp_decode_str(field, &value_len); - if (value_len == (uint)len && - memcmp(value, key, len) == 0) - return 0; - } else { - /* Skip key. */ - mp_next(field); - } - /* Skip value. */ - mp_next(field); - } - return -1; -} - -int -tuple_go_to_path(const char **data, const char *path, uint32_t path_len) -{ - int rc; - struct json_lexer lexer; - struct json_token token; - json_lexer_create(&lexer, path, path_len, TUPLE_INDEX_BASE); - while ((rc = json_lexer_next_token(&lexer, &token)) == 0) { - switch (token.type) { - case JSON_TOKEN_NUM: - rc = tuple_field_go_to_index(data, token.num); - break; - case JSON_TOKEN_STR: - rc = tuple_field_go_to_key(data, token.str, token.len); - break; - default: - assert(token.type == JSON_TOKEN_END); - return 0; - } - if (rc != 0) { - *data = NULL; - return 0; - } - } - return rc != 0 ? -1 : 0; -} - -const char * -tuple_field_raw_by_full_path(struct tuple_format *format, const char *tuple, - const uint32_t *field_map, const char *path, - uint32_t path_len, uint32_t path_hash) -{ - assert(path_len > 0); - uint32_t fieldno; - /* - * It is possible, that a field has a name as - * well-formatted JSON. For example 'a.b.c.d' or '[1]' can - * be field name. To save compatibility at first try to - * use the path as a field name. - */ - if (tuple_fieldno_by_name(format->dict, path, path_len, path_hash, - &fieldno) == 0) - return tuple_field_raw(format, tuple, field_map, fieldno); - struct json_lexer lexer; - struct json_token token; - json_lexer_create(&lexer, path, path_len, TUPLE_INDEX_BASE); - if (json_lexer_next_token(&lexer, &token) != 0) - return NULL; - switch(token.type) { - case JSON_TOKEN_NUM: { - fieldno = token.num; - break; - } - case JSON_TOKEN_STR: { - /* First part of a path is a field name. */ - uint32_t name_hash; - if (path_len == (uint32_t) token.len) { - name_hash = path_hash; - } else { - /* - * If a string is "field....", then its - * precalculated juajit hash can not be - * used. A tuple dictionary hashes only - * name, not path. - */ - name_hash = field_name_hash(token.str, token.len); - } - if (tuple_fieldno_by_name(format->dict, token.str, token.len, - name_hash, &fieldno) != 0) - return NULL; - break; - } - default: - assert(token.type == JSON_TOKEN_END); - return NULL; - } - return tuple_field_raw_by_path(format, tuple, field_map, fieldno, - path + lexer.offset, - path_len - lexer.offset, NULL); -} diff --git a/src/box/tuple_format.h b/src/box/tuple_format.h index 0b5616f39a..f4e142d531 100644 --- a/src/box/tuple_format.h +++ b/src/box/tuple_format.h @@ -406,150 +406,6 @@ int tuple_init_field_map(struct tuple_format *format, uint32_t *field_map, const char *tuple, bool validate); -/** - * Retrieve msgpack data by JSON path. - * @param data[in, out] Pointer to msgpack with data. - * If the field cannot be retrieved be the - * specified path @path, it is overwritten - * with NULL. - * @param path The path to process. - * @param path_len The length of the @path. - * @retval 0 On success. - * @retval -1 In case of error in JSON path. - */ -int -tuple_go_to_path(const char **data, const char *path, uint32_t path_len); - -/** - * Get tuple field by field index and relative JSON path. - * @param format Tuple format. - * @param tuple MessagePack tuple's body. - * @param field_map Tuple field map. - * @param path Relative JSON path to field. - * @param path_len Length of @a path. - * @param offset_slot_hint The pointer to a variable that contains - * an offset slot. May be NULL. - * If specified AND value by pointer is - * not TUPLE_OFFSET_SLOT_NIL is used to - * access data in a single operation. - * Else it is initialized with offset_slot - * of format field by path. - */ -static inline const char * -tuple_field_raw_by_path(struct tuple_format *format, const char *tuple, - const uint32_t *field_map, uint32_t fieldno, - const char *path, uint32_t path_len, - int32_t *offset_slot_hint) -{ - int32_t offset_slot; - if (offset_slot_hint != NULL && - *offset_slot_hint != TUPLE_OFFSET_SLOT_NIL) { - offset_slot = *offset_slot_hint; - goto offset_slot_access; - } - if (likely(fieldno < format->index_field_count)) { - struct tuple_field *field; - if (path == NULL && fieldno == 0) { - mp_decode_array(&tuple); - return tuple; - } - field = tuple_format_field_by_path(format, fieldno, path, - path_len); - assert(field != NULL || path != NULL); - if (path != NULL && field == NULL) - goto parse; - offset_slot = field->offset_slot; - if (offset_slot == TUPLE_OFFSET_SLOT_NIL) - goto parse; - if (offset_slot_hint != NULL) - *offset_slot_hint = offset_slot; -offset_slot_access: - /* Indexed field */ - if (field_map[offset_slot] == 0) - return NULL; - tuple += field_map[offset_slot]; - } else { - uint32_t field_count; -parse: - ERROR_INJECT(ERRINJ_TUPLE_FIELD, return NULL); - field_count = mp_decode_array(&tuple); - if (unlikely(fieldno >= field_count)) - return NULL; - for (uint32_t k = 0; k < fieldno; k++) - mp_next(&tuple); - if (path != NULL && - unlikely(tuple_go_to_path(&tuple, path, - path_len) != 0)) - return NULL; - } - return tuple; -} - -/** - * Get a field at the specific position in this MessagePack array. - * Returns a pointer to MessagePack data. - * @param format tuple format - * @param tuple a pointer to MessagePack array - * @param field_map a pointer to the LAST element of field map - * @param field_no the index of field to return - * - * @returns field data if field exists or NULL - * @sa tuple_init_field_map() - */ -static inline const char * -tuple_field_raw(struct tuple_format *format, const char *tuple, - const uint32_t *field_map, uint32_t field_no) -{ - return tuple_field_raw_by_path(format, tuple, field_map, field_no, - NULL, 0, NULL); -} - -/** - * Get tuple field by full JSON path. - * Unlike tuple_field_raw_by_path this function works with full - * JSON paths, performing root field index resolve on its own. - * When the first JSON path token has JSON_TOKEN_STR type, routine - * uses tuple format dictionary to get field index by field name. - * @param format Tuple format. - * @param tuple MessagePack tuple's body. - * @param field_map Tuple field map. - * @param path Full JSON path to field. - * @param path_len Length of @a path. - * @param path_hash Hash of @a path. - * - * @retval field data if field exists or NULL - */ -const char * -tuple_field_raw_by_full_path(struct tuple_format *format, const char *tuple, - const uint32_t *field_map, const char *path, - uint32_t path_len, uint32_t path_hash); - -/** - * Get a tuple field pointed to by an index part. - * @param format Tuple format. - * @param tuple A pointer to MessagePack array. - * @param field_map A pointer to the LAST element of field map. - * @param part Index part to use. - * @retval Field data if the field exists or NULL. - */ -static inline const char * -tuple_field_raw_by_part(struct tuple_format *format, const char *data, - const uint32_t *field_map, struct key_part *part) -{ - if (unlikely(part->format_epoch != format->epoch)) { - assert(format->epoch != 0); - part->format_epoch = format->epoch; - /* - * Clear the offset slot cache, since it's stale. - * The cache will be reset by the lookup. - */ - part->offset_slot_cache = TUPLE_OFFSET_SLOT_NIL; - } - return tuple_field_raw_by_path(format, data, field_map, part->fieldno, - part->path, part->path_len, - &part->offset_slot_cache); -} - /** * Initialize tuple format subsystem. * @retval 0 on success, -1 otherwise. -- GitLab