From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> To: tarantool-patches@freelists.org, Kirill Shcherbatov <kshcherbatov@tarantool.org> Subject: [tarantool-patches] Re: [PATCH v3 2/4] box: introduce slot_cache in key_part Date: Mon, 3 Sep 2018 13:35:04 +0300 [thread overview] Message-ID: <94ec4d86-f611-b1c8-9665-ababdf21481e@tarantool.org> (raw) In-Reply-To: <9be616bdd2190a0ab38aaee981098811f542eeb1.1535354849.git.kshcherbatov@tarantool.org> Hi! Thanks for the fixes! See 11 comments below, a commit on the branch and a diff at the bottom this email. > diff --git a/src/box/alter.cc b/src/box/alter.cc > index a6299a1..a46b886 100644 > --- a/src/box/alter.cc > +++ b/src/box/alter.cc > @@ -1032,6 +1032,42 @@ ModifySpace::~ModifySpace() > space_def_delete(new_def); > } > > +class ModifySpaceFormat: public AlterSpaceOp > +{ > +public: > + ModifySpaceFormat(struct alter_space *alter) : AlterSpaceOp(alter) {} > + virtual void alter(struct alter_space *alter); > +}; 1. Comments. > + > +void > +ModifySpaceFormat:: alter(struct alter_space * alter) 2. Redundant white spaces. (fixed by me) > +{ > + struct tuple_format *format = alter->new_space != NULL ? > + alter->new_space->format : NULL; 3. How new_space can be NULL? alter() called only after new_space is created. (fixed by me) > + if (format == NULL) > + return; > + struct rlist *key_list = &alter->key_list; > + bool is_format_epoch_changed = false; > + struct index_def *index_def; > + rlist_foreach_entry(index_def, key_list, link) { > + struct key_part *part = index_def->key_def->parts; > + struct key_part *parts_end = > + part + index_def->key_def->part_count; > + for (; part < parts_end; part++) { > + struct tuple_field *field = > + &format->fields[part->fieldno]; > + if (field->offset_slot != part->offset_slot) > + is_format_epoch_changed = true; 4. Makes no sense to continue the cycle from this moment. (fixed by me) > + } > + } > + format->epoch = alter->old_space != NULL && > + alter->old_space->format != NULL ? > + alter->old_space->format->epoch : 0; 5. How old_space can be NULL here? It is stored in struct alter right in its constructor. What is more, how old_space->format can be NULL, if a new space format is not NULL? And you do not need is_format_epoch_changed in such a case. (fixed by me) > + if (is_format_epoch_changed) > + format->epoch++; > +} > + > + > /** DropIndex - remove an index from space. */ > > class DropIndex: public AlterSpaceOp > @@ -1316,6 +1352,7 @@ RebuildIndex::prepare(struct alter_space *alter) > /* Get the new index and build it. */ > new_index = space_index(alter->new_space, new_index_def->iid); > assert(new_index != NULL); > + assert(alter->new_space != NULL && alter->old_space != NULL); > space_build_index_xc(alter->old_space, new_index, 6. Garbage diff. (fixed by me) > alter->new_space->format); > } > diff --git a/src/box/key_def.h b/src/box/key_def.h > index aecbe03..a32c34c 100644 > --- a/src/box/key_def.h > +++ b/src/box/key_def.h > @@ -74,6 +74,17 @@ struct key_part { > struct coll *coll; > /** True if a part can store NULLs. */ > bool is_nullable; > + /** > + * Epoch of offset slot cache. Initialized with > + * incremental epoch of format on caching it's field's > + * offset_slot via tuple_field_by_part_raw to speed up > + * access on subsequent calls with same format. > + * Cache is expected to use "the eldest format is most 7. Why 'the eldest'? As I remember, we decided to prefer newer format offset slots. > + * relevant" strategy. > + */ > + uint64_t offset_slot_epoch; > + /** Cache with format's field offset slot. */ > + int32_t offset_slot; > }; > > struct key_def; > diff --git a/src/box/memtx_bitset.c b/src/box/memtx_bitset.c > index a665f1a..9529618 100644 > --- a/src/box/memtx_bitset.c > +++ b/src/box/memtx_bitset.c > @@ -283,8 +283,12 @@ memtx_bitset_index_replace(struct index *base, struct tuple *old_tuple, > } > > if (new_tuple != NULL) { > - const char *field; > - field = tuple_field(new_tuple, base->def->key_def->parts[0].fieldno); > + const char *field = > + tuple_field_by_part_raw(tuple_format(new_tuple), > + tuple_data(new_tuple), > + tuple_field_map(new_tuple), > + (struct key_part *) > + base->def->key_def->parts); 8. Looks like you ignored my comment about why do you case struct key_part * to self. Let me fix it for you where possible. Where it is not possible, please, remove 'const struct key_def' qualifier from the function declaration and do not cast too. Also, as you could see, when a tuple_field function is introduced, it has two versions: raw and not raw. Not raw functions are used exactly for such hunks, when you do not need to get multiple fields. (partially fixed by me) > uint32_t key_len; > const void *key = make_key(field, &key_len); > #ifndef OLD_GOOD_BITSET > diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc > index e53afba..5d7df4d 100644 > --- a/src/box/tuple_compare.cc > +++ b/src/box/tuple_compare.cc > @@ -449,7 +459,7 @@ tuple_common_key_parts(const struct tuple *tuple_a, > return i; > } > > -template<bool is_nullable, bool has_optional_parts> > +template<bool is_nullable, bool has_optional_parts, bool has_json_path> 9. You said, that has_json_path is substituted with is_flat, but looks like you did not. Please, fix all the remarks of the previous review more accurate. > static inline int > tuple_compare_slowpath(const struct tuple *tuple_a, const struct tuple *tuple_b, > const struct key_def *key_def) > diff --git a/src/box/tuple_format.c b/src/box/tuple_format.c > index b385c0d..2d4a85f 100644 > --- a/src/box/tuple_format.c > +++ b/src/box/tuple_format.c > @@ -232,6 +232,11 @@ tuple_format_alloc(struct key_def * const *keys, uint16_t key_count, > format->dict = dict; > tuple_dictionary_ref(dict); > } > + /* > + * Set invalid epoch that should be changed later on > + * attaching to space. > + */ > + format->epoch = 1; 10. Why is this epoch invalid? As I understand, a format can live with it normally but comparators will be slow. > format->refs = 0; > format->id = FORMAT_ID_NIL; > format->field_count = field_count; > diff --git a/src/box/vy_stmt.h b/src/box/vy_stmt.h > index 273d5e8..c4885c0 100644 > --- a/src/box/vy_stmt.h > +++ b/src/box/vy_stmt.h > @@ -719,7 +719,12 @@ static inline bool > vy_tuple_key_contains_null(const struct tuple *tuple, const struct key_def *def) > { > for (uint32_t i = 0; i < def->part_count; ++i) { > - const char *field = tuple_field(tuple, def->parts[i].fieldno); > + const char *field = > + tuple_field_by_part_raw(tuple_format(tuple), > + tuple_data(tuple), > + tuple_field_map(tuple), > + (struct key_part *) > + &def->parts[i]); 11. The same as in the previous review: do not call tuple_format() and other tuple functions multiple times when possible. (fixed by me) > if (field == NULL || mp_typeof(*field) == MP_NIL) > return true; > } > Diff of my fixes here and on the branch: commit 2bb228dafc7b8b1f69e1ed077c01861ea50e6ec9 Author: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Date: Thu Aug 30 16:32:28 2018 -0300 Review fixes diff --git a/src/box/alter.cc b/src/box/alter.cc index 0833635f6..3267b978a 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -1036,18 +1036,19 @@ class ModifySpaceFormat: public AlterSpaceOp { public: ModifySpaceFormat(struct alter_space *alter) : AlterSpaceOp(alter) {} - virtual void alter(struct alter_space *alter); + + virtual void + alter(struct alter_space *alter); }; void -ModifySpaceFormat:: alter(struct alter_space * alter) +ModifySpaceFormat::alter(struct alter_space *alter) { - struct tuple_format *format = alter->new_space != NULL ? - alter->new_space->format : NULL; + struct tuple_format *format = alter->new_space->format; if (format == NULL) return; + format->epoch = alter->old_space->format->epoch; struct rlist *key_list = &alter->key_list; - bool is_format_epoch_changed = false; struct index_def *index_def; rlist_foreach_entry(index_def, key_list, link) { struct key_part *part = index_def->key_def->parts; @@ -1056,15 +1057,12 @@ ModifySpaceFormat:: alter(struct alter_space * alter) for (; part < parts_end; part++) { struct tuple_field *field = &format->fields[part->fieldno]; - if (field->offset_slot != part->offset_slot) - is_format_epoch_changed = true; + if (field->offset_slot != part->offset_slot) { + ++format->epoch; + return; + } } } - format->epoch = alter->old_space != NULL && - alter->old_space->format != NULL ? - alter->old_space->format->epoch : 1; - if (is_format_epoch_changed) - format->epoch++; } @@ -1352,7 +1350,6 @@ RebuildIndex::prepare(struct alter_space *alter) /* Get the new index and build it. */ new_index = space_index(alter->new_space, new_index_def->iid); assert(new_index != NULL); - assert(alter->new_space != NULL && alter->old_space != NULL); space_build_index_xc(alter->old_space, new_index, alter->new_space->format); } diff --git a/src/box/memtx_bitset.c b/src/box/memtx_bitset.c index 9529618d2..cd7362ee1 100644 --- a/src/box/memtx_bitset.c +++ b/src/box/memtx_bitset.c @@ -284,11 +284,8 @@ memtx_bitset_index_replace(struct index *base, struct tuple *old_tuple, if (new_tuple != NULL) { const char *field = - tuple_field_by_part_raw(tuple_format(new_tuple), - tuple_data(new_tuple), - tuple_field_map(new_tuple), - (struct key_part *) - base->def->key_def->parts); + tuple_field_by_part(new_tuple, + base->def->key_def->parts); 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 00aaf79d4..f2aa6c3e5 100644 --- a/src/box/memtx_rtree.c +++ b/src/box/memtx_rtree.c @@ -112,11 +112,8 @@ extract_rectangle(struct rtree_rect *rect, const struct tuple *tuple, struct index_def *index_def) { assert(index_def->key_def->part_count == 1); - const char *elems = - tuple_field_by_part_raw(tuple_format(tuple), tuple_data(tuple), - tuple_field_map(tuple), - (struct key_part *) - index_def->key_def->parts); + const char *elems = tuple_field_by_part(tuple, + index_def->key_def->parts); 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 2e84516de..b638f5086 100644 --- a/src/box/tuple.h +++ b/src/box/tuple.h @@ -43,6 +43,7 @@ extern "C" { struct slab_arena; struct quota; +struct key_part; /** * A format for standalone tuples allocated on runtime arena. @@ -521,6 +522,19 @@ tuple_field(const struct tuple *tuple, uint32_t fieldno) tuple_field_map(tuple), fieldno); } +/** + * Get a field refereed by index @part in tuple. + * @param tuple Tuple to get the field from. + * @param part Index part to use. + * @retval Field data if the field exists or NULL. + */ +static inline const char * +tuple_field_by_part(const struct tuple *tuple, struct key_part *part) +{ + return tuple_field_by_part_raw(tuple_format(tuple), tuple_data(tuple), + tuple_field_map(tuple), part); +} + /** * Get tuple field by its JSON path. * @param tuple Tuple to get field from. diff --git a/src/box/tuple_format.h b/src/box/tuple_format.h index ecbf64c24..9406d5bbc 100644 --- a/src/box/tuple_format.h +++ b/src/box/tuple_format.h @@ -330,12 +330,12 @@ tuple_init_field_map(const struct tuple_format *format, uint32_t *field_map, const char *tuple); /** - * Get a field refereed by multipart index @part in tuple. + * Get a field refereed by index @part in tuple. * @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 Multipart index part to use. - * @retval Field data if field exists or NULL. + * @param part Index part to use. + * @retval Field data if the field exists or NULL. */ const char * tuple_field_by_part_raw(const struct tuple_format *format, const char *data, diff --git a/src/box/tuple_hash.cc b/src/box/tuple_hash.cc index 561ca550a..c9a16ee31 100644 --- a/src/box/tuple_hash.cc +++ b/src/box/tuple_hash.cc @@ -158,11 +158,8 @@ struct TupleHash uint32_t carry = 0; uint32_t total_size = 0; const char *field = - tuple_field_by_part_raw(tuple_format(tuple), - tuple_data(tuple), - tuple_field_map(tuple), - (struct key_part *) - key_def->parts); + tuple_field_by_part(tuple, + (struct key_part *) key_def->parts); TupleFieldHash<TYPE, MORE_TYPES...>:: hash(&field, &h, &carry, &total_size); return PMurHash32_Result(h, carry, total_size); @@ -175,11 +172,8 @@ struct TupleHash<FIELD_TYPE_UNSIGNED> { const struct key_def *key_def) { const char *field = - tuple_field_by_part_raw(tuple_format(tuple), - tuple_data(tuple), - tuple_field_map(tuple), - (struct key_part *) - key_def->parts); + tuple_field_by_part(tuple, + (struct key_part *) key_def->parts); uint64_t val = mp_decode_uint(&field); if (likely(val <= UINT32_MAX)) return val; @@ -322,10 +316,8 @@ tuple_hash_key_part(uint32_t *ph1, uint32_t *pcarry, const struct tuple *tuple, const struct key_part *part) { - const char *field = - tuple_field_by_part_raw(tuple_format(tuple), tuple_data(tuple), - tuple_field_map(tuple), - (struct key_part *)part); + const char *field = tuple_field_by_part(tuple, + (struct key_part *) part); if (field == NULL) return tuple_hash_null(ph1, pcarry); return tuple_hash_field(ph1, pcarry, &field, part->coll); diff --git a/src/box/vy_stmt.h b/src/box/vy_stmt.h index c4885c09b..4f8cbbdd3 100644 --- a/src/box/vy_stmt.h +++ b/src/box/vy_stmt.h @@ -716,15 +716,15 @@ vy_tuple_format_new_with_colmask(struct tuple_format *mem_format); * @retval Does the key contain NULL or not? */ static inline bool -vy_tuple_key_contains_null(const struct tuple *tuple, const struct key_def *def) +vy_tuple_key_contains_null(const struct tuple *tuple, struct key_def *def) { - for (uint32_t i = 0; i < def->part_count; ++i) { + 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_by_part_raw(tuple_format(tuple), - tuple_data(tuple), - tuple_field_map(tuple), - (struct key_part *) - &def->parts[i]); + tuple_field_by_part_raw(format, data, field_map, part); if (field == NULL || mp_typeof(*field) == MP_NIL) return true; }
next prev parent reply other threads:[~2018-09-03 10:35 UTC|newest] Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-08-27 7:37 [tarantool-patches] [PATCH v3 0/4] box: indexes by JSON path Kirill Shcherbatov 2018-08-27 7:37 ` [tarantool-patches] [PATCH v3 1/4] rfc: describe a Tarantool JSON indexes Kirill Shcherbatov 2018-08-27 7:37 ` [tarantool-patches] [PATCH v3 2/4] box: introduce slot_cache in key_part Kirill Shcherbatov 2018-09-03 10:35 ` Vladislav Shpilevoy [this message] 2018-09-06 12:47 ` [tarantool-patches] " Kirill Shcherbatov 2018-09-17 17:08 ` Vladimir Davydov 2018-08-27 7:37 ` [tarantool-patches] [PATCH v3 3/4] box: introduce JSON indexes Kirill Shcherbatov 2018-09-03 10:32 ` [tarantool-patches] " Vladislav Shpilevoy 2018-09-03 10:35 ` Vladislav Shpilevoy 2018-09-06 12:46 ` Kirill Shcherbatov 2018-08-27 7:37 ` [tarantool-patches] [PATCH v3 4/4] box: specify indexes in user-friendly form Kirill Shcherbatov 2018-09-03 10:32 ` [tarantool-patches] " Vladislav Shpilevoy 2018-09-06 12:46 ` Kirill Shcherbatov 2018-09-17 15:50 ` [tarantool-patches] [PATCH v3 0/4] box: indexes by JSON path Vladimir Davydov
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=94ec4d86-f611-b1c8-9665-ababdf21481e@tarantool.org \ --to=v.shpilevoy@tarantool.org \ --cc=kshcherbatov@tarantool.org \ --cc=tarantool-patches@freelists.org \ --subject='[tarantool-patches] Re: [PATCH v3 2/4] box: introduce slot_cache in key_part' \ /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