Tarantool development patches archive
 help / color / mirror / Atom feed
From: Kirill Shcherbatov <kshcherbatov@tarantool.org>
To: tarantool-patches@freelists.org,
	Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
Subject: [tarantool-patches] Re: [PATCH v2 4/5] box: introduce path_hash and tuple_field tree
Date: Mon, 27 Aug 2018 10:37:08 +0300	[thread overview]
Message-ID: <682425fa-6195-ba1a-8b17-7a16bd47c892@tarantool.org> (raw)
In-Reply-To: <0f6705a6-6f87-5095-665f-b01add43152c@tarantool.org>

> 1. Document structure in future could be defined not only
> via indexes.
-       /* 55 */_(ER_DATA_MISMATCH_INDEX_PART,  "Tuple doesn't math document structure defined as index") \
+       /* 55 */_(ER_DATA_STRUCTURE_MISMATCH,   "Tuple doesn't math document structure") \
> 2. A comment, please.
> 3. Please, add suffix '_cb' which we use for callbacks.
> 4. Why not just 'return key_mp_type_validate(...);'?

/**
 * Watch json_field_tree_routine description.
 * Validate field tree leaf has correct type.
 */
static int
tuple_validate_json_path_data_cb(const struct tuple_field *field, uint32_t idx,
				 const char *tuple, const char *offset,
				 void *ctx)
{
	(void)tuple;
	(void)ctx;
	return key_mp_type_validate(field->type, mp_typeof(*offset),
				    ER_KEY_PART_TYPE, idx, field->is_nullable);
}

/**
 * Watch json_field_tree_routine description.
 * Initialize tuple field map using field tree leaf offset_slot.
 * @param ctx is field_map
 */
 static int
-tuple_init_json_field_map_routine(const struct tuple_field *field, uint32_t idx,
-                                 const char *tuple, const char *offset,
-                                 void *ctx)
+tuple_init_json_field_map_cb(const struct tuple_field *field, uint32_t idx,
+                            const char *tuple, const char *offset, void *ctx)

> 5. The same problem as in the previous version - you double decode
> the field. First inside the tree walker and second here.
> 
> Please, find a way how to avoid it. For help see my comments
> for the walker.
Believe, this is already fixed.

> 6. It should be part of the previous patch together with any
> changes of this file.
Ok

> 7. Static inline and a comment. Also, this function is called
> from places having 'is_flat' template parameter which
> allows to do not check path for NULL on compilation time, but
> you do not use it. Please, make it template too.
Ok, done.

> 8. All the changes between this point and point 7 should be
> part of the previous patch.
Ok.

> 9. First level fieldno should not be encoded in the path. See
> the previous patch for comments.
It is not so, already answered.
> 10. You have exactly the same code in tuple_field_raw_by_path. Please,
> extract either the whole while cycle or this switch into a function.
I've introduce new tuple_field_dig_with_parser routine.
It calls tuple_field_go_to_index and tuple_field_go_to_key using parser,
so I like this name.

> 11. At first, it is a part of the previous patch. At second, it
> run too far. It is time to declare a matrix of functions, maybe
> three dimensional or two, indexes of which are calculated from
> contains_sequential_parts, has_optional_parts and is_flat. See
> field_type1_contains_type2 for an example.
> Same for other functions, having >= 3 template parameters.
Done as a part of previous path.

> 12. Why do you return node_t if you always use only node->val? Why not
> to return val?
It was not nessesary in path that you've revieved but it is important now:
I update leaf field manually and change str pointer to point to format
chunk path memory.

> 13. Why so complicated? Just rename it to new and return the hash
> instead of int.
Simplified.

> 14. Please, put an empty line between the functions.
Done.

> 15. Do not use SQLite style of freeing objects, please.
Done.

> 16. How is it possible that the record exists already? And
> where do you check it here?
Legacy. Dropped.

> 17. Fits in one line.
Done.

> 18. Out of 80. Use sizeof(array[0]). The same below.
-                                       part->num * sizeof(struct tuple_field *));
+                                       part->num * sizeof(array[0]));
Done.

> 19. Size here is not correct. You forgot about * part->num.
-                                       sizeof(struct tuple_field *), "realloc",
-                                       "array");
+                                        part->num * sizeof(array[0]),
+                                        "realloc","array");
Fixed.

> 20. Why are these cases different? If I substitute field->array_size
> (which is true when field->array == NULL) with 0, I will match the
> first branch. It is not?
-                       if (field->array == NULL) {
-                               memset(array, 0, part->num *
-                                       sizeof(struct tuple_field *));
-                       } else {
-                               memset(&array[field->array_size], 0,
-                                      (part->num - field->array_size) *
-                                      sizeof(struct tuple_field *));
-                       }
+                       memset(&array[field->array_size], 0,
+                               (part->num - field->array_size) *
+                               sizeof(array[0]));

