[tarantool-patches] [PATCH 1/5] Create new methods for ephemeral spaces

imeevma at tarantool.org imeevma at tarantool.org
Thu Jul 12 14:16:09 MSK 2018


Up to this patch any space had two additional methods
that were methods of ephemeral spaces. In this patch
these methods deleted from vtab and from now on
ephemeral spaces are spaces with special vtab.

Part of #3375.
---
 src/box/box.cc           | 108 ++++++++++++++++++++++++
 src/box/box.h            |  42 ++++++++++
 src/box/memtx_space.c    | 210 ++++++++++++++++++++++++++++++++++++++++-------
 src/box/memtx_tree.c     |   5 ++
 src/box/space.h          |  17 ----
 src/box/sql.c            |  10 +--
 src/box/sysview_engine.c |  22 -----
 src/box/vinyl.c          |  22 -----
 8 files changed, 339 insertions(+), 97 deletions(-)

diff --git a/src/box/box.cc b/src/box/box.cc
index 481c2dd..795e3ee 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -1170,6 +1170,114 @@ box_upsert(uint32_t space_id, uint32_t index_id, const char *tuple,
 	return box_process1(&request, result);
 }
 
+int
+box_ephemeral_insert(struct space *space, const char *tuple,
+		     const char *tuple_end, box_tuple_t **result)
+{
+	mp_tuple_assert(tuple, tuple_end);
+	struct request request;
+	memset(&request, 0, sizeof(request));
+	request.type = IPROTO_INSERT;
+	request.space_id = space->def->id;
+	request.tuple = tuple;
+	request.tuple_end = tuple_end;
+	if(result != NULL)
+		return space_execute_dml(space, NULL, &request, result);
+	struct tuple *temp_result;
+	return space_execute_dml(space, NULL, &request, &temp_result);
+}
+
+int
+box_ephemeral_replace(struct space *space, const char *tuple,
+		      const char *tuple_end, box_tuple_t **result)
+{
+	mp_tuple_assert(tuple, tuple_end);
+	struct request request;
+	memset(&request, 0, sizeof(request));
+	request.type = IPROTO_REPLACE;
+	request.space_id = space->def->id;
+	request.tuple = tuple;
+	request.tuple_end = tuple_end;
+	if(result != NULL)
+		return space_execute_dml(space, NULL, &request, result);
+	struct tuple *temp_result;
+	return space_execute_dml(space, NULL, &request, &temp_result);
+}
+
+int
+box_ephemeral_delete(struct space *space, uint32_t index_id, const char *key,
+		     const char *key_end, box_tuple_t **result)
+{
+	mp_tuple_assert(key, key_end);
+	struct request request;
+	memset(&request, 0, sizeof(request));
+	request.type = IPROTO_DELETE;
+	request.space_id = space->def->id;
+	request.index_id = index_id;
+	request.key = key;
+	request.key_end = key_end;
+	if(result != NULL)
+		return space_execute_dml(space, NULL, &request, result);
+	struct tuple *temp_result;
+	int rc = space_execute_dml(space, NULL, &request, &temp_result);
+	if(temp_result != NULL)
+		tuple_unref(temp_result);
+	return rc;
+}
+
+int
+box_ephemeral_update(struct space *space, uint32_t index_id, const char *key,
+		     const char *key_end, const char *ops, const char *ops_end,
+		     int index_base, box_tuple_t **result)
+{
+	mp_tuple_assert(key, key_end);
+	mp_tuple_assert(ops, ops_end);
+	struct request request;
+	memset(&request, 0, sizeof(request));
+	request.type = IPROTO_UPDATE;
+	request.space_id = space->def->id;
+	request.index_id = index_id;
+	request.key = key;
+	request.key_end = key_end;
+	request.index_base = index_base;
+	/** Legacy: in case of update, ops are passed in in request tuple */
+	request.tuple = ops;
+	request.tuple_end = ops_end;
+	if(result != NULL)
+		return space_execute_dml(space, NULL, &request, result);
+	struct tuple *temp_result;
+	int rc = space_execute_dml(space, NULL, &request, &temp_result);
+	if(temp_result != NULL)
+		tuple_unref(temp_result);
+	return rc;
+}
+
+int
+box_ephemeral_upsert(struct space *space, uint32_t index_id, const char *tuple,
+		     const char *tuple_end, const char *ops,
+		     const char *ops_end, int index_base, box_tuple_t **result)
+{
+	mp_tuple_assert(ops, ops_end);
+	mp_tuple_assert(tuple, tuple_end);
+	struct request request;
+	memset(&request, 0, sizeof(request));
+	request.type = IPROTO_UPSERT;
+	request.space_id = space->def->id;
+	request.index_id = index_id;
+	request.ops = ops;
+	request.ops_end = ops_end;
+	request.tuple = tuple;
+	request.tuple_end = tuple_end;
+	request.index_base = index_base;
+	if(result != NULL)
+		return space_execute_dml(space, NULL, &request, result);
+	struct tuple *temp_result;
+	int rc = space_execute_dml(space, NULL, &request, &temp_result);
+	if(temp_result != NULL)
+		tuple_unref(temp_result);
+	return rc;
+}
+
 /**
  * Trigger space truncation by bumping a counter
  * in _truncate space.
diff --git a/src/box/box.h b/src/box/box.h
index d879847..a00a842 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -402,6 +402,48 @@ int
 box_process1(struct request *request, box_tuple_t **result);
 
 /**
+ * Used to prepare request for inserting tuple into
+ * ephemeral space and call box_process_rw().
+ */
+int
+box_ephemeral_insert(struct space *space, const char *tuple,
+		     const char *tuple_end, box_tuple_t **result);
+
+/**
+ * Used to prepare request for deleting tuple from
+ * ephemeral space and call box_process_rw().
+ */
+int
+box_ephemeral_replace(struct space *space, const char *tuple,
+		      const char *tuple_end, box_tuple_t **result);
+
+/**
+ * Used to prepare request for replacong tuple in
+ * ephemeral space and call box_process_rw().
+ */
+int
+box_ephemeral_delete(struct space *space, uint32_t index_id, const char *key,
+		     const char *key_end, box_tuple_t **result);
+
+/**
+ * Used to prepare request for updating tuple from
+ * ephemeral space and call box_process_rw().
+ */
+int
+box_ephemeral_update(struct space *space, uint32_t index_id, const char *key,
+		     const char *key_end, const char *ops, const char *ops_end,
+		     int index_base, box_tuple_t **result);
+
+/**
+ * Used to prepare request for inserting tuple into
+ * ephemeral space or updating tuple from ephemeral
+ * space and call box_process_rw().
+ */
+int
+box_ephemeral_upsert(struct space *space, uint32_t index_id, const char *tuple,
+		     const char *tuple_end, const char *ops,
+		     const char *ops_end, int index_base, box_tuple_t **result);
+/**
  * Execute request on given space.
  *
  * \param request Request to be executed
diff --git a/src/box/memtx_space.c b/src/box/memtx_space.c
index b94c4ab..e4781e3 100644
--- a/src/box/memtx_space.c
+++ b/src/box/memtx_space.c
@@ -543,56 +543,51 @@ memtx_space_execute_upsert(struct space *space, struct txn *txn,
 }
 
 /**
- * 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.
+ * This function creates new memtx tuple, refs it and calls
+ * ephemeral space's replace function.
+ *
+ * This function isn't involved in any transaction routine.
  */
 static int
