diff --git a/src/box/read_view.c b/src/box/read_view.c index c99a1ea34e00b1b4531a63559fccd95b77672138..819863224de0a56d5c38d5a08de42b522666a857 100644 --- a/src/box/read_view.c +++ b/src/box/read_view.c @@ -18,6 +18,7 @@ #include "space.h" #include "space_cache.h" #include "trivia/util.h" +#include "tuple.h" static bool default_space_filter(struct space *space, void *arg) @@ -42,6 +43,7 @@ read_view_opts_create(struct read_view_opts *opts) opts->filter_space = default_space_filter; opts->filter_index = default_index_filter; opts->filter_arg = NULL; + opts->needs_field_names = false; } static void @@ -54,6 +56,7 @@ space_read_view_delete(struct space_read_view *space_rv) index_read_view_delete(index_rv); } } + tuple_format_unref(space_rv->format); TRASH(space_rv); free(space_rv); } @@ -61,6 +64,24 @@ space_read_view_delete(struct space_read_view *space_rv) static struct space_read_view * space_read_view_new(struct space *space, const struct read_view_opts *opts) { + struct tuple_format *format = tuple_format_runtime; + if (opts->needs_field_names) { + /** + * Sic: Even though a tuple dictionary has a reference counter, + * we can't reuse the tuple dictionary used by the space tuple + * format, because it may change when the space is altered, see + * tuple_dictionary_swap. + */ + struct tuple_dictionary *dict = tuple_dictionary_new( + space->def->fields, space->def->field_count); + if (dict == NULL) + return NULL; + format = runtime_tuple_format_new(dict); + tuple_dictionary_unref(dict); + if (format == NULL) + return NULL; + } + struct space_read_view *space_rv; size_t index_map_size = sizeof(*space_rv->index_map) * (space->index_id_max + 1); @@ -76,6 +97,8 @@ space_read_view_new(struct space *space, const struct read_view_opts *opts) space_rv->id = space_id(space); space_rv->group_id = space_group_id(space); + space_rv->format = format; + tuple_format_ref(format); space_rv->index_id_max = space->index_id_max; memset(space_rv->index_map, 0, index_map_size); for (uint32_t i = 0; i <= space->index_id_max; i++) { diff --git a/src/box/read_view.h b/src/box/read_view.h index d6aa859f5fb8897db3d7d46db50de970eea93e3a..ab7f37f54af88fbec176492477dd308301cd9431 100644 --- a/src/box/read_view.h +++ b/src/box/read_view.h @@ -27,6 +27,21 @@ struct space_read_view { uint32_t id; /** Space name. */ char *name; + /** + * Runtime tuple format needed to access tuple field names by name. + * Referenced (ref counter incremented). + * + * A new format is created only if read_view_opts::needs_field_names + * is set, otherwise runtime_tuple_format is used. + * + * We can't just use the space tuple format as is because it allocates + * tuples from the space engine arena, which is single-threaded, while + * a read view may be used from threads other than tx. Good news is + * runtime tuple formats are reusable so if we create more than one + * read view of the same space, we will use just one tuple format for + * them all. + */ + struct tuple_format *format; /** Replication group id. See space_opts::group_id. */ uint32_t group_id; /** @@ -81,6 +96,13 @@ struct read_view_opts { * Argument passed to filter functions. */ void *filter_arg; + /** + * If this flag is set, a new runtime tuple format will be created for + * each read view space to support accessing tuple fields by name, + * otherwise the preallocated name-less runtime tuple format will be + * used instead. + */ + bool needs_field_names; }; /** Sets read view options to default values. */