[patches] [server 1/2] tuple: move tuple field names hash to a separate shared struct
Vladislav Shpilevoy
v.shpilevoy at tarantool.org
Tue Jan 23 14:38:43 MSK 2018
Struct tuple_dictionary stores hash of field names, defined in
a space format. The structure is refable and are going to be used
to share new field names with old space formats.
Part of #3011
Signed-off-by: Vladislav Shpilevoy <v.shpilevoy at tarantool.org>
---
src/box/CMakeLists.txt | 1 +
src/box/lua/tuple.c | 7 +-
src/box/memtx_space.c | 5 +-
src/box/space_def.c | 12 ++-
src/box/space_def.h | 8 +-
src/box/tuple.c | 5 +-
src/box/tuple_dictionary.c | 217 ++++++++++++++++++++++++++++++++++++++++
src/box/tuple_dictionary.h | 110 ++++++++++++++++++++
src/box/tuple_format.c | 193 +++++------------------------------
src/box/tuple_format.h | 31 +++---
src/box/vinyl.c | 8 +-
src/box/vy_index.c | 5 +-
test/unit/vy_iterators_helper.c | 7 +-
test/unit/vy_mem.c | 3 +-
test/unit/vy_point_lookup.c | 4 +-
15 files changed, 409 insertions(+), 207 deletions(-)
create mode 100644 src/box/tuple_dictionary.c
create mode 100644 src/box/tuple_dictionary.h
diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt
index 494269fb1..bcdae9d99 100644
--- a/src/box/CMakeLists.txt
+++ b/src/box/CMakeLists.txt
@@ -36,6 +36,7 @@ add_library(tuple STATIC
tuple_update.c
tuple_compare.cc
tuple_hash.cc
+ tuple_dictionary.c
key_def.cc
coll_def.c
coll.c
diff --git a/src/box/lua/tuple.c b/src/box/lua/tuple.c
index d5ed7c489..7ca4299a3 100644
--- a/src/box/lua/tuple.c
+++ b/src/box/lua/tuple.c
@@ -287,11 +287,12 @@ lbox_tuple_to_map(struct lua_State *L)
const struct tuple_field *field = &format->fields[0];
const char *pos = tuple_data(tuple);
int field_count = (int)mp_decode_array(&pos);
- int n_named = tuple_format_named_fields(format);
+ int n_named = format->dict->name_count;
lua_createtable(L, field_count, n_named);
for (int i = 0; i < n_named; ++i, ++field) {
/* Access by name. */
- lua_pushstring(L, field->name);
+ const char *name = format->dict->names[i];
+ lua_pushstring(L, name);
luamp_decode(L, luaL_msgpack_default, &pos);
lua_rawset(L, -3);
/*
@@ -299,7 +300,7 @@ lbox_tuple_to_map(struct lua_State *L)
* copy for tables - lua optimizes it and uses
* references.
*/
- lua_pushstring(L, field->name);
+ lua_pushstring(L, name);
lua_rawget(L, -2);
lua_rawseti(L, -2, i + TUPLE_INDEX_BASE);
}
diff --git a/src/box/memtx_space.c b/src/box/memtx_space.c
index 599a68e13..e1968e5c2 100644
--- a/src/box/memtx_space.c
+++ b/src/box/memtx_space.c
@@ -933,8 +933,9 @@ memtx_space_new(struct memtx_engine *memtx,
rlist_foreach_entry(index_def, key_list, link)
keys[key_count++] = index_def->key_def;
- struct tuple_format *format = tuple_format_new(&memtx_tuple_format_vtab,
- keys, key_count, 0, def->fields, def->field_count);
+ struct tuple_format *format =
+ tuple_format_new(&memtx_tuple_format_vtab, keys, key_count, 0,
+ def->fields, def->field_count, def->dict);
if (format == NULL) {
free(memtx_space);
return NULL;
diff --git a/src/box/space_def.c b/src/box/space_def.c
index fdbbc907e..ce5872ffb 100644
--- a/src/box/space_def.c
+++ b/src/box/space_def.c
@@ -42,10 +42,10 @@ const struct opt_def space_opts_reg[] = {
};
/**
- * Size of the space_def, calculated using its name.
+ * Size of the space_def.
* @param name_len Length of the space name.
- * @param field_defs_size Binary size of a field definitions
- * array.
+ * @param field_names_size Size of all names.
+ * @param field_count Space field count.
* @param[out] names_offset Offset from the beginning of a def to
* a field names memory.
* @param[out] fields_offset Offset from the beginning of a def to
@@ -86,6 +86,7 @@ space_def_dup(const struct space_def *src)
name_pos += strlen(name_pos) + 1;
}
}
+ tuple_dictionary_ref(ret->dict);
return ret;
}
@@ -109,6 +110,11 @@ space_def_new(uint32_t id, uint32_t uid, uint32_t exact_field_count,
}
assert(name_len <= BOX_NAME_MAX);
assert(engine_len <= ENGINE_NAME_MAX);
+ def->dict = tuple_dictionary_new(fields, field_count);
+ if (def->dict == NULL) {
+ free(def);
+ return NULL;
+ }
def->id = id;
def->uid = uid;
def->exact_field_count = exact_field_count;
diff --git a/src/box/space_def.h b/src/box/space_def.h
index 2db09cb92..97c7e1380 100644
--- a/src/box/space_def.h
+++ b/src/box/space_def.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
#include "trivia/util.h"
-#include "field_def.h"
+#include "tuple_dictionary.h"
#include "schema_def.h"
#include <stdbool.h>
@@ -77,6 +77,11 @@ struct space_def {
*/
uint32_t exact_field_count;
char engine_name[ENGINE_NAME_MAX + 1];
+ /**
+ * Tuple field names dictionary, shared with a space's
+ * tuple format.
+ */
+ struct tuple_dictionary *dict;
/** Space fields, specified by a user. */
struct field_def *fields;
/** Length of @a fields. */
@@ -92,6 +97,7 @@ struct space_def {
static inline void
space_def_delete(struct space_def *def)
{
+ tuple_dictionary_unref(def->dict);
TRASH(def);
free(def);
}
diff --git a/src/box/tuple.c b/src/box/tuple.c
index 54325af43..b0e661a48 100644
--- a/src/box/tuple.c
+++ b/src/box/tuple.c
@@ -389,9 +389,8 @@ tuple_init(field_name_hash_f hash)
/*
* Create a format for runtime tuples
*/
- RLIST_HEAD(empty_list);
tuple_format_runtime = tuple_format_new(&tuple_format_runtime_vtab,
- NULL, 0, 0, NULL, 0);
+ NULL, 0, 0, NULL, 0, NULL);
if (tuple_format_runtime == NULL)
return -1;
@@ -473,7 +472,7 @@ box_tuple_format_new(struct key_def **keys, uint16_t key_count)
{
box_tuple_format_t *format =
tuple_format_new(&tuple_format_runtime_vtab,
- keys, key_count, 0, NULL, 0);
+ keys, key_count, 0, NULL, 0, NULL);
if (format != NULL)
tuple_format_ref(format);
return format;
diff --git a/src/box/tuple_dictionary.c b/src/box/tuple_dictionary.c
new file mode 100644
index 000000000..a8ea13a51
--- /dev/null
+++ b/src/box/tuple_dictionary.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2010-2016, Tarantool AUTHORS, please see AUTHORS file.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "tuple_dictionary.h"
+#include "error.h"
+#include "diag.h"
+
+field_name_hash_f field_name_hash;
+
+#define mh_name _strnu32
+struct mh_strnu32_key_t {
+ const char *str;
+ size_t len;
+ uint32_t hash;
+};
+#define mh_key_t struct mh_strnu32_key_t *
+struct mh_strnu32_node_t {
+ const char *str;
+ size_t len;
+ uint32_t hash;
+ uint32_t val;
+};
+#define mh_node_t struct mh_strnu32_node_t
+
+#define mh_arg_t void *
+#define mh_hash(a, arg) ((a)->hash)
+#define mh_hash_key(a, arg) mh_hash(a, arg)
+#define mh_cmp(a, b, arg) ((a)->len != (b)->len || \
+ memcmp((a)->str, (b)->str, (a)->len))
+#define mh_cmp_key(a, b, arg) mh_cmp(a, b, arg)
+#define MH_SOURCE 1
+#include "salad/mhash.h" /* Create mh_strnu32_t hash. */
+
+/** Free names hash and its content. */
+static inline void
+tuple_dictionary_delete_hash(struct mh_strnu32_t *hash)
+{
+ while (mh_size(hash)) {
+ mh_int_t i = mh_first(hash);
+ mh_strnu32_del(hash, i, NULL);
+ }
+ mh_strnu32_delete(hash);
+}
+
+/** Free tuple dictionary and its content. */
+static inline void
+tuple_dictionary_delete(struct tuple_dictionary *dict)
+{
+ assert(dict->refs == 0);
+ if (dict->hash != NULL) {
+ tuple_dictionary_delete_hash(dict->hash);
+ free(dict->names);
+ } else {
+ assert(dict->names == NULL);
+ }
+ free(dict);
+}
+
+/**
+ * Set a new name in a dictionary. Check duplicates. Memory must
+ * be reserved already.
+ * @param dict Tuple dictionary.
+ * @param name New name.
+ * @param name_len Length of @a name.
+ * @param fieldno Field number.
+ *
+ * @retval 0 Success.
+ * @retval -1 Duplicate name error.
+ */
+static inline int
+tuple_dictionary_set_name(struct tuple_dictionary *dict, const char *name,
+ uint32_t name_len, uint32_t fieldno)
+{
+ assert(fieldno < dict->name_count);
+ uint32_t name_hash = field_name_hash(name, name_len);
+ struct mh_strnu32_key_t key = {
+ name, name_len, name_hash
+ };
+ mh_int_t rc = mh_strnu32_find(dict->hash, &key, NULL);
+ if (rc != mh_end(dict->hash)) {
+ diag_set(ClientError, ER_SPACE_FIELD_IS_DUPLICATE,
+ name);
+ return -1;
+ }
+ struct mh_strnu32_node_t name_node = {
+ name, name_len, name_hash, fieldno
+ };
+ rc = mh_strnu32_put(dict->hash, &name_node, NULL, NULL);
+ /* Memory was reserved in new(). */
+ assert(rc != mh_end(dict->hash));
+ (void) rc;
+ return 0;
+}
+
+struct tuple_dictionary *
+tuple_dictionary_new(const struct field_def *fields, uint32_t field_count)
+{
+ struct tuple_dictionary *dict =
+ (struct tuple_dictionary *)calloc(1, sizeof(*dict));
+ if (dict == NULL) {
+ diag_set(OutOfMemory, sizeof(*dict), "malloc",
+ "dict");
+ return NULL;
+ }
+ dict->refs = 1;
+ dict->name_count = field_count;
+ if (field_count == 0)
+ return dict;
+ uint32_t names_offset = sizeof(dict->names[0]) * field_count;
+ uint32_t total = names_offset;
+ for (uint32_t i = 0; i < field_count; ++i)
+ total += strlen(fields[i].name) + 1;
+ dict->names = (char **) malloc(total);
+ if (dict->names == NULL) {
+ diag_set(OutOfMemory, total, "malloc", "dict->names");
+ goto err_memory;
+ }
+ dict->hash = mh_strnu32_new();
+ if (dict->hash == NULL) {
+ diag_set(OutOfMemory, sizeof(*dict->hash),
+ "mh_strnu32_new", "dict->hash");
+ goto err_hash;
+ }
+ if (mh_strnu32_reserve(dict->hash, field_count, NULL) != 0) {
+ diag_set(OutOfMemory, field_count *
+ sizeof(struct mh_strnu32_node_t), "mh_strnu32_reserve",
+ "dict->hash");
+ goto err_name;
+ }
+ char *pos = (char *) dict->names + names_offset;
+ for (uint32_t i = 0; i < field_count; ++i) {
+ int len = strlen(fields[i].name);
+ memcpy(pos, fields[i].name, len);
+ pos[len] = 0;
+ dict->names[i] = pos;
+ if (tuple_dictionary_set_name(dict, pos, len, i) != 0)
+ goto err_name;
+ pos += len + 1;
+ }
+ return dict;
+
+err_name:
+ tuple_dictionary_delete_hash(dict->hash);
+err_hash:
+ free(dict->names);
+err_memory:
+ free(dict);
+ return NULL;
+}
+
+void
+tuple_dictionary_swap(struct tuple_dictionary *a, struct tuple_dictionary *b)
+{
+ int a_refs = a->refs;
+ int b_refs = b->refs;
+ struct tuple_dictionary t = *a;
+ *a = *b;
+ *b = t;
+ a->refs = a_refs;
+ b->refs = b_refs;
+}
+
+void
+tuple_dictionary_unref(struct tuple_dictionary *dict)
+{
+ assert(dict->refs > 0);
+ if (--dict->refs == 0)
+ tuple_dictionary_delete(dict);
+}
+
+void
+tuple_dictionary_ref(struct tuple_dictionary *dict)
+{
+ ++dict->refs;
+}
+
+int
+tuple_fieldno_by_name(struct tuple_dictionary *dict, const char *name,
+ uint32_t name_len, uint32_t name_hash, uint32_t *fieldno)
+{
+ struct mh_strnu32_t *hash = dict->hash;
+ if (hash == NULL)
+ return -1;
+ struct mh_strnu32_key_t key = {name, name_len, name_hash};
+ mh_int_t rc = mh_strnu32_find(hash, &key, NULL);
+ if (rc == mh_end(hash))
+ return -1;
+ *fieldno = mh_strnu32_node(hash, rc)->val;
+ return 0;
+}
diff --git a/src/box/tuple_dictionary.h b/src/box/tuple_dictionary.h
new file mode 100644
index 000000000..5f699f5e1
--- /dev/null
+++ b/src/box/tuple_dictionary.h
@@ -0,0 +1,110 @@
+#ifndef TARANTOOL_BOX_TUPLE_DICTIONARY_H_INCLUDED
+#define TARANTOOL_BOX_TUPLE_DICTIONARY_H_INCLUDED
+/*
+ * Copyright 2010-2016, Tarantool AUTHORS, please see AUTHORS file.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "trivia/util.h"
+#include "field_def.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mh_strnu32_t;
+typedef uint32_t (*field_name_hash_f)(const char *str, uint32_t len);
+extern field_name_hash_f field_name_hash;
+
+/**
+ * Shared tuple field names hash. It is referenced by tuple format
+ * and space definition.
+ */
+struct tuple_dictionary {
+ /** Field names hash. Key - name, value - field number. */
+ struct mh_strnu32_t *hash;
+ /**
+ * Array of names. All of them are stored in monolit
+ * memory area.
+ */
+ char **names;
+ /** Length of a names array. */
+ uint32_t name_count;
+ /** Reference counter. */
+ int refs;
+};
+
+/**
+ * Create a new tuple dictionary.
+ * @param fields Array of space fields.
+ * @param field_count Length of @a fields.
+ *
+ * @retval NULL Memory error.
+ * @retval not NULL Tuple dictionary with one ref.
+ */
+struct tuple_dictionary *
+tuple_dictionary_new(const struct field_def *fields, uint32_t field_count);
+
+/**
+ * Swap content of two dictionaries. Reference counters are not
+ * swaped.
+ */
+void
+tuple_dictionary_swap(struct tuple_dictionary *a, struct tuple_dictionary *b);
+
+/**
+ * Decrement reference counter. If a new reference counter value
+ * is 0, then the dictionary is deleted.
+ */
+void
+tuple_dictionary_unref(struct tuple_dictionary *dict);
+
+/** Increment reference counter. */
+void
+tuple_dictionary_ref(struct tuple_dictionary *dict);
+
+/**
+ * Get field number by a name.
+ * @param dict Tuple dictionary.
+ * @param name Name to search.
+ * @param name_len Length of @a name.
+ * @param name_hash Hash of @a name.
+ * @param[out] fieldno Field number, if it is found.
+ *
+ * @retval 0 Field is found.
+ * @retval -1 No such field.
+ */
+int
+tuple_fieldno_by_name(struct tuple_dictionary *dict, const char *name,
+ uint32_t name_len, uint32_t name_hash, uint32_t *fieldno);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /*TARANTOOL_BOX_TUPLE_DICTIONARY_H_INCLUDED*/
diff --git a/src/box/tuple_format.c b/src/box/tuple_format.c
index 4e0b22347..3e2c8bf57 100644
--- a/src/box/tuple_format.c
+++ b/src/box/tuple_format.c
@@ -30,32 +30,6 @@
*/
#include "tuple_format.h"
-field_name_hash_f field_name_hash;
-
-#define mh_name _strnu32
-struct mh_strnu32_key_t {
- const char *str;
- size_t len;
- uint32_t hash;
-};
-#define mh_key_t struct mh_strnu32_key_t *
-struct mh_strnu32_node_t {
- const char *str;
- size_t len;
- uint32_t hash;
- uint32_t val;
-};
-#define mh_node_t struct mh_strnu32_node_t
-
-#define mh_arg_t void *
-#define mh_hash(a, arg) ((a)->hash)
-#define mh_hash_key(a, arg) mh_hash(a, arg)
-#define mh_cmp(a, b, arg) ((a)->len != (b)->len || \
- memcmp((a)->str, (b)->str, (a)->len))
-#define mh_cmp_key(a, b, arg) mh_cmp(a, b, arg)
-#define MH_SOURCE 1
-#include "salad/mhash.h" /* Create mh_strnu32_t hash. */
-
/** Global table of tuple formats */
struct tuple_format **tuple_formats;
static intptr_t recycled_format_ids = FORMAT_ID_NIL;
@@ -63,52 +37,9 @@ static intptr_t recycled_format_ids = FORMAT_ID_NIL;
static uint32_t formats_size = 0, formats_capacity = 0;
static const struct tuple_field tuple_field_default = {
- FIELD_TYPE_ANY, TUPLE_OFFSET_SLOT_NIL, false, NULL, false,
+ FIELD_TYPE_ANY, TUPLE_OFFSET_SLOT_NIL, false, false,
};
-int
-tuple_format_named_fields(const struct tuple_format *format)
-{
- return format->names == NULL ? 0 : mh_size(format->names);
-}
-
-/**
- * Add @a name to a name hash of @a format.
- * @param format Format to add name.
- * @param name Name to add.
- * @param name_len Length of @a name.
- * @param fieldno Field number.
- * @param check_dup True, if need to check for duplicates.
- *
- * @retval -1 Duplicate field error.
- * @retval 0 Success.
- */
-static inline int
-tuple_format_add_name(struct tuple_format *format, const char *name,
- uint32_t name_len, uint32_t fieldno, bool check_dup)
-{
- uint32_t name_hash = field_name_hash(name, name_len);
- struct mh_strnu32_node_t name_node = {
- name, name_len, name_hash, fieldno
- };
- if (check_dup) {
- struct mh_strnu32_key_t key = {
- name, name_len, name_hash
- };
- mh_int_t rc = mh_strnu32_find(format->names, &key, NULL);
- if (rc != mh_end(format->names)) {
- diag_set(ClientError, ER_SPACE_FIELD_IS_DUPLICATE,
- name);
- return -1;
- }
- }
- mh_int_t rc = mh_strnu32_put(format->names, &name_node, NULL, NULL);
- /* Memory was reserved in alloc(). */
- assert(rc != mh_end(format->names));
- (void) rc;
- return 0;
-}
-
/**
* Extract all available type info from keys and field
* definitions.
@@ -122,21 +53,12 @@ tuple_format_create(struct tuple_format *format, struct key_def * const *keys,
format->field_map_size = 0;
return 0;
}
- char *name_pos = (char *)format + sizeof(*format) +
- sizeof(struct tuple_field) * format->field_count;
/* Initialize defined fields */
for (uint32_t i = 0; i < field_count; ++i) {
format->fields[i].is_key_part = false;
format->fields[i].type = fields[i].type;
format->fields[i].offset_slot = TUPLE_OFFSET_SLOT_NIL;
format->fields[i].is_nullable = fields[i].is_nullable;
- format->fields[i].name = name_pos;
- size_t len = strlen(fields[i].name);
- memcpy(name_pos, fields[i].name, len);
- name_pos[len] = 0;
- if (tuple_format_add_name(format, name_pos, len, i, true) != 0)
- return -1;
- name_pos += len + 1;
if (i + 1 > format->min_field_count && !fields[i].is_nullable)
format->min_field_count = i + 1;
}
@@ -178,10 +100,13 @@ tuple_format_create(struct tuple_format *format, struct key_def * const *keys,
} else if (field->type != part->type) {
const char *name;
int fieldno = part->fieldno + TUPLE_INDEX_BASE;
- if (field->name == NULL)
+ if (part->fieldno >= field_count) {
name = tt_sprintf("%d", fieldno);
- else
- name = tt_sprintf("'%s'", field->name);
+ } else {
+ const struct field_def *def =
+ &fields[part->fieldno];
+ name = tt_sprintf("'%s'", def->name);
+ }
int errcode;
if (! field->is_key_part)
errcode = ER_FORMAT_MISMATCH_INDEX_PART;
@@ -267,8 +192,7 @@ tuple_format_deregister(struct tuple_format *format)
static struct tuple_format *
tuple_format_alloc(struct key_def * const *keys, uint16_t key_count,
- const struct field_def *space_fields,
- uint32_t space_field_count)
+ uint32_t space_field_count, struct tuple_dictionary *dict)
{
uint32_t index_field_count = 0;
/* find max max field no */
@@ -284,8 +208,6 @@ tuple_format_alloc(struct key_def * const *keys, uint16_t key_count,
uint32_t field_count = MAX(space_field_count, index_field_count);
uint32_t total = sizeof(struct tuple_format) +
field_count * sizeof(struct tuple_field);
- for (uint32_t i = 0; i < space_field_count; ++i)
- total += strlen(space_fields[i].name) + 1;
struct tuple_format *format = (struct tuple_format *) malloc(total);
if (format == NULL) {
@@ -293,22 +215,16 @@ tuple_format_alloc(struct key_def * const *keys, uint16_t key_count,
"tuple format");
return NULL;
}
- if (space_field_count != 0) {
- format->names = mh_strnu32_new();
- if (format->names == NULL) {
- diag_set(OutOfMemory, sizeof(*format->names),
- "mh_strnu32_new", "format->names");
- goto error_name_hash_new;
- }
- if (mh_strnu32_reserve(format->names, space_field_count,
- NULL) != 0) {
- diag_set(OutOfMemory, space_field_count *
- sizeof(struct mh_strnu32_node_t),
- "mh_strnu32_reserve", "format->names");
- goto error_name_hash_reserve;
+ if (dict == NULL) {
+ assert(space_field_count == 0);
+ format->dict = tuple_dictionary_new(NULL, 0);
+ if (format->dict == NULL) {
+ free(format);
+ return NULL;
}
} else {
- format->names = NULL;
+ format->dict = dict;
+ tuple_dictionary_ref(dict);
}
format->refs = 0;
format->id = FORMAT_ID_NIL;
@@ -317,25 +233,13 @@ tuple_format_alloc(struct key_def * const *keys, uint16_t key_count,
format->exact_field_count = 0;
format->min_field_count = index_field_count;
return format;
-
-error_name_hash_reserve:
- mh_strnu32_delete(format->names);
-error_name_hash_new:
- free(format);
- return NULL;
}
/** Free tuple format resources, doesn't unregister. */
static inline void
tuple_format_destroy(struct tuple_format *format)
{
- if (format->names != NULL) {
- while (mh_size(format->names)) {
- mh_int_t i = mh_first(format->names);
- mh_strnu32_del(format->names, i, NULL);
- }
- mh_strnu32_delete(format->names);
- }
+ tuple_dictionary_unref(format->dict);
}
void
@@ -349,11 +253,13 @@ tuple_format_delete(struct tuple_format *format)
struct tuple_format *
tuple_format_new(struct tuple_format_vtab *vtab, struct key_def * const *keys,
uint16_t key_count, uint16_t extra_size,
- const struct field_def *space_fields, uint32_t space_field_count)
+ const struct field_def *space_fields,
+ uint32_t space_field_count, struct tuple_dictionary *dict)
{
+ assert((dict == NULL && space_field_count == 0) ||
+ (dict != NULL && space_field_count == dict->name_count));
struct tuple_format *format =
- tuple_format_alloc(keys, key_count, space_fields,
- space_field_count);
+ tuple_format_alloc(keys, key_count, space_field_count, dict);
if (format == NULL)
return NULL;
format->vtab = *vtab;
@@ -390,47 +296,17 @@ tuple_format_eq(const struct tuple_format *a, const struct tuple_format *b)
}
struct tuple_format *
-tuple_format_dup(const struct tuple_format *src)
+tuple_format_dup(struct tuple_format *src)
{
uint32_t total = sizeof(struct tuple_format) +
src->field_count * sizeof(struct tuple_field);
- uint32_t name_offset = total;
- uint32_t name_count = 0;
- for (; name_count < src->field_count &&
- src->fields[name_count].name != NULL; ++name_count)
- total += strlen(src->fields[name_count].name) + 1;
-
struct tuple_format *format = (struct tuple_format *) malloc(total);
if (format == NULL) {
diag_set(OutOfMemory, total, "malloc", "tuple format");
return NULL;
}
memcpy(format, src, total);
- if (name_count != 0) {
- format->names = mh_strnu32_new();
- if (format->names == NULL) {
- diag_set(OutOfMemory, sizeof(*format->names),
- "mh_strnu32_new", "format->names");
- goto error_name_hash_new;
- }
- if (mh_strnu32_reserve(format->names, name_count,
- NULL) != 0) {
- diag_set(OutOfMemory, sizeof(struct mh_strnu32_node_t) *
- name_count,
- "mh_strnu32_reserve", "format->names");
- goto error_name_hash_reserve;
- }
- char *name_pos = (char *)format + name_offset;
- for (uint32_t i = 0; i < name_count; ++i) {
- assert(src->fields[i].name != NULL);
- uint32_t len = strlen(src->fields[i].name);
- format->fields[i].name = name_pos;
- tuple_format_add_name(format, name_pos, len, i, false);
- name_pos += len + 1;
- }
- } else {
- assert(format->names == NULL);
- }
+ tuple_dictionary_ref(format->dict);
format->id = FORMAT_ID_NIL;
format->refs = 0;
if (tuple_format_register(format) != 0) {
@@ -439,12 +315,6 @@ tuple_format_dup(const struct tuple_format *src)
return NULL;
}
return format;
-
-error_name_hash_reserve:
- mh_strnu32_delete(format->names);
-error_name_hash_new:
- free(format);
- return NULL;
}
/** @sa declaration for details. */
@@ -531,18 +401,3 @@ box_tuple_format_unref(box_tuple_format_t *format)
{
tuple_format_unref(format);
}
-
-const char *
-tuple_field_raw_by_name(struct tuple_format *format, const char *tuple,
- const uint32_t *field_map, const char *name,
- uint32_t name_len, uint32_t name_hash)
-{
- if (format->names == NULL)
- return NULL;
- struct mh_strnu32_key_t key = {name, name_len, name_hash};
- mh_int_t rc = mh_strnu32_find(format->names, &key, NULL);
- if (rc == mh_end(format->names))
- return NULL;
- uint32_t fieldno = mh_strnu32_node(format->names, rc)->val;
- return tuple_field_raw(format, tuple, field_map, fieldno);
-}
diff --git a/src/box/tuple_format.h b/src/box/tuple_format.h
index bb92e14bb..d33c77ae6 100644
--- a/src/box/tuple_format.h
+++ b/src/box/tuple_format.h
@@ -34,6 +34,7 @@
#include "key_def.h"
#include "field_def.h"
#include "errinj.h"
+#include "tuple_dictionary.h"
#if defined(__cplusplus)
extern "C" {
@@ -95,16 +96,10 @@ struct tuple_field {
int32_t offset_slot;
/** True if this field is used by an index. */
bool is_key_part;
- /** Tuple field name, specified by a user. Can be NULL. */
- char *name;
/** True, if a field can store NULL. */
bool is_nullable;
};
-struct mh_strnu32_t;
-typedef uint32_t (*field_name_hash_f)(const char *str, uint32_t len);
-extern field_name_hash_f field_name_hash;
-
/**
* @brief Tuple format
* Tuple format describes how tuple is stored and information about its fields
@@ -144,17 +139,16 @@ struct tuple_format {
uint32_t min_field_count;
/* Length of 'fields' array. */
uint32_t field_count;
- /** Field names hash. Key - name, value - field number. */
- struct mh_strnu32_t *names;
+ /**
+ * Shared names storage used by all formats of a space.
+ */
+ struct tuple_dictionary *dict;
/* Formats of the fields */
struct tuple_field fields[0];
};
extern struct tuple_format **tuple_formats;
-int
-tuple_format_named_fields(const struct tuple_format *format);
-
static inline uint32_t
tuple_format_id(const struct tuple_format *format)
{
@@ -203,7 +197,7 @@ struct tuple_format *
tuple_format_new(struct tuple_format_vtab *vtab, struct key_def * const *keys,
uint16_t key_count, uint16_t extra_size,
const struct field_def *space_fields,
- uint32_t space_field_count);
+ uint32_t space_field_count, struct tuple_dictionary *dict);
/**
* Check that two tuple formats are identical.
@@ -221,7 +215,7 @@ tuple_format_eq(const struct tuple_format *a, const struct tuple_format *b);
* @retval NULL Memory or format register error.
*/
struct tuple_format *
-tuple_format_dup(const struct tuple_format *src);
+tuple_format_dup(struct tuple_format *src);
/**
* Returns the total size of tuple metadata of this format.
@@ -337,10 +331,17 @@ tuple_field_raw(const struct tuple_format *format, const char *tuple,
* @retval not NULL MessagePack field.
* @retval NULL No field with @a name.
*/
-const char *
+static inline const char *
tuple_field_raw_by_name(struct tuple_format *format, const char *tuple,
const uint32_t *field_map, const char *name,
- uint32_t name_len, uint32_t name_hash);
+ uint32_t name_len, uint32_t name_hash)
+{
+ uint32_t fieldno;
+ if (tuple_fieldno_by_name(format->dict, name, name_len, name_hash,
+ &fieldno) != 0)
+ return NULL;
+ return tuple_field_raw(format, tuple, field_map, fieldno);
+}
#if defined(__cplusplus)
} /* extern "C" */
diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index 3b971b580..59bd6e7d9 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -581,8 +581,9 @@ vinyl_engine_create_space(struct engine *engine, struct space_def *def,
rlist_foreach_entry(index_def, key_list, link)
keys[key_count++] = index_def->key_def;
- struct tuple_format *format = tuple_format_new(&vy_tuple_format_vtab,
- keys, key_count, 0, def->fields, def->field_count);
+ struct tuple_format *format =
+ tuple_format_new(&vy_tuple_format_vtab, keys, key_count, 0,
+ def->fields, def->field_count, def->dict);
if (format == NULL) {
free(space);
return NULL;
@@ -3017,7 +3018,8 @@ vy_join_cb(const struct vy_log_record *record, void *arg)
if (ctx->format != NULL)
tuple_format_unref(ctx->format);
ctx->format = tuple_format_new(&vy_tuple_format_vtab,
- &ctx->key_def, 1, 0, NULL, 0);
+ &ctx->key_def, 1, 0, NULL, 0,
+ NULL);
if (ctx->format == NULL)
return -1;
tuple_format_ref(ctx->format);
diff --git a/src/box/vy_index.c b/src/box/vy_index.c
index c70b2d8ef..93bf71a81 100644
--- a/src/box/vy_index.c
+++ b/src/box/vy_index.c
@@ -86,7 +86,7 @@ vy_index_env_create(struct vy_index_env *env, const char *path,
void *upsert_thresh_arg)
{
env->key_format = tuple_format_new(&vy_tuple_format_vtab,
- NULL, 0, 0, NULL, 0);
+ NULL, 0, 0, NULL, 0, NULL);
if (env->key_format == NULL)
return -1;
tuple_format_ref(env->key_format);
@@ -167,7 +167,8 @@ vy_index_new(struct vy_index_env *index_env, struct vy_cache_env *cache_env,
tuple_format_ref(format);
} else {
index->disk_format = tuple_format_new(&vy_tuple_format_vtab,
- &cmp_def, 1, 0, NULL, 0);
+ &cmp_def, 1, 0, NULL, 0,
+ NULL);
if (index->disk_format == NULL)
goto fail_format;
for (uint32_t i = 0; i < cmp_def->part_count; ++i) {
diff --git a/test/unit/vy_iterators_helper.c b/test/unit/vy_iterators_helper.c
index ee390c499..8e94d7738 100644
--- a/test/unit/vy_iterators_helper.c
+++ b/test/unit/vy_iterators_helper.c
@@ -18,7 +18,7 @@ vy_iterator_C_test_init(size_t cache_size)
tuple_init(NULL);
vy_cache_env_create(&cache_env, cord_slab_cache(), cache_size);
vy_key_format = tuple_format_new(&vy_tuple_format_vtab, NULL, 0, 0,
- NULL, 0);
+ NULL, 0, NULL);
tuple_format_ref(vy_key_format);
size_t mem_size = 64 * 1024 * 1024;
@@ -209,7 +209,7 @@ create_test_mem(struct key_def *def)
struct key_def * const defs[] = { def };
struct tuple_format *format =
tuple_format_new(&vy_tuple_format_vtab, defs, def->part_count,
- 0, NULL, 0);
+ 0, NULL, 0, NULL);
fail_if(format == NULL);
/* Create format with column mask */
@@ -237,7 +237,8 @@ create_test_cache(uint32_t *fields, uint32_t *types,
*def = box_key_def_new(fields, types, key_cnt);
assert(*def != NULL);
vy_cache_create(cache, &cache_env, *def);
- *format = tuple_format_new(&vy_tuple_format_vtab, def, 1, 0, NULL, 0);
+ *format = tuple_format_new(&vy_tuple_format_vtab, def, 1, 0, NULL, 0,
+ NULL);
tuple_format_ref(*format);
}
diff --git a/test/unit/vy_mem.c b/test/unit/vy_mem.c
index 0aa56a3ae..5d1608771 100644
--- a/test/unit/vy_mem.c
+++ b/test/unit/vy_mem.c
@@ -79,7 +79,8 @@ test_iterator_restore_after_insertion()
/* Create format */
struct tuple_format *format = tuple_format_new(&vy_tuple_format_vtab,
- &key_def, 1, 0, NULL, 0);
+ &key_def, 1, 0, NULL, 0,
+ NULL);
assert(format != NULL);
tuple_format_ref(format);
diff --git a/test/unit/vy_point_lookup.c b/test/unit/vy_point_lookup.c
index c14f89f36..05abe0efb 100644
--- a/test/unit/vy_point_lookup.c
+++ b/test/unit/vy_point_lookup.c
@@ -44,9 +44,9 @@ test_basic()
isnt(key_def, NULL, "key_def is not NULL");
vy_cache_create(&cache, &cache_env, key_def);
-
struct tuple_format *format = tuple_format_new(&vy_tuple_format_vtab,
- &key_def, 1, 0, NULL, 0);
+ &key_def, 1, 0, NULL, 0,
+ NULL);
isnt(format, NULL, "tuple_format_new is not NULL");
tuple_format_ref(format);
--
2.11.0 (Apple Git-81)
More information about the Tarantool-patches
mailing list