[PATCH 2/7] Get rid of tuple_field_by_part_multikey

Vladimir Davydov vdavydov.dev at gmail.com
Wed May 8 20:22:34 MSK 2019


Always require multikey_idx to be passed to tuple_field_by_part.
If the key definition isn't multikey, pass -1. Rationale: having
separate functions for multikey and unikey indexes doesn't have
any performance benefits (as all those functions are inline), but
makes the code inconsistent with other functions (e.g. tuple_compare)
which don't have a separate multikey variant. After all, passing -1
when the key definition is known to be unikey doesn't blow the code.
While we are at it, let's also add a few assertions ensuring that
the key definition isn't multikey to functions that don't support
multikey yet.
---
 src/box/memtx_bitset.c       |  6 ++---
 src/box/memtx_rtree.c        |  3 ++-
 src/box/tuple.h              | 29 +++++++-----------------
 src/box/tuple_compare.cc     | 53 +++++++++++++++++++++++---------------------
 src/box/tuple_extract_key.cc | 12 +++++-----
 src/box/tuple_hash.cc        | 17 ++++++++------
 6 files changed, 58 insertions(+), 62 deletions(-)

diff --git a/src/box/memtx_bitset.c b/src/box/memtx_bitset.c
index b6f8f7ac..275e736d 100644
--- a/src/box/memtx_bitset.c
+++ b/src/box/memtx_bitset.c
@@ -276,6 +276,7 @@ memtx_bitset_index_replace(struct index *base, struct tuple *old_tuple,
 	struct memtx_bitset_index *index = (struct memtx_bitset_index *)base;
 
 	assert(!base->def->opts.is_unique);
+	assert(!key_def_is_multikey(base->def->key_def));
 	assert(old_tuple != NULL || new_tuple != NULL);
 	(void) mode;
 
@@ -300,9 +301,8 @@ memtx_bitset_index_replace(struct index *base, struct tuple *old_tuple,
 	}
 
 	if (new_tuple != NULL) {
-		const char *field =
-			tuple_field_by_part(new_tuple,
-					    base->def->key_def->parts);
+		const char *field = tuple_field_by_part(new_tuple,
+					base->def->key_def->parts, -1);
 		uint32_t key_len;
 		const void *key = make_key(field, &key_len);
 #ifndef OLD_GOOD_BITSET
diff --git a/src/box/memtx_rtree.c b/src/box/memtx_rtree.c
index 0a903517..19cb69a1 100644
--- a/src/box/memtx_rtree.c
+++ b/src/box/memtx_rtree.c
@@ -120,8 +120,9 @@ extract_rectangle(struct rtree_rect *rect, struct tuple *tuple,
 		  struct index_def *index_def)
 {
 	assert(index_def->key_def->part_count == 1);
+	assert(!key_def_is_multikey(index_def->key_def));
 	const char *elems = tuple_field_by_part(tuple,
-						index_def->key_def->parts);
+				index_def->key_def->parts, -1);
 	unsigned dimension = index_def->opts.dimension;
 	uint32_t count = mp_decode_array(&elems);
 	return mp_decode_rect(rect, dimension, elems, count, "Field");
diff --git a/src/box/tuple.h b/src/box/tuple.h
index c0d06dbe..2a46f371 100644
--- a/src/box/tuple.h
+++ b/src/box/tuple.h
@@ -653,9 +653,9 @@ tuple_field_raw_by_full_path(struct tuple_format *format, const char *tuple,
  * @retval Field data if the field exists or NULL.
  */
 static inline const char *
-tuple_field_raw_by_part_multikey(struct tuple_format *format, const char *data,
-				 const uint32_t *field_map,
-				 struct key_part *part, int multikey_idx)
+tuple_field_raw_by_part(struct tuple_format *format, const char *data,
+			const uint32_t *field_map,
+			struct key_part *part, int multikey_idx)
 {
 	if (unlikely(part->format_epoch != format->epoch)) {
 		assert(format->epoch != 0);
@@ -672,32 +672,19 @@ tuple_field_raw_by_part_multikey(struct tuple_format *format, const char *data,
 }
 
 /**
- * Get a tuple field pointed to by an index part.
- * @param format Tuple format.
- * @param data 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)
-{
-	return tuple_field_raw_by_part_multikey(format, data, field_map,
-						part, -1);
-}
-
-/**
  * Get a field refereed by index @part in tuple.
  * @param tuple Tuple to get the field from.
  * @param part Index part to use.
+ * @param multikey_idx A multikey index hint.
  * @retval Field data if the field exists or NULL.
  */
 static inline const char *
-tuple_field_by_part(struct tuple *tuple, struct key_part *part)
+tuple_field_by_part(struct tuple *tuple, struct key_part *part,
+		    int multikey_idx)
 {
 	return tuple_field_raw_by_part(tuple_format(tuple), tuple_data(tuple),
-				       tuple_field_map(tuple), part);
+				       tuple_field_map(tuple), part,
+				       multikey_idx);
 }
 
 /**
diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc
index 9a3780c6..0aa032af 100644
--- a/src/box/tuple_compare.cc
+++ b/src/box/tuple_compare.cc
@@ -504,17 +504,17 @@ tuple_compare_slowpath(struct tuple *tuple_a, hint_t tuple_a_hint,
 
 	for (; part < end; part++) {
 		if (is_multikey) {
-			field_a = tuple_field_raw_by_part_multikey(format_a,
-					tuple_a_raw, field_map_a, part,
-					(int)tuple_a_hint);
-			field_b = tuple_field_raw_by_part_multikey(format_b,
-					tuple_b_raw, field_map_b, part,
-					(int)tuple_b_hint);
+			field_a = tuple_field_raw_by_part(format_a, tuple_a_raw,
+							  field_map_a, part,
+							  (int)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) {
 			field_a = tuple_field_raw_by_part(format_a, tuple_a_raw,
-							  field_map_a, part);
+							  field_map_a, part, -1);
 			field_b = tuple_field_raw_by_part(format_b, tuple_b_raw,
-							  field_map_b, part);
+							  field_map_b, part, -1);
 		} else {
 			field_a = tuple_field_raw(format_a, tuple_a_raw,
 						  field_map_a, part->fieldno);
@@ -568,17 +568,17 @@ tuple_compare_slowpath(struct tuple *tuple_a, hint_t tuple_a_hint,
 	end = key_def->parts + key_def->part_count;
 	for (; part < end; ++part) {
 		if (is_multikey) {
-			field_a = tuple_field_raw_by_part_multikey(format_a,
-					tuple_a_raw, field_map_a, part,
-					(int)tuple_a_hint);
-			field_b = tuple_field_raw_by_part_multikey(format_b,
-					tuple_b_raw, field_map_b, part,
-					(int)tuple_b_hint);
+			field_a = tuple_field_raw_by_part(format_a, tuple_a_raw,
+							  field_map_a, part,
+							  (int)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) {
 			field_a = tuple_field_raw_by_part(format_a, tuple_a_raw,
-							  field_map_a, part);
+							  field_map_a, part, -1);
 			field_b = tuple_field_raw_by_part(format_b, tuple_b_raw,
-							  field_map_b, part);
+							  field_map_b, part, -1);
 		} else {
 			field_a = tuple_field_raw(format_a, tuple_a_raw,
 						  field_map_a, part->fieldno);
@@ -625,12 +625,12 @@ tuple_compare_with_key_slowpath(struct tuple *tuple, hint_t tuple_hint,
 	if (likely(part_count == 1)) {
 		const char *field;
 		if (is_multikey) {
-			field = tuple_field_raw_by_part_multikey(format,
-					tuple_raw, field_map, part,
-					(int)tuple_hint);
+			field = tuple_field_raw_by_part(format, tuple_raw,
+							field_map, part,
+							(int)tuple_hint);
 		} else if (has_json_paths) {
 			field = tuple_field_raw_by_part(format, tuple_raw,
-							field_map, part);
+							field_map, part, -1);
 		} else {
 			field = tuple_field_raw(format, tuple_raw, field_map,
 						part->fieldno);
@@ -659,12 +659,12 @@ tuple_compare_with_key_slowpath(struct tuple *tuple, hint_t tuple_hint,
 	for (; part < end; ++part, mp_next(&key)) {
 		const char *field;
 		if (is_multikey) {
-			field = tuple_field_raw_by_part_multikey(format,
-					tuple_raw, field_map, part,
-					(int)tuple_hint);
+			field = tuple_field_raw_by_part(format, tuple_raw,
+							field_map, part,
+							(int)tuple_hint);
 		} else if (has_json_paths) {
 			field = tuple_field_raw_by_part(format, tuple_raw,
-							field_map, part);
+							field_map, part, -1);
 		} else {
 			field = tuple_field_raw(format, tuple_raw, field_map,
 						part->fieldno);
@@ -1553,6 +1553,7 @@ template <enum field_type type, bool is_nullable>
 static hint_t
 key_hint(const char *key, uint32_t part_count, struct key_def *key_def)
 {
+	assert(!key_def_is_multikey(key_def));
 	if (part_count == 0)
 		return HINT_NONE;
 	return field_hint<type, is_nullable>(key, key_def->parts->coll);
@@ -1562,7 +1563,8 @@ template <enum field_type type, bool is_nullable>
 static hint_t
 tuple_hint(struct tuple *tuple, struct key_def *key_def)
 {
-	const char *field = tuple_field_by_part(tuple, key_def->parts);
+	assert(!key_def_is_multikey(key_def));
+	const char *field = tuple_field_by_part(tuple, key_def->parts, -1);
 	if (is_nullable && field == NULL)
 		return hint_nil();
 	return field_hint<type, is_nullable>(field, key_def->parts->coll);
@@ -1584,6 +1586,7 @@ key_hint_multikey(const char *key, uint32_t part_count, struct key_def *key_def)
 	 * do nothing on key hint calculation an it is valid
 	 * because it is never used(unlike tuple hint).
 	 */
+	assert(key_def_is_multikey(key_def));
 	return HINT_NONE;
 }
 
diff --git a/src/box/tuple_extract_key.cc b/src/box/tuple_extract_key.cc
index 7fded038..7868378d 100644
--- a/src/box/tuple_extract_key.cc
+++ b/src/box/tuple_extract_key.cc
@@ -132,7 +132,7 @@ tuple_extract_key_slowpath(struct tuple *tuple, struct key_def *key_def,
 						key_def->parts[i].fieldno);
 		} else {
 			field = tuple_field_raw_by_part(format, data, field_map,
-							&key_def->parts[i]);
+							&key_def->parts[i], -1);
 		}
 		if (has_optional_parts && field == NULL) {
 			bsize += mp_sizeof_nil();
@@ -179,7 +179,7 @@ tuple_extract_key_slowpath(struct tuple *tuple, struct key_def *key_def,
 						key_def->parts[i].fieldno);
 		} else {
 			field = tuple_field_raw_by_part(format, data, field_map,
-							&key_def->parts[i]);
+							&key_def->parts[i], -1);
 		}
 		if (has_optional_parts && field == NULL) {
 			key_buf = mp_encode_nil(key_buf);
@@ -413,13 +413,14 @@ key_def_set_extract_func(struct key_def *key_def)
 bool
 tuple_key_contains_null(struct tuple *tuple, struct key_def *def)
 {
+	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);
+		const char *field = tuple_field_raw_by_part(format, data,
+							    field_map, part, -1);
 		if (field == NULL || mp_typeof(*field) == MP_NIL)
 			return true;
 	}