-memtx_space_ephemeral_replace(struct space *space, const char *tuple,
-				      const char *tuple_end)
+memtx_space_ephemeral_replace(struct space *space, struct txn *txn,
+			      struct request *request, struct tuple **result)
 {
+	(void)txn;
 	struct memtx_space *memtx_space = (struct memtx_space *)space;
-	struct tuple *new_tuple = memtx_tuple_new(space->format, tuple,
-						  tuple_end);
+	enum dup_replace_mode mode = dup_replace_mode(request->type);
+	struct tuple *new_tuple = memtx_tuple_new(space->format, request->tuple,
+						  request->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) {
+				 mode, &old_tuple) != 0) {
 		tuple_unref(new_tuple);
 		return -1;
 	}
+	*result = new_tuple;
 	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.
+ * Delete tuple with given key from primary index of
+ * ephemeral space.
  *
- * Similarly to ephemeral replace function,
- * it isn't involved in any transaction routine.
+ * This function isn't involved in any transaction routine.
  */
 static int
-memtx_space_ephemeral_delete(struct space *space, const char *key)
+memtx_space_ephemeral_delete(struct space *space, struct txn *txn,
+			     struct request *request, struct tuple **result)
 {
+	(void)txn;
 	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;
+	const char *key = request->key;
 	uint32_t part_count = mp_decode_array(&key);
 	struct tuple *old_tuple;
 	if (index_get(primary_index, key, part_count, &old_tuple) != 0)
@@ -601,7 +596,138 @@ memtx_space_ephemeral_delete(struct space *space, const char *key)
 	    memtx_space->replace(space, old_tuple, NULL,
 				 DUP_REPLACE, &old_tuple) != 0)
 		return -1;
