[patches] [sql 3/9] Add replace/delete functions for ephemeral spaces

Nikita Pettik korablev at tarantool.org
Tue Jan 23 23:19:14 MSK 2018


Ephemeral tables shouldn't be involved in any transaction routine,
since they are used only for internal needs. Moreover, ephemeral spaces
can be created and destroyed within one transaction, which may lead to
incorrect behaviour. Thus, ephemeral replace and delete don't take txn
as an argument.

Furthermore, delete operation should work on tuples with nulls in primary key.
As a rule, it is considered to be bad practice, due to ambiguity when
deleting tuple from space with several tuples containing nulls in PK.
On the other hand, ephemeral spaces are used only for internal needs,
so if it is guaranteed that no such situation occur, it is OK to allow
insertion nulls in PK. Hence, function which implements deletion on ephemeral
tables, doesn't check tuple on null fields.

Currently, supported only by memtx engine.

Signed-off-by: Nikita Pettik <korablev at tarantool.org>
---
 src/box/memtx_space.c    | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/box/space.h          | 18 ++++++++++++++
 src/box/sysview_engine.c | 22 ++++++++++++++++
 src/box/vinyl.c          | 22 ++++++++++++++++
 4 files changed, 127 insertions(+)

diff --git a/src/box/memtx_space.c b/src/box/memtx_space.c
index 304e7fda3..c0b8c9011 100644
--- a/src/box/memtx_space.c
+++ b/src/box/memtx_space.c
@@ -532,6 +532,69 @@ memtx_space_execute_upsert(struct space *space, struct txn *txn,
 	return 0;
 }
 
+/**
+ * This function simply creates new memtx tuple, refs it and calls space's
+ * replace function. In constrast to original memtx_space_execute_replace(), it
+ * doesn't handle any transaction routine.
+ * Ephemeral spaces shouldn't be involved in transaction routine, since
+ * they are used only for internal purposes. Moreover, ephemeral spaces
+ * can be created and destroyed within one transaction and rollback of already
+ * destroyed space may lead to undefined behaviour. For this reason it
+ * doesn't take txn as an argument.
+ */
+static int
+memtx_space_ephemeral_replace(struct space *space, const char *tuple,
+				      const char *tuple_end)
+{
+	struct memtx_space *memtx_space = (struct memtx_space *)space;
+	struct tuple *new_tuple = memtx_tuple_new(space->format, tuple,
+						  tuple_end);
+	if (new_tuple == NULL)
+		return -1;
+	tuple_ref(new_tuple);
+	struct tuple *old_tuple = NULL;
+	if (memtx_space->replace(space, old_tuple, new_tuple,
+				 DUP_REPLACE_OR_INSERT, &old_tuple) != 0) {
+		tuple_unref(new_tuple);
+		return -1;
+	}
+	if (old_tuple != NULL)
+		tuple_unref(old_tuple);
+	return 0;
+}
+
+/**
+ * Delete tuple with given key from primary index. Tuple checking is omitted
+ * due to the ability of ephemeral spaces to hold nulls in primary key.
+ * Generally speaking, it is not correct behaviour owing to ambiguity when
+ * fetching/deleting tuple from space with several tuples containing
+ * nulls in PK. On the other hand, ephemeral spaces are used only for internal
+ * needs, so if it is guaranteed that no such situation occur
+ * (when several tuples with nulls in PK exist), it is OK to allow
+ * insertion nulls in PK.
+ *
+ * Similarly to ephemeral replace function,
+ * it isn't involved in any transaction routine.
+ */
+static int
+memtx_space_ephemeral_delete(struct space *space, const char *key)
+{
+	struct memtx_space *memtx_space = (struct memtx_space *)space;
+	struct index *primary_index = space_index(space, 0 /* primary index*/);
+	if (primary_index == NULL)
+		return -1;
+	uint32_t part_count = mp_decode_array(&key);
+	struct tuple *old_tuple;
+	if (index_get(primary_index, key, part_count, &old_tuple) != 0)
+		return -1;
+	if (old_tuple != NULL &&
+	    memtx_space->replace(space, old_tuple, NULL,
+				 DUP_REPLACE, &old_tuple) != 0)
+		return -1;
+	tuple_unref(old_tuple);
+	return 0;
+}
+
 /* }}} DML */
 
 /* {{{ DDL */
@@ -922,6 +985,8 @@ static const struct space_vtab memtx_space_vtab = {
 	/* .execute_delete = */ memtx_space_execute_delete,
 	/* .execute_update = */ memtx_space_execute_update,
 	/* .execute_upsert = */ memtx_space_execute_upsert,
+	/* .ephemeral_replace = */ memtx_space_ephemeral_replace,
+	/* .ephemeral_delete = */ memtx_space_ephemeral_delete,
 	/* .init_system_space = */ memtx_init_system_space,
 	/* .init_ephemeral_space = */ memtx_init_ephemeral_space,
 	/* .check_index_def = */ memtx_space_check_index_def,
diff --git a/src/box/space.h b/src/box/space.h
index b3d2cde98..184469055 100644
--- a/src/box/space.h
+++ b/src/box/space.h
@@ -66,6 +66,10 @@ struct space_vtab {
 			      struct request *, struct tuple **result);
 	int (*execute_upsert)(struct space *, struct txn *, struct request *);
 
+	int (*ephemeral_replace)(struct space *, const char *, const char *);
+
+	int (*ephemeral_delete)(struct space *, const char *);
+
 	void (*init_system_space)(struct space *);
 	/**
 	 * Initialize an ephemeral space instance.
@@ -334,6 +338,20 @@ int
 space_execute_upsert(struct space *space, struct txn *txn,
 		     struct request *request);
 
+
+static inline int
+space_ephemeral_replace(struct space *space, const char *tuple,
+			const char *tuple_end)
+{
+	return space->vtab->ephemeral_replace(space, tuple, tuple_end);
+}
+
+static inline int
+space_ephemeral_delete(struct space *space, const char *key)
+{
+	return space->vtab->ephemeral_delete(space, key);
+}
+
 static inline void
 init_system_space(struct space *space)
 {
diff --git a/src/box/sysview_engine.c b/src/box/sysview_engine.c
index 556a7e148..817b86355 100644
--- a/src/box/sysview_engine.c
+++ b/src/box/sysview_engine.c
@@ -99,6 +99,26 @@ sysview_space_execute_upsert(struct space *space, struct txn *txn,
 	return -1;
 }
 
+static int
+sysview_space_ephemeral_replace(struct space *space, const char *tuple,
+				const char *tuple_end)
+{
+	(void)space;
+	(void)tuple;
+	(void)tuple_end;
+	unreachable();
+	return -1;
+}
+
+static int
+sysview_space_ephemeral_delete(struct space *space, const char *key)
+{
+	(void)key;
+	(void)space;
+	unreachable();
+	return -1;
+}
+
 static void
 sysview_init_system_space(struct space *space)
 {
@@ -200,6 +220,8 @@ static const struct space_vtab sysview_space_vtab = {
 	/* .execute_delete = */ sysview_space_execute_delete,
 	/* .execute_update = */ sysview_space_execute_update,
 	/* .execute_upsert = */ sysview_space_execute_upsert,
+	/* .ephemeral_replace = */ sysview_space_ephemeral_replace,
+	/* .ephemeral_delete = */ sysview_space_ephemeral_delete,
 	/* .init_system_space = */ sysview_init_system_space,
 	/* .init_ephemeral_space = */ sysview_init_ephemeral_space,
 	/* .check_index_def = */ sysview_space_check_index_def,
diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index 4c670f3cd..0541ebe14 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -2362,6 +2362,26 @@ vinyl_space_execute_upsert(struct space *space, struct txn *txn,
 	return vy_upsert(env, tx, stmt, space, request);
 }
 
+static int
+vinyl_space_ephemeral_replace(struct space *space, const char *tuple,
+			      const char *tuple_end)
+{
+	(void)space;
+	(void)tuple;
+	(void)tuple_end;
+	unreachable();
+	return -1;
+}
+
+static int
+vinyl_space_ephemeral_delete(struct space *space, const char *key)
+{
+	(void)space;
+	(void)key;
+	unreachable();
+	return -1;
+}
+
 static inline void
 txn_stmt_unref_tuples(struct txn_stmt *stmt)
 {
@@ -4013,6 +4033,8 @@ static const struct space_vtab vinyl_space_vtab = {
 	/* .execute_delete = */ vinyl_space_execute_delete,
 	/* .execute_update = */ vinyl_space_execute_update,
 	/* .execute_upsert = */ vinyl_space_execute_upsert,
+	/* .ephemeral_replace = */ vinyl_space_ephemeral_replace,
+	/* .ephemeral_delete = */ vinyl_space_ephemeral_delete,
 	/* .init_system_space = */ vinyl_init_system_space,
 	/* .init_ephemeral_space = */ vinyl_init_ephemeral_space,
 	/* .check_index_def = */ vinyl_space_check_index_def,
-- 
2.15.1




More information about the Tarantool-patches mailing list