@@ -429,9 +430,10 @@ tuple_key_contains_null(struct tuple *tuple, struct key_def *def)
 int
 tuple_validate_key_parts(struct key_def *key_def, struct tuple *tuple)
 {
+	assert(!key_def_is_multikey(key_def));
 	for (uint32_t idx = 0; idx < key_def->part_count; idx++) {
 		struct key_part *part = &key_def->parts[idx];
-		const char *field = tuple_field_by_part(tuple, part);
+		const char *field = tuple_field_by_part(tuple, part, -1);
 		if (field == NULL) {
 			if (key_part_is_nullable(part))
 				continue;
diff --git a/src/box/tuple_hash.cc b/src/box/tuple_hash.cc
index 85095eb8..63de2bae 100644
--- a/src/box/tuple_hash.cc
+++ b/src/box/tuple_hash.cc
@@ -155,11 +155,12 @@ struct TupleHash
 {
 	static uint32_t hash(struct tuple *tuple, struct key_def *key_def)
 	{
+		assert(!key_def_is_multikey(key_def));
 		uint32_t h = HASH_SEED;
 		uint32_t carry = 0;
 		uint32_t total_size = 0;
-		const char *field =
-			tuple_field_by_part(tuple, key_def->parts);
+		const char *field = tuple_field_by_part(tuple,
+						key_def->parts, -1);
 		TupleFieldHash<TYPE, MORE_TYPES...>::
 			hash(&field, &h, &carry, &total_size);
 		return PMurHash32_Result(h, carry, total_size);
@@ -170,8 +171,9 @@ template <>
 struct TupleHash<FIELD_TYPE_UNSIGNED> {
 	static uint32_t	hash(struct tuple *tuple, struct key_def *key_def)
 	{
-		const char *field =
-			tuple_field_by_part(tuple, key_def->parts);
+		assert(!key_def_is_multikey(key_def));
+		const char *field = tuple_field_by_part(tuple,
+						key_def->parts, -1);
 		uint64_t val = mp_decode_uint(&field);
 		if (likely(val <= UINT32_MAX))
 			return val;
@@ -348,7 +350,7 @@ uint32_t
 tuple_hash_key_part(uint32_t *ph1, uint32_t *pcarry, struct tuple *tuple,
 		    struct key_part *part)
 {
-	const char *field = tuple_field_by_part(tuple, part);
+	const char *field = tuple_field_by_part(tuple, part, -1);
 	if (field == NULL)
 		return tuple_hash_null(ph1, pcarry);
 	return tuple_hash_field(ph1, pcarry, &field, part->coll);
@@ -360,6 +362,7 @@ 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(key_def));
 	uint32_t h = HASH_SEED;
 	uint32_t carry = 0;
 	uint32_t total_size = 0;
@@ -370,7 +373,7 @@ tuple_hash_slowpath(struct tuple *tuple, struct key_def *key_def)
 	const char *field;
 	if (has_json_paths) {
 		field = tuple_field_raw_by_part(format, tuple_raw, field_map,
-						key_def->parts);
+						key_def->parts, -1);
 	} else {
 		field = tuple_field_raw(format, tuple_raw, field_map,
 					prev_fieldno);
@@ -391,7 +394,7 @@ tuple_hash_slowpath(struct tuple *tuple, struct key_def *key_def)
 			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);
+								field_map, part, -1);
 			} else {
 				field = tuple_field_raw(format, tuple_raw, field_map,
 						    part->fieldno);
-- 
2.11.0




More information about the Tarantool-patches mailing list