-	tuple_unref(old_tuple);
+	*result = old_tuple;
+	return 0;
+}
+
+/**
+ * Replace tuple with given key from primary index of
+ * ephemeral space with new tuple.
+ *
+ * This function isn't involved in any transaction routine.
+ */
+static int
+memtx_space_ephemeral_update(struct space *space, struct txn *txn,
+			     struct request *request, struct tuple **result)
+{
+	(void)txn;
+	struct memtx_space *memtx_space = (struct memtx_space *)space;
+	struct index *pk = space_index(space, 0 /* primary index*/);
+	if (pk == NULL)
+		return -1;
+	const char *key = request->key;
+	uint32_t part_count = mp_decode_array(&key);
+	struct tuple *old_tuple;
+	if (exact_key_validate(pk->def->key_def, key, part_count) != 0)
+		return -1;
+	if (index_get(pk, key, part_count, &old_tuple) != 0)
+		return -1;
+	if (old_tuple == NULL) {
+		*result = NULL;
+		return 0;
+	}
+
+	/* Update the tuple; legacy, request ops are in request->tuple */
+	uint32_t new_size = 0, bsize;
+	const char *old_data = tuple_data_range(old_tuple, &bsize);
+	const char *new_data =
+		tuple_update_execute(region_aligned_alloc_cb, &fiber()->gc,
+				     request->tuple, request->tuple_end,
+				     old_data, old_data + bsize,
+				     &new_size, request->index_base, NULL);
+	if (new_data == NULL)
+		return -1;
+	struct tuple *new_tuple = memtx_tuple_new(space->format, new_data,
+						  new_data + new_size);
+	if (new_tuple == NULL)
+		return -1;
+	tuple_ref(new_tuple);
+	if (memtx_space->replace(space, old_tuple, new_tuple,
+				 DUP_REPLACE, &old_tuple) != 0) {
+		tuple_unref(new_tuple);
+		return -1;
+	}
+	*result = new_tuple;
+	return 0;
+}
+
+/**
+ * As ephemeral spaces doesn't works with transactions
+ * upsert becomes almost the same as update but it
+ * doesn't return any result.
+ *
+ * This function isn't involved in any transaction routine.
+ */
+static int
+memtx_space_ephemeral_upsert(struct space *space, struct txn *txn,
+			     struct request *request)
+{
+	(void)txn;
+	struct memtx_space *memtx_space = (struct memtx_space *)space;
+	if (tuple_validate_raw(space->format, request->tuple))
+		return -1;
+	struct index *index = index_find_unique(space, 0);
+	if (index == NULL)
+		return -1;
+	uint32_t part_count = index->def->key_def->part_count;
+	uint32_t key_size;
+	const char *key = tuple_extract_key_raw(request->tuple,
+						request->tuple_end,
+						index->def->key_def, &key_size);
+	if (key == NULL)
+		return -1;
+	mp_decode_array(&key);
+	struct tuple *old_tuple;
+	struct tuple *new_tuple;
+	if (index_get(index, key, part_count, &old_tuple) != 0)
+		return -1;
+	if (old_tuple == NULL) {
+		if (tuple_update_check_ops(region_aligned_alloc_cb,
+					   &fiber()->gc, request->ops,
+					   request->ops_end,
+					   request->index_base)) {
+			return -1;
+		}
+		new_tuple = memtx_tuple_new(space->format,
+					    request->tuple,
+					    request->tuple_end);
+		if (new_tuple == NULL)
+			return -1;
+		tuple_ref(new_tuple);
+	} else {
+		uint32_t new_size = 0, bsize;
+		const char *old_data = tuple_data_range(old_tuple, &bsize);
+		uint64_t column_mask = COLUMN_MASK_FULL;
+		const char *new_data =
+			tuple_upsert_execute(region_aligned_alloc_cb,
+					     &fiber()->gc, request->ops,
+					     request->ops_end, old_data,
+					     old_data + bsize, &new_size,
+					     request->index_base, false,
+					     &column_mask);
+		if (new_data == NULL)
+			return -1;
+		new_tuple = memtx_tuple_new(space->format, new_data,
+					    new_data + new_size);
+		if (new_tuple == NULL)
+			return -1;
+		tuple_ref(new_tuple);
+		if (!key_update_can_be_skipped(index->def->key_def->column_mask,
+					       column_mask) &&
+		    tuple_compare(old_tuple, new_tuple,
+				  index->def->key_def) != 0) {
+			diag_set(ClientError, ER_CANT_UPDATE_PRIMARY_KEY,
+				 index->def->name, space_name(space));
+			diag_log();
+			tuple_unref(new_tuple);
+			old_tuple = NULL;
+			new_tuple = NULL;
+		}
+	}
+	if (new_tuple != NULL &&
+	    memtx_space->replace(space, old_tuple, new_tuple,
+				 DUP_REPLACE_OR_INSERT, &old_tuple) != 0)
+		return -1;
 	return 0;
 }
 
