[Tarantool-patches] [PATCH 2/2] box: use tuple_field_raw_by_part where possible
Serge Petrenko
sergepetrenko at tarantool.org
Sat Nov 14 20:28:23 MSK 2020
tuple_field_raw_by_part allows to use part's offset slot cache to bypass
tuple field lookup in a JSON tree, which is involved even for plain
tuples.
Since both tuple_field_raw_by_part and tuple_field_raw are basically
aliases to tuple_field_raw_by_path, prefer the former to the latter,
since it takes advantage over key part's offset slot cache.
Also remove has_json_paths template argument for functions where it
was used to decide between tuple_field_raw and tuple_field_raw_by_part.
This patch was tested by snapshot recovery part involving secondary
index building for a 1.5G snapshot with
one space and one secondary index over 4 integer and one string field.
Comparison table is below:
Version | time(seconds) | Change relative to 1.10
---------------|----------------|------------------------
1.10 | 2:24 | -/-
2.x(unpatched) | 3:03 | + 27%
2.x (patched) | 2:44 | + 14%
Numbers below show cumulative time spent in tuple_compare_slowpath,
for 1.10 / 2.x(unpatched) / 2.x(patched) for 15, 19 and 17 second
profiles respectively: 13.9 / 17.8 / 15.7.
tuple_field_raw_by_path wasn't measured, since it's inlined, but all its
uses come from tuple_compare_slowpath.
Closes #4774
---
src/box/tuple_compare.cc | 37 +++++++++---------------------------
src/box/tuple_extract_key.cc | 10 ++--------
src/box/tuple_hash.cc | 35 +++++++++-------------------------
3 files changed, 20 insertions(+), 62 deletions(-)
diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc
index 0946d77f8..cbb3a850d 100644
--- a/src/box/tuple_compare.cc
+++ b/src/box/tuple_compare.cc
@@ -589,18 +589,13 @@ tuple_compare_slowpath(struct tuple *tuple_a, hint_t tuple_a_hint,
field_b = tuple_field_raw_by_part(format_b, tuple_b_raw,
field_map_b, part,
(int)tuple_b_hint);
- } else if (has_json_paths) {
+ } else {
field_a = tuple_field_raw_by_part(format_a, tuple_a_raw,
field_map_a, part,
MULTIKEY_NONE);
field_b = tuple_field_raw_by_part(format_b, tuple_b_raw,
field_map_b, part,
MULTIKEY_NONE);
- } else {
- field_a = tuple_field_raw(format_a, tuple_a_raw,
- field_map_a, part->fieldno);
- field_b = tuple_field_raw(format_b, tuple_b_raw,
- field_map_b, part->fieldno);
}
assert(has_optional_parts ||
(field_a != NULL && field_b != NULL));
@@ -655,18 +650,13 @@ tuple_compare_slowpath(struct tuple *tuple_a, hint_t tuple_a_hint,
field_b = tuple_field_raw_by_part(format_b, tuple_b_raw,
field_map_b, part,
(int)tuple_b_hint);
- } else if (has_json_paths) {
+ } else {
field_a = tuple_field_raw_by_part(format_a, tuple_a_raw,
field_map_a, part,
MULTIKEY_NONE);
field_b = tuple_field_raw_by_part(format_b, tuple_b_raw,
field_map_b, part,
MULTIKEY_NONE);
- } else {
- field_a = tuple_field_raw(format_a, tuple_a_raw,
- field_map_a, part->fieldno);
- field_b = tuple_field_raw(format_b, tuple_b_raw,
- field_map_b, part->fieldno);
}
/*
* Extended parts are primary, and they can not
@@ -681,14 +671,12 @@ tuple_compare_slowpath(struct tuple *tuple_a, hint_t tuple_a_hint,
return 0;
}
-template<bool is_nullable, bool has_optional_parts, bool has_json_paths,
- bool is_multikey>
+template<bool is_nullable, bool has_optional_parts, bool is_multikey>
static inline int
tuple_compare_with_key_slowpath(struct tuple *tuple, hint_t tuple_hint,
const char *key, uint32_t part_count,
hint_t key_hint, struct key_def *key_def)
{
- assert(has_json_paths == key_def->has_json_paths);
assert(!has_optional_parts || is_nullable);
assert(is_nullable == key_def->is_nullable);
assert(has_optional_parts == key_def->has_optional_parts);
@@ -711,13 +699,10 @@ tuple_compare_with_key_slowpath(struct tuple *tuple, hint_t tuple_hint,
field = tuple_field_raw_by_part(format, tuple_raw,
field_map, part,
(int)tuple_hint);
- } else if (has_json_paths) {
+ } else {
field = tuple_field_raw_by_part(format, tuple_raw,
field_map, part,
MULTIKEY_NONE);
- } else {
- field = tuple_field_raw(format, tuple_raw, field_map,
- part->fieldno);
}
if (! is_nullable) {
return tuple_compare_field(field, key, part->type,
@@ -746,13 +731,10 @@ tuple_compare_with_key_slowpath(struct tuple *tuple, hint_t tuple_hint,
field = tuple_field_raw_by_part(format, tuple_raw,
field_map, part,
(int)tuple_hint);
- } else if (has_json_paths) {
+ } else {
field = tuple_field_raw_by_part(format, tuple_raw,
field_map, part,
MULTIKEY_NONE);
- } else {
- field = tuple_field_raw(format, tuple_raw, field_map,
- part->fieldno);
}
if (! is_nullable) {
rc = tuple_compare_field(field, key, part->type,
@@ -1998,8 +1980,7 @@ key_def_set_compare_func_fast(struct key_def *def)
if (cmp_wk == NULL) {
cmp_wk = is_sequential ?
tuple_compare_with_key_sequential<false, false> :
- tuple_compare_with_key_slowpath<false, false,
- false, false>;
+ tuple_compare_with_key_slowpath<false, false, false>;
}
def->tuple_compare = cmp;
@@ -2020,7 +2001,7 @@ key_def_set_compare_func_plain(struct key_def *def)
def->tuple_compare = tuple_compare_slowpath
<is_nullable, has_optional_parts, false, false>;
def->tuple_compare_with_key = tuple_compare_with_key_slowpath
- <is_nullable, has_optional_parts, false, false>;
+ <is_nullable, has_optional_parts, false>;
}
}
@@ -2033,12 +2014,12 @@ key_def_set_compare_func_json(struct key_def *def)
def->tuple_compare = tuple_compare_slowpath
<is_nullable, has_optional_parts, true, true>;
def->tuple_compare_with_key = tuple_compare_with_key_slowpath
- <is_nullable, has_optional_parts, true, true>;
+ <is_nullable, has_optional_parts, true>;
} else {
def->tuple_compare = tuple_compare_slowpath
<is_nullable, has_optional_parts, true, false>;
def->tuple_compare_with_key = tuple_compare_with_key_slowpath
- <is_nullable, has_optional_parts, true, false>;
+ <is_nullable, has_optional_parts, false>;
}
}
diff --git a/src/box/tuple_extract_key.cc b/src/box/tuple_extract_key.cc
index c1ad3929e..6f347ac16 100644
--- a/src/box/tuple_extract_key.cc
+++ b/src/box/tuple_extract_key.cc
@@ -132,10 +132,7 @@ tuple_extract_key_slowpath(struct tuple *tuple, struct key_def *key_def,
/* Calculate the key size. */
for (uint32_t i = 0; i < part_count; ++i) {
const char *field;
- if (!has_json_paths) {
- field = tuple_field_raw(format, data, field_map,
- key_def->parts[i].fieldno);
- } else if (!is_multikey) {
+ if (!is_multikey) {
field = tuple_field_raw_by_part(format, data, field_map,
&key_def->parts[i],
MULTIKEY_NONE);
@@ -184,10 +181,7 @@ tuple_extract_key_slowpath(struct tuple *tuple, struct key_def *key_def,
char *key_buf = mp_encode_array(key, part_count);
for (uint32_t i = 0; i < part_count; ++i) {
const char *field;
- if (!has_json_paths) {
- field = tuple_field_raw(format, data, field_map,
- key_def->parts[i].fieldno);
- } else if (!is_multikey) {
+ if (!is_multikey) {
field = tuple_field_raw_by_part(format, data, field_map,
&key_def->parts[i],
MULTIKEY_NONE);
diff --git a/src/box/tuple_hash.cc b/src/box/tuple_hash.cc
index 39f89a659..43e37af87 100644
--- a/src/box/tuple_hash.cc
+++ b/src/box/tuple_hash.cc
@@ -217,7 +217,7 @@ static const hasher_signature hash_arr[] = {
#undef HASHER
-template <bool has_optional_parts, bool has_json_paths>
+template <bool has_optional_parts>
uint32_t
tuple_hash_slowpath(struct tuple *tuple, struct key_def *key_def);
@@ -261,15 +261,9 @@ key_def_set_hash_func(struct key_def *key_def) {
slowpath:
if (key_def->has_optional_parts) {
- if (key_def->has_json_paths)
- key_def->tuple_hash = tuple_hash_slowpath<true, true>;
- else
- key_def->tuple_hash = tuple_hash_slowpath<true, false>;
+ key_def->tuple_hash = tuple_hash_slowpath<true>;
} else {
- if (key_def->has_json_paths)
- key_def->tuple_hash = tuple_hash_slowpath<false, true>;
- else
- key_def->tuple_hash = tuple_hash_slowpath<false, false>;
+ key_def->tuple_hash = tuple_hash_slowpath<false>;
}
key_def->key_hash = key_hash_slowpath;
}
@@ -358,11 +352,10 @@ tuple_hash_key_part(uint32_t *ph1, uint32_t *pcarry, struct tuple *tuple,
return tuple_hash_field(ph1, pcarry, &field, part->coll);
}
-template <bool has_optional_parts, bool has_json_paths>
+template <bool has_optional_parts>
uint32_t
tuple_hash_slowpath(struct tuple *tuple, struct key_def *key_def)
{
- assert(has_json_paths == key_def->has_json_paths);
assert(has_optional_parts == key_def->has_optional_parts);
assert(!key_def->is_multikey);
assert(!key_def->for_func_index);
@@ -374,13 +367,8 @@ tuple_hash_slowpath(struct tuple *tuple, struct key_def *key_def)
const char *tuple_raw = tuple_data(tuple);
const uint32_t *field_map = tuple_field_map(tuple);
const char *field;
- if (has_json_paths) {
- field = tuple_field_raw_by_part(format, tuple_raw, field_map,
- key_def->parts, MULTIKEY_NONE);
- } else {
- field = tuple_field_raw(format, tuple_raw, field_map,
- prev_fieldno);
- }
+ field = tuple_field_raw_by_part(format, tuple_raw, field_map,
+ key_def->parts, MULTIKEY_NONE);
const char *end = (char *)tuple + tuple_size(tuple);
if (has_optional_parts && field == NULL) {
total_size += tuple_hash_null(&h, &carry);
@@ -395,14 +383,9 @@ tuple_hash_slowpath(struct tuple *tuple, struct key_def *key_def)
*/
if (prev_fieldno + 1 != key_def->parts[part_id].fieldno) {
struct key_part *part = &key_def->parts[part_id];
- if (has_json_paths) {
- field = tuple_field_raw_by_part(format, tuple_raw,
- field_map, part,
- MULTIKEY_NONE);
- } else {
- field = tuple_field_raw(format, tuple_raw, field_map,
- part->fieldno);
- }
+ field = tuple_field_raw_by_part(format, tuple_raw,
+ field_map, part,
+ MULTIKEY_NONE);
}
if (has_optional_parts && (field == NULL || field >= end)) {
total_size += tuple_hash_null(&h, &carry);
--
2.24.3 (Apple Git-128)
More information about the Tarantool-patches
mailing list