[PATCH v2 1/5] box: introduce tuple_extra infrastructure
Kirill Shcherbatov
kshcherbatov at tarantool.org
Mon Jun 24 17:27:00 MSK 2019
Introduced a new object tuple_extra: a memory allocation is
associated with given tuple and chunk_id. Extended tuple_format's
vtab with few new methods to manage tuple_extras lifecycle.
Supported tuple_extra for memtx engine: a memory
chunks are allocated with memtx's smalloc allocator and are
registered in tuple_exta_cache: an engine-independent hashtable
<tuple *, chunk_id> -> <tuple_extra *>.
Needed for #1260
---
src/box/memtx_engine.c | 43 +++++++++++++++++++++++++
src/box/tuple.c | 65 ++++++++++++++++++++++++++++++++++++++
src/box/tuple.h | 71 ++++++++++++++++++++++++++++++++++++++++++
src/box/tuple_format.h | 22 +++++++++++++
src/box/vy_stmt.c | 3 ++
5 files changed, 204 insertions(+)
diff --git a/src/box/memtx_engine.c b/src/box/memtx_engine.c
index cd763e547..294f4d73d 100644
--- a/src/box/memtx_engine.c
+++ b/src/box/memtx_engine.c
@@ -1199,9 +1199,52 @@ memtx_tuple_delete(struct tuple_format *format, struct tuple *tuple)
smfree_delayed(&memtx->alloc, memtx_tuple, total);
}
+void
+metmx_tuple_extra_delete(struct tuple_format *format,
+ struct tuple_extra *tuple_extra)
+{
+ struct memtx_engine *memtx = (struct memtx_engine *)format->engine;
+ tuple_extra_cache_unregister(tuple_extra);
+ uint32_t sz = tuple_extra_sz(tuple_extra->data_sz);
+ smfree(&memtx->alloc, tuple_extra, sz);
+}
+
+struct tuple_extra *
+memtx_tuple_extra_new(struct tuple_format *format, struct tuple *tuple,
+ uint32_t chunk_id, uint32_t data_sz)
+{
+ struct memtx_engine *memtx = (struct memtx_engine *)format->engine;
+ uint32_t sz = tuple_extra_sz(data_sz);
+ struct tuple_extra *tuple_extra =
+ (struct tuple_extra *) smalloc(&memtx->alloc, sz);
+ if (tuple == NULL) {
+ diag_set(OutOfMemory, sz, "smalloc", "tuple");
+ return NULL;
+ }
+ tuple_extra->tuple = tuple;
+ tuple_extra->chunk_id = chunk_id;
+ tuple_extra->data_sz = data_sz;
+ if (tuple_extra_cache_register(tuple_extra) != 0) {
+ smfree(&memtx->alloc, tuple_extra, sz);
+ return NULL;
+ }
+ return tuple_extra;
+}
+
+static inline struct tuple_extra *
+memtx_tuple_extra_get(struct tuple_format *format, struct tuple *tuple,
+ uint32_t chunk_id)
+{
+ (void) format;
+ return tuple_extra_cache_find(tuple, chunk_id);
+}
+
struct tuple_format_vtab memtx_tuple_format_vtab = {
memtx_tuple_delete,
memtx_tuple_new,
+ metmx_tuple_extra_delete,
+ memtx_tuple_extra_new,
+ memtx_tuple_extra_get,
};
/**
diff --git a/src/box/tuple.c b/src/box/tuple.c
index a7ef332b2..9512543d6 100644
--- a/src/box/tuple.c
+++ b/src/box/tuple.c
@@ -42,6 +42,21 @@
static struct mempool tuple_iterator_pool;
static struct small_alloc runtime_alloc;
+/** Map: (struct tuple *) => (struct tuple_extra *). */
+#define MH_SOURCE 1
+#define mh_name _tuple_extra
+#define mh_key_t struct tuple *
+#define mh_node_t struct tuple_extra *
+#define mh_arg_t uint32_t
+#define mh_hash(a, arg) ((uintptr_t)(*(a))->tuple)
+#define mh_hash_key(a, arg) ((uintptr_t) a)
+#define mh_cmp(a, b, arg) ((*(a))->tuple != (*(b))->tuple || \
+ (*(a))->chunk_id != (*(b))->chunk_id)
+#define mh_cmp_key(a, b, arg) ((a) != (*(b))->tuple || (arg) != (*(b))->chunk_id)
+#include "salad/mhash.h"
+
+static struct mh_tuple_extra_t *tuple_extra_cache;
+
enum {
/** Lowest allowed slab_alloc_minimal */
OBJSIZE_MIN = 16,
@@ -67,6 +82,9 @@ runtime_tuple_new(struct tuple_format *format, const char *data, const char *end
static struct tuple_format_vtab tuple_format_runtime_vtab = {
runtime_tuple_delete,
runtime_tuple_new,
+ NULL,
+ NULL,
+ NULL,
};
static struct tuple *
@@ -301,6 +319,10 @@ tuple_init(field_name_hash_f hash)
if (tuple_format_runtime == NULL)
return -1;
+ tuple_extra_cache = mh_tuple_extra_new();
+ if (tuple_extra_cache == NULL)
+ return -1;
+
/* Make sure this one stays around. */
tuple_format_ref(tuple_format_runtime);
@@ -374,6 +396,9 @@ tuple_free(void)
mempool_destroy(&tuple_iterator_pool);
small_alloc_destroy(&runtime_alloc);
+ assert(mh_size(tuple_extra_cache) == 0);
+ mh_tuple_extra_delete(tuple_extra_cache);
+
tuple_format_free();
coll_id_cache_destroy();
@@ -785,3 +810,43 @@ mp_str(const char *data)
return "<failed to format message pack>";
return buf;
}
+
+uint32_t
+tuple_extra_sz(uint32_t data_sz)
+{
+ return sizeof(struct tuple_extra) + data_sz;
+}
+
+int
+tuple_extra_cache_register(struct tuple_extra *tuple_extra)
+{
+ mh_int_t id = mh_tuple_extra_put(tuple_extra_cache,
+ (const struct tuple_extra **)&tuple_extra,
+ NULL, 0);
+ if (id == mh_end(tuple_extra_cache))
+ return -1;
+ return 0;
+}
+
+void
+tuple_extra_cache_unregister(struct tuple_extra *tuple_extra)
+{
+ struct tuple *tuple = tuple_extra->tuple;
+ uint32_t chunk_id = tuple_extra->chunk_id;
+ mh_int_t id = mh_tuple_extra_find(tuple_extra_cache,
+ tuple, chunk_id);
+ assert(id != mh_end(tuple_extra_cache));
+ mh_tuple_extra_del(tuple_extra_cache, id, chunk_id);
+}
+
+struct tuple_extra *
+tuple_extra_cache_find(struct tuple *tuple, uint32_t chunk_id)
+{
+ mh_int_t id = mh_tuple_extra_find(tuple_extra_cache, tuple, chunk_id);
+ if (id == mh_end(tuple_extra_cache))
+ return NULL;
+ struct tuple_extra **tuple_extra_ptr =
+ mh_tuple_extra_node(tuple_extra_cache, id);
+ assert(tuple_extra_ptr != NULL && *tuple_extra_ptr != NULL);
+ return *tuple_extra_ptr;
+}
diff --git a/src/box/tuple.h b/src/box/tuple.h
index 99dfeb82d..3504c1d95 100644
--- a/src/box/tuple.h
+++ b/src/box/tuple.h
@@ -447,6 +447,77 @@ tuple_delete(struct tuple *tuple)
format->vtab.tuple_delete(format, tuple);
}
+/** Tuple metadata hashtable entry. */
+struct tuple_extra {
+ /** Tuple pointer is used as a hash key. */
+ struct tuple *tuple;
+ /** An extention identifier. */
+ uint32_t chunk_id;
+ /** The payload size. Needed to perform memory release.*/
+ uint32_t data_sz;
+ /** Metadata object payload. */
+ char data[0];
+};
+
+/** Calculate the size of tuple_extra object by given data_sz. */
+uint32_t
+tuple_extra_sz(uint32_t data_sz);
+
+/**
+ * Lookup for tuple_extra by given tuple and chunk_id in the tuple
+ * extra hashtable.
+ */
+struct tuple_extra *
+tuple_extra_cache_find(struct tuple *tuple, uint32_t chunk_id);
+
+/**
+ * Register a new tuple_extra extention in the tuple extra
+ * hashtable.
+ */
+int
+tuple_extra_cache_register(struct tuple_extra *tuple_extra);
+
+/**
+ * Unregister a given tuple_extra extention in the tuple extra
+ * hashtable.
+ */
+void
+tuple_extra_cache_unregister(struct tuple_extra *tuple_extra);
+
+/**
+ * Allocate a new extra allocation for given tuple and
+ * unique chunk_id identifier.
+ */
+static inline struct tuple_extra *
+tuple_extra_new(struct tuple *tuple, uint32_t chunk_id, uint32_t data_sz)
+{
+ struct tuple_format *format = tuple_format(tuple);
+ return format->vtab.tuple_extra_new(format, tuple, chunk_id, data_sz);
+}
+
+/**
+ * Free allocated tuple extra for given tuple and unique
+ * chunk_id identifier.
+ */
+static inline void
+tuple_extra_delete(struct tuple_extra *tuple_extra)
+{
+ struct tuple_format *format =
+ tuple_format(tuple_extra->tuple);
+ format->vtab.tuple_extra_delete(format, tuple_extra);
+}
+
+/**
+ * Get an existent extra allocation for given tuple and
+ * unique chunk_id identifier.
+ */
+static inline struct tuple_extra *
+tuple_extra_get(struct tuple *tuple, uint32_t chunk_id)
+{
+ struct tuple_format *format = tuple_format(tuple);
+ return format->vtab.tuple_extra_get(format, tuple, chunk_id);
+}
+
/**
* Check tuple data correspondence to space format.
* Actually, checks everything that is checked by
diff --git a/src/box/tuple_format.h b/src/box/tuple_format.h
index e4f5f0018..8b37a48d7 100644
--- a/src/box/tuple_format.h
+++ b/src/box/tuple_format.h
@@ -64,6 +64,7 @@ enum { TUPLE_INDEX_BASE = 1 };
enum { TUPLE_OFFSET_SLOT_NIL = INT32_MAX };
struct tuple;
+struct tuple_extra;
struct tuple_format;
struct coll;
@@ -82,6 +83,27 @@ struct tuple_format_vtab {
struct tuple*
(*tuple_new)(struct tuple_format *format, const char *data,
const char *end);
+ /**
+ * Free allocated tuple extra for given tuple and unique
+ * chunk_id identifier.
+ */
+ void
+ (*tuple_extra_delete)(struct tuple_format *format,
+ struct tuple_extra *tuple_extra);
+ /**
+ * Allocate a new extra allocation for given tuple and
+ * unique chunk_id identifier.
+ */
+ struct tuple_extra *
+ (*tuple_extra_new)(struct tuple_format *format, struct tuple *tuple,
+ uint32_t chunk_id, uint32_t data_sz);
+ /**
+ * Get an existent extra allocation for given tuple and
+ * unique chunk_id identifier.
+ */
+ struct tuple_extra *
+ (*tuple_extra_get)(struct tuple_format *format, struct tuple *tuple,
+ uint32_t chunk_id);
};
/** Tuple field meta information for tuple_format. */
diff --git a/src/box/vy_stmt.c b/src/box/vy_stmt.c
index f936cd61f..5c79eac41 100644
--- a/src/box/vy_stmt.c
+++ b/src/box/vy_stmt.c
@@ -118,6 +118,9 @@ vy_stmt_env_create(struct vy_stmt_env *env)
{
env->tuple_format_vtab.tuple_new = vy_tuple_new;
env->tuple_format_vtab.tuple_delete = vy_tuple_delete;
+ env->tuple_format_vtab.tuple_extra_new = NULL;
+ env->tuple_format_vtab.tuple_extra_delete = NULL;
+ env->tuple_format_vtab.tuple_extra_get = NULL;
env->max_tuple_size = 1024 * 1024;
env->key_format = vy_stmt_format_new(env, NULL, 0, NULL, 0, 0, NULL);
if (env->key_format == NULL)
--
2.21.0
More information about the Tarantool-patches
mailing list