@@ -842,10 +968,7 @@ memtx_init_system_space(struct space *space)
 }
 
 static void
-memtx_init_ephemeral_space(struct space *space)
-{
-	memtx_space_add_primary_key(space);
-}
+memtx_init_ephemeral_space(struct space *space);
 
 static int
 memtx_space_build_index(struct space *src_space, struct index *new_index,
@@ -943,8 +1066,6 @@ 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,
@@ -957,6 +1078,33 @@ static const struct space_vtab memtx_space_vtab = {
 	/* .prepare_alter = */ memtx_space_prepare_alter,
 };
 
+static const struct space_vtab memtx_space_ephemeral_vtab = {
+	/* .destroy = */ memtx_space_destroy,
+	/* .bsize = */ memtx_space_bsize,
+	/* .apply_initial_join_row = */ memtx_space_apply_initial_join_row,
+	/* .execute_replace = */ memtx_space_ephemeral_replace,
+	/* .execute_delete = */ memtx_space_ephemeral_delete,
+	/* .execute_update = */ memtx_space_ephemeral_update,
+	/* .execute_upsert = */ memtx_space_ephemeral_upsert,
+	/* .init_system_space = */ memtx_init_system_space,
+	/* .init_ephemeral_space = */ memtx_init_ephemeral_space,
+	/* .check_index_def = */ memtx_space_check_index_def,
+	/* .create_index = */ memtx_space_create_index,
+	/* .add_primary_key = */ memtx_space_add_primary_key,
+	/* .drop_primary_key = */ memtx_space_drop_primary_key,
+	/* .check_format  = */ memtx_space_check_format,
+	/* .build_index = */ memtx_space_build_index,
+	/* .swap_index = */ generic_space_swap_index,
+	/* .prepare_alter = */ memtx_space_prepare_alter,
+};
+
+static void
+memtx_init_ephemeral_space(struct space *space)
+{
+	space->vtab = &memtx_space_ephemeral_vtab;
+	memtx_space_add_primary_key(space);
+}
+
 struct space *
 memtx_space_new(struct memtx_engine *memtx,
 		struct space_def *def, struct rlist *key_list)
diff --git a/src/box/memtx_tree.c b/src/box/memtx_tree.c
index f851fb8..b0634f9 100644
--- a/src/box/memtx_tree.c
+++ b/src/box/memtx_tree.c
@@ -461,6 +461,11 @@ memtx_tree_index_replace(struct index *base, struct tuple *old_tuple,
 			memtx_tree_delete(&index->tree, new_tuple);
 			if (dup_tuple)
 				memtx_tree_insert(&index->tree, dup_tuple, 0);
+			if (base->def->space_id == 0) {
+				diag_set(ClientError, errcode, base->def->name,
+					 "ephemeral");
+				return -1;
+			}
 			struct space *sp = space_cache_find(base->def->space_id);
 			if (sp != NULL)
 				diag_set(ClientError, errcode, base->def->name,
diff --git a/src/box/space.h b/src/box/space.h
index adf06b7..60fa603 100644
--- a/src/box/space.h
+++ b/src/box/space.h
@@ -67,10 +67,6 @@ 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.
@@ -310,19 +306,6 @@ int
 space_execute_dml(struct space *space, struct txn *txn,
 		  struct request *request, struct tuple **result);
 
-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);
-}
-
 /**
  * Generic implementation of space_vtab::swap_index
  * that simply swaps the two indexes in index maps.
diff --git a/src/box/sql.c b/src/box/sql.c
index fdce224..5c1da72 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -451,7 +451,7 @@ int tarantoolSqlite3EphemeralInsert(struct space *space, const char *tuple,
 {
 	assert(space != NULL);
 	mp_tuple_assert(tuple, tuple_end);
-	if (space_ephemeral_replace(space, tuple, tuple_end) != 0)
+	if (box_ephemeral_replace(space, tuple, tuple_end, NULL) != 0)
 		return SQL_TARANTOOL_INSERT_FAIL;
 	return SQLITE_OK;
 }
@@ -515,9 +515,8 @@ int tarantoolSqlite3EphemeralDelete(BtCursor *pCur)
 				&key_size);
 	if (key == NULL)
 		return SQL_TARANTOOL_DELETE_FAIL;
-
-	int rc = space_ephemeral_delete(pCur->space, key);
-	if (rc != 0) {
+	if (box_ephemeral_delete(pCur->space, 0, key,
+				 key + key_size, NULL) != 0) {
 		diag_log();
 		return SQL_TARANTOOL_DELETE_FAIL;
 	}
@@ -600,7 +599,8 @@ int tarantoolSqlite3EphemeralClearTable(BtCursor *pCur)
 	while (iterator_next(it, &tuple) == 0 && tuple != NULL) {
 		key = tuple_extract_key(tuple, it->index->def->key_def,
 					&key_size);
-		if (space_ephemeral_delete(pCur->space, key) != 0) {
+		if (box_ephemeral_delete(pCur->space, 0, key,
+					 key + key_size, NULL) != 0) {
 			iterator_delete(it);
 			return SQL_TARANTOOL_DELETE_FAIL;
 		}
diff --git a/src/box/sysview_engine.c b/src/box/sysview_engine.c
index bd9432a..3067175 100644
--- a/src/box/sysview_engine.c
+++ b/src/box/sysview_engine.c
@@ -99,26 +99,6 @@ 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)
 {
@@ -197,8 +177,6 @@ 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 ba9cd3a..bfa9590 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -2349,26 +2349,6 @@ 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)
 {
@@ -4514,8 +4494,6 @@ 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.7.4





More information about the Tarantool-patches mailing list