> 21. I think, it is rather 'else' branch. Evidently, the condition
> is unreachable, if the field was just created in the code above.
Yep, upgraded.

> 22. If field->map == NULL then sure you do not
> need to check node existence below. Please,
> split those two cases into 2 branches.
Done.

> 23. How can it be NULL?
Fixed.
>> +int
>> +json_field_tree_exec_routine(const struct tuple_field *field, uint32_t idx,
>> +			     const char *tuple, const char *offset,
>> +			     json_field_tree_routine routine, void *routine_ctx)
> 
> 24. I got the idea and I like it - have a walker applicable
> for any puprose. But it calls a function by pointer on a hot
> path - initialization of a tuple field map + validation.
> 
> Lets make it macros. I know, that a macros can not be recursive,
> but we can write a generator of such walker. A macros taking a
> function and generating new json_field_tree_exec_routine.
I've reworked this function a lot. It is complicated enough. Believe, it is not necessary now.

> 25. Talking about one of my first comments (how to iterate over
> the field only once when possible): here, for array, you can
> merely continue iteration and mp_next calling behind field->array_size
> up to count.
> 
> For map the things are more complex. And you can apply the method
> I have described on the previous review. You learn map size and
> on each tuple_field_go_to_key remember maximal number and position
> of the decoded key-value pair. When the iteration is finished,
> you decode the tail starting from the maximal decoded key-value
> pair until the end. In such a case the tail is decoded only once
> always.

> 26. No such parameter 'field_type'. Only 'type'.
Ok, fixed.

> 27. Do not use SQLite style of variables declaration. It
> can be declared and assigned at the same time below.
Ok.

> 28. I do not see a test on this. Please, use gcov to be sure that
> test coverage of all the new code is 100% (except OOM errors).
Added test.

> 29. What about nullability mismatch?Ugum, there was a lot changes in this scenario. I've fixed it now.

> 30. Please. consider this:
> 
>   	field->type = type;
> -	if (json_path_hash_insert(format->path_hash, path, path_len,
> -				  field) != 0)
> -		return -1;
> -
>   	*leaf_field = field;
> -	return 0;
> +	return json_path_hash_insert(format->path_hash, path, path_len, field);
>   }
Ok, applied.
> 31. The aforementioned two hunks are complete mess. Please,
> move the 'is_key_part = true' before them. Then after it at
> first check for 'if (part->path != NULL) { ...; continue; }'.
> Then remove checks for 'path == NULL'.
Done.

> 32. When some indexes has common fields, you count
> and allocate their paths twice.
I've fixed this using hashtable init on format alloc and on-fact leaf initialization.
It is also important to patch hashtable string source and recreate parser with new string.

>> +	for (uint32_t i = 0; i < format->field_count; i++) {
>> +		format->fields[i].array = NULL;
>> +		format->fields[i].array_size = 0;
> 
> 33. Just memset them.
Those fields has other data that I wouldn't copy again.

>> +	if (tuple_format_register(format) != 0)
>> +		goto error;
>>   	return format;
> 
> 34. Consider thisOk, tnx.

> 35. Why here do you check for map != NULL but in all other places
> for array != NULL?
I've introduce childs field that I use in such situations.

> 36. If this is true, then the previous 'if' is unreachable
> (field->offset_slot != TUPLE_OFFSET_SLOT_NIL). Complex field
> can not have an offset slot. So this is 'else' branch, I guess.
Yep.
> 37. After you fix my other comments, this mp_next should
> not be called, if json tree walker was used.
Ugum, done.

> 38. Just inline it.
Ok, done.

> 39. Inversely, it is likely.
Fixed.

> 40. Do here 'return' and reduce indentation level below.
Done.
> 41. As I understand, when a part is JSON and its epoch
> matches the format, it always has a valid slot_cache and you
> do not need to check for '< field_map_size'.
This also related to 42th comment.
Vinyl now has two formats with compatible field map of same size.
But format field count could differ a little. If I not mistaken, disk format
may have less field_count. So smaller format-tuple field map of is initialized
with 0 where appropriate fields don't present.
On the other hand, part cache is looking valid as format epoch are similar.
And it is so, except the fact that such data is not exists for this format type.
Code is appended below.

> Moreover, I do not understand why do you check this slot
> to be not SLOT_NIL and has not zero value in field_map. It
> is 100% valid and you already now can do
> 'return data + field_map[part->slot_cache]', it is not?> 42. The same here. When an offset slot is stored in a field
> from format->path_hash, it always has not zero field_map
> value and not SLOT_NIL offset. So the branch below is actually
> 'else', I guess.

const char *
tuple_field_by_part_raw(const struct tuple_format *format, const char *data,
			const uint32_t *field_map, struct key_part *part)
{
	if (likely(part->path == NULL))
		return tuple_field_raw(format, data, field_map, part->fieldno);

	struct tuple_field *field = NULL;
	int32_t offset_slot = TUPLE_OFFSET_SLOT_NIL;
	if (likely(part->offset_slot_epoch == format->epoch)) {
		offset_slot = part->offset_slot;
	} else if (format->path_hash != NULL &&
		   (field = json_path_hash_get(format->path_hash, part->path,
					       part->path_len,
					       part->path_hash)) != NULL) {
		offset_slot = field->offset_slot;
	} else {
		/*
		 * Legacy tuple having no field map for
		 * JSON index.
		 */
		uint32_t path_hash =
			field_name_hash(part->path, part->path_len);
		const char *raw = NULL;
		if (tuple_field_raw_by_path(format, data, field_map,
					    part->path, part->path_len,
					    path_hash, &raw) != 0)
			raw = NULL;
		return raw;
	}
	assert(offset_slot < 0);
	assert(-offset_slot * sizeof(uint32_t) <= format->field_map_size);
	if (unlikely(field_map[offset_slot] == 0))
		return NULL;
	/* Cache offset_slot if required. */
	if (part->offset_slot_epoch < format->epoch) {
		part->offset_slot = offset_slot;
		part->offset_slot_epoch = format->epoch;
	}
	return data + field_map[offset_slot];
}

> 43. Please, move this function above within its original commit.
Done.

> 44. Actually, it is not used in tree-walker.
                /** Leaf argument for manual tuple construction. */
		void *arg;

> 45. I see, how do you struggle with checking that the
> field has no childs, so I propose to add a member in the
> union 'void *child'. And check it for NULL. It is better
> than check explicitly array or map in places where it
> does not matter.
Done.

> 46. All these changes should be done in the previous commit.
Done.

> 47. Why do you check for child != NULL instead of part->path != NULL?
Fixed.

>> +static void
>> +vy_stmt_msgpack_build(struct tuple_field *field, char *tuple,
>> +		      uint32_t *field_map, char **offset, bool write_data)
> 
> 48. Why you do not use json_field_tree_exec_routine? Because you need
> to do something before and afer decoding the field? Then just implement
> it as a macro as I said and add 2 parameters:
> start_field_cb(field_type, field_size) and end_field_cb(field_type).
> And if a _cb is not defined, its call is not generated.
I have no callbacks now.

> 49. Double ';'.Fixed.
Done.

  reply	other threads:[~2018-08-27  7:37 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-15 12:14 [tarantool-patches] [PATCH v2 0/5] box: indexes by JSON path Kirill Shcherbatov
2018-08-15 12:14 ` [tarantool-patches] [PATCH v2 1/5] rfc: describe a Tarantool JSON indexes Kirill Shcherbatov
2018-08-15 12:15 ` [tarantool-patches] [PATCH v2 2/5] box: introduce slot_cache in key_part Kirill Shcherbatov
2018-08-22  0:27   ` [tarantool-patches] " Vladislav Shpilevoy
2018-08-27  7:37     ` Kirill Shcherbatov
2018-09-03 10:32       ` Vladislav Shpilevoy
2018-08-15 12:15 ` [tarantool-patches] [PATCH v2 3/5] box: introduce path field " Kirill Shcherbatov
2018-08-22  0:26   ` [tarantool-patches] " Vladislav Shpilevoy
2018-08-27  7:37     ` Kirill Shcherbatov
2018-08-15 12:15 ` [tarantool-patches] [PATCH v2 4/5] box: introduce path_hash and tuple_field tree Kirill Shcherbatov
2018-08-22  0:26   ` [tarantool-patches] " Vladislav Shpilevoy
2018-08-27  7:37     ` Kirill Shcherbatov [this message]
2018-08-15 12:15 ` [tarantool-patches] [PATCH v2 5/5] box: specify indexes in user-friendly form Kirill Shcherbatov
2018-08-22  0:26   ` [tarantool-patches] " Vladislav Shpilevoy
2018-08-27  7:37     ` Kirill Shcherbatov
2018-08-22  0:28   ` Vladislav Shpilevoy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=682425fa-6195-ba1a-8b17-7a16bd47c892@tarantool.org \
    --to=kshcherbatov@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --cc=v.shpilevoy@tarantool.org \
    --subject='[tarantool-patches] Re: [PATCH v2 4/5] box: introduce path_hash and tuple_field tree' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox