[tarantool-patches] [PATCH v3 3/7] box: create new methods for ephemeral spaces

imeevma at tarantool.org imeevma at tarantool.org
Tue Jul 24 14:58:14 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        | 165 ++++++++++++++++-----
 src/box/box.h         |  94 ++++++++++++
 src/box/memtx_space.c | 395 ++++++++++++++++++++++++++++++++++++--------------
 src/box/space.h       |  17 ---
 src/box/sql.c         |  33 ++++-
 src/box/sysview.c     |   2 -
 src/box/vinyl.c       |   2 -
 7 files changed, 538 insertions(+), 170 deletions(-)

diff --git a/src/box/box.cc b/src/box/box.cc
index 71f3a51..e811496 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -872,6 +872,62 @@ box_set_net_msg_max(void)
 /* }}} configuration bindings */
 
 /**
+ * Fill up request according to given operation type.
+ *
+ * @param request[out] request to fill up.
+ * @param type type of operation.
+ * @param space_id id of space for this operation.
+ * @param index_id id of index for this operation.
+ * @param key key field for UPDATE/DELETE operations and ops field
+ * for UPSERT operation.
+ * @param key_end key_end field for UPDATE/DELETE operations and
+ * ops_end field for UPSERT operation.
+ * @param tuple tuple field for REPLACE, UPDATE and UPSERT
+ * operations.
+ * @param tuple_end tuple_end field for REPLACE, UPDATE and UPSERT
+ * operations.
+ * @param index_base index_base field for UPDATE and UPSERT
+ * operations.
+ */
+static inline void
+request_fill(struct request *request, uint32_t type, uint32_t space_id,
+	     uint32_t index_id, const char *key, const char *key_end,
+	     const char *tuple, const char *tuple_end, int index_base)
+{
+	memset(request, 0, sizeof(*request));
+	request->type = type;
+	request->space_id = space_id;
+	request->index_id = index_id;
+	switch (type) {
+	case IPROTO_INSERT:
+	case IPROTO_REPLACE:
+		request->tuple = tuple;
+		request->tuple_end = tuple_end;
+		break;
+	case IPROTO_DELETE:
+		request->key = key;
+		request->key_end = key_end;
+		break;
+	case IPROTO_UPDATE:
+		request->key = key;
+		request->key_end = key_end;
+		request->tuple = tuple;
+		request->tuple_end = tuple_end;
+		request->index_base = index_base;
+		break;
+	case IPROTO_UPSERT:
+		request->ops = key;
+		request->ops_end = key_end;
+		request->tuple = tuple;
+		request->tuple_end = tuple_end;
+		request->index_base = index_base;
+		break;
+	default:
+		unreachable();
+	}
+}
+
+/**
  * Execute a request against a given space id with
  * a variable-argument tuple described in format.
  *
@@ -1127,11 +1183,8 @@ box_insert(uint32_t space_id, const char *tuple, const char *tuple_end,
 	if (space == NULL || space_check_writable(space) != 0)
 		return -1;
 	struct request request;
-	memset(&request, 0, sizeof(request));
-	request.type = IPROTO_INSERT;
-	request.space_id = space_id;
-	request.tuple = tuple;
-	request.tuple_end = tuple_end;
+	request_fill(&request, IPROTO_INSERT, space_id, 0, NULL, NULL, tuple,
+		     tuple_end, 0);
 	return box_process_rw(&request, space, result);
 }
 
@@ -1144,11 +1197,8 @@ box_replace(uint32_t space_id, const char *tuple, const char *tuple_end,
 	if (space == NULL || space_check_writable(space) != 0)
 		return -1;
 	struct request request;
-	memset(&request, 0, sizeof(request));
-	request.type = IPROTO_REPLACE;
-	request.space_id = space_id;
-	request.tuple = tuple;
-	request.tuple_end = tuple_end;
+	request_fill(&request, IPROTO_REPLACE, space_id, 0, NULL, NULL, tuple,
+		     tuple_end, 0);
 	return box_process_rw(&request, space, result);
 }
 
@@ -1162,12 +1212,8 @@ box_delete(uint32_t space_id, uint32_t index_id, const char *key,
 	    key_check_findable(space, index_id, key) != 0)
 		return -1;
 	struct request request;
-	memset(&request, 0, sizeof(request));
-	request.type = IPROTO_DELETE;
-	request.space_id = space_id;
-	request.index_id = index_id;
-	request.key = key;
-	request.key_end = key_end;
+	request_fill(&request, IPROTO_DELETE, space_id, index_id, key, key_end,
+		     NULL, NULL, 0);
 	return box_process_rw(&request, space, result);
 }
 
@@ -1183,17 +1229,8 @@ box_update(uint32_t space_id, uint32_t index_id, const char *key,
 	    key_check_findable(space, index_id, key) != 0)
 		return -1;
 	struct request request;
-	memset(&request, 0, sizeof(request));
-	request.type = IPROTO_UPDATE;
-	request.space_id = space_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;
-
+	request_fill(&request, IPROTO_UPDATE, space_id, index_id, key, key_end,
+		     ops, ops_end, index_base);
 	return box_process_rw(&request, space, result);
 }
 
@@ -1208,18 +1245,74 @@ box_upsert(uint32_t space_id, uint32_t index_id, const char *tuple,
 	if (space == NULL || space_check_writable(space) != 0)
 		return -1;
 	struct request request;
-	memset(&request, 0, sizeof(request));
-	request.type = IPROTO_UPSERT;
-	request.space_id = space_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;
+	request_fill(&request, IPROTO_UPSERT, space_id, index_id, ops, ops_end,
+		     tuple, tuple_end, index_base);
 	return box_process_rw(&request, space, 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;
+	request_fill(&request, IPROTO_INSERT, 0, 0, NULL, NULL, tuple,
+		     tuple_end, 0);
+	return space_execute_dml(space, NULL, &request, 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;
+	request_fill(&request, IPROTO_REPLACE, 0, 0, NULL, NULL, tuple,
+		     tuple_end, 0);
+	return space_execute_dml(space, NULL, &request, 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);
+	if (key_check_findable(space, index_id, key) != 0)
+		return -1;
+	struct request request;
+	request_fill(&request, IPROTO_DELETE, 0, index_id, key, key_end,
+		     NULL, NULL, 0);
+	return space_execute_dml(space, NULL, &request, result);
+}
+
+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);
+	if (key_check_findable(space, index_id, key) != 0)
+		return -1;
+	struct request request;
+	request_fill(&request, IPROTO_UPDATE, 0, index_id, key, key_end,
+		     ops, ops_end, index_base);
+	return space_execute_dml(space, NULL, &request, result);
+}
+
+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;
+	request_fill(&request, IPROTO_UPSERT, 0, index_id, ops, ops_end,
+		     tuple, tuple_end, index_base);
+	return space_execute_dml(space, NULL, &request, result);
+}
+
 /**
  * Trigger space truncation by bumping a counter
  * in _truncate space.
diff --git a/src/box/box.h b/src/box/box.h
index 6ba2bdf..e582fbc 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -404,6 +404,100 @@ int
 box_process1(struct request *request, box_tuple_t **result);
 
 /**
+ * Execute an INSERT request for ephemeral spaces.
+ *
+ * \param space ephemeral space.
+ * \param tuple encoded tuple in
+ * MsgPack Array format.
+ * \param tuple_end end of @a tuple.
+ * \param[out] result a new tuple.
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_ephemeral_insert(struct space *space, const char *tuple,
+		     const char *tuple_end, box_tuple_t **result);
+
+/**
+ * Execute an REPLACE request for ephemeral spaces.
+ *
+ * \param space ephemeral space.
+ * \param tuple encoded tuple in
+ * MsgPack Array format.
+ * \param tuple_end end of @a tuple.
+ * \param[out] result a new tuple.
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_ephemeral_replace(struct space *space, const char *tuple,
+		      const char *tuple_end, box_tuple_t **result);
+
+/**
+ * Execute an DELETE request for ephemeral spaces.
+ *
+ * \param space ephemeral space.
+ * \param index_id index identifier
+ * \param key encoded key in
+ * MsgPack Array format.
+ * \param key_end the end of encoded \a key.
+ * \param[out] result an old tuple.
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_ephemeral_delete(struct space *space, uint32_t index_id, const char *key,
+		     const char *key_end, box_tuple_t **result);
+
+/**
+ * Execute an UPDATE request for ephemeral spaces.
+ *
+ * \param space ephemeral space.
+ * \param index_id index identifier
+ * \param key encoded key in
+ * MsgPack Array format.
+ * \param key_end the end of encoded \a key.
+ * \param ops encoded operations in
+ * MsgPack Arrat format.
+ * \param ops_end the end of encoded \a ops.
+ * \param index_base 0 if fieldnos in
+ * update operations are zero-based
+ * indexed (like C) or 1 if for one-based
+ * indexed field ids (like Lua).
+ * \param[out] result a new tuple.
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+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);
+
+/**
+ * Execute an UPSERT request for ephemeral spaces.
+ *
+ * \param space ephemeral space.
+ * \param index_id index identifier
+ * \param ops encoded operations in
+ * MsgPack Arrat format.
+ * \param ops_end the end of encoded \a ops.
+ * \param tuple encoded tuple in
+ * MsgPack Array format.
+ * \param tuple_end end of @a tuple.
+ * \param index_base 0 if fieldnos in update
+ * operations are zero-based
+ * indexed (like C) or 1 if for one-based
+ * indexed field ids (like Lua).
+ * \param[out] result a new tuple.
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+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 0d00b90..a5d3594 100644
--- a/src/box/memtx_space.c
+++ b/src/box/memtx_space.c
@@ -332,75 +332,105 @@ rollback:
 	return -1;
 }
 
-static int
-memtx_space_execute_replace(struct space *space, struct txn *txn,
-			    struct request *request, struct tuple **result)
+/**
+ * Executes INSERT and REPLACE operations for given space.
+ *
+ * @param space space for which operation is executed.
+ * @param new_tuple address of caller's new_tuple.
+ * @param old_tuple address of caller's old_tuple.
+ * @param request request which defines operation.
+ * @param[out] result result tuple.
+ *
+ * @returns 0 Success.
+ * @returns -1 Error.
+ */
+static inline int
+memtx_space_replace_impl(struct space *space, struct request *request,
+			 struct tuple **new_tuple, struct tuple **old_tuple,
+			 struct tuple **result)
 {
 	struct memtx_space *memtx_space = (struct memtx_space *)space;
-	struct txn_stmt *stmt = txn_current_stmt(txn);
 	enum dup_replace_mode mode = dup_replace_mode(request->type);
-	stmt->new_tuple = memtx_tuple_new(space->format, request->tuple,
-					  request->tuple_end);
-	if (stmt->new_tuple == NULL)
+	*new_tuple = memtx_tuple_new(space->format, request->tuple,
+				     request->tuple_end);
+	if (*new_tuple == NULL)
 		return -1;
-	tuple_ref(stmt->new_tuple);
-	if (memtx_space->replace(space, NULL, stmt->new_tuple,
-				 mode, &stmt->old_tuple) != 0)
+	if (memtx_space->replace(space, NULL, *new_tuple, mode, old_tuple) != 0)
 		return -1;
-	stmt->engine_savepoint = stmt;
 	/** The new tuple is referenced by the primary key. */
-	*result = stmt->new_tuple;
+	*result = *new_tuple;
 	return 0;
 }
 
-static int
-memtx_space_execute_delete(struct space *space, struct txn *txn,
-			   struct request *request, struct tuple **result)
+/**
+ * Executes DELETE operation for given space.
+ *
+ * @param space space for which operation is executed.
+ * @param old_tuple address of caller's old_tuple.
+ * @param request request which defines operation.
+ * @param[out] result result tuple.
+ *
+ * @returns 0 Success.
+ * @returns -1 Error.
+ */
+static inline int
+memtx_space_delete_impl(struct space *space, struct request *request,
+			struct tuple **old_tuple, struct tuple **result)
 {
 	struct memtx_space *memtx_space = (struct memtx_space *)space;
-	struct txn_stmt *stmt = txn_current_stmt(txn);
 	/* Try to find the tuple by unique key. */
 	struct index *pk = index_find_unique(space, request->index_id);
 	if (pk == NULL)
 		return -1;
 	const char *key = request->key;
 	uint32_t part_count = mp_decode_array(&key);
-	struct tuple *old_tuple;
-	if (index_get(pk, key, part_count, &old_tuple) != 0)
+	struct tuple *tmp_tuple;
+	if (index_get(pk, key, part_count, &tmp_tuple) != 0)
 		return -1;
-	if (old_tuple != NULL &&
-	    memtx_space->replace(space, old_tuple, NULL,
-				 DUP_REPLACE_OR_INSERT, &stmt->old_tuple) != 0)
+	if (tmp_tuple != NULL &&
+	    memtx_space->replace(space, tmp_tuple, NULL,
+				 DUP_REPLACE_OR_INSERT, old_tuple) != 0)
 		return -1;
-	stmt->engine_savepoint = stmt;
-	*result = stmt->old_tuple;
+	*result = *old_tuple;
 	return 0;
 }
 
-static int
-memtx_space_execute_update(struct space *space, struct txn *txn,
-			   struct request *request, struct tuple **result)
+/**
+ * Executes UPDATE operation for given space.
+ *
+ * @param space space for which operation is executed.
+ * @param new_tuple address of caller's new_tuple.
+ * @param old_tuple address of caller's old_tuple.
+ * @param request request which defines operation.
+ * @param[out] result result tuple.
+ *
+ * @returns 0 Success.
+ * @returns -1 Error.
+ */
+static inline int
+memtx_space_update_impl(struct space *space, struct request *request,
+			struct tuple **new_tuple, struct tuple **old_tuple,
+			struct tuple **result)
 {
 	struct memtx_space *memtx_space = (struct memtx_space *)space;
-	struct txn_stmt *stmt = txn_current_stmt(txn);
 	/* Try to find the tuple by unique key. */
 	struct index *pk = index_find_unique(space, request->index_id);
 	if (pk == NULL)
 		return -1;
 	const char *key = request->key;
 	uint32_t part_count = mp_decode_array(&key);
-	struct tuple *old_tuple;
-	if (index_get(pk, key, part_count, &old_tuple) != 0)
+	struct tuple *tmp_tuple;
+	if (index_get(pk, key, part_count, &tmp_tuple) != 0)
 		return -1;
 
-	if (old_tuple == NULL) {
+	if (tmp_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 *old_data = tuple_data_range(tmp_tuple, &bsize);
 	const char *new_data =
 		tuple_update_execute(region_aligned_alloc_cb, &fiber()->gc,
 				     request->tuple, request->tuple_end,
@@ -409,25 +439,33 @@ memtx_space_execute_update(struct space *space, struct txn *txn,
 	if (new_data == NULL)
 		return -1;
 
-	stmt->new_tuple = memtx_tuple_new(space->format, new_data,
-					  new_data + new_size);
-	if (stmt->new_tuple == NULL)
+	*new_tuple = memtx_tuple_new(space->format, new_data,
+				     new_data + new_size);
+	if (*new_tuple == NULL)
 		return -1;
-	tuple_ref(stmt->new_tuple);
-	if (memtx_space->replace(space, old_tuple, stmt->new_tuple,
-				 DUP_REPLACE, &stmt->old_tuple) != 0)
+	if (memtx_space->replace(space, tmp_tuple, *new_tuple,
+				 DUP_REPLACE, old_tuple) != 0)
 		return -1;
-	stmt->engine_savepoint = stmt;
-	*result = stmt->new_tuple;
+	*result = *new_tuple;
 	return 0;
 }
 
-static int
-memtx_space_execute_upsert(struct space *space, struct txn *txn,
-			   struct request *request)
+/**
+ * Executes INSERT operation for given space.
+ *
+ * @param space space for which operation is executed.
+ * @param new_tuple address of caller's new_tuple.
+ * @param old_tuple address of caller's old_tuple.
+ * @param request request which defines operation.
+ *
+ * @returns 0 Success.
+ * @returns -1 Error.
+ */
+static inline int
+memtx_space_upsert_impl(struct space *space, struct request *request,
+			struct tuple **new_tuple, struct tuple **old_tuple)
 {
 	struct memtx_space *memtx_space = (struct memtx_space *)space;
-	struct txn_stmt *stmt = txn_current_stmt(txn);
 	/*
 	 * Check all tuple fields: we should produce an error on
 	 * malformed tuple even if upsert turns into an update.
@@ -450,11 +488,11 @@ memtx_space_execute_upsert(struct space *space, struct txn *txn,
 	mp_decode_array(&key);
 
 	/* Try to find the tuple by primary key. */
-	struct tuple *old_tuple;
-	if (index_get(index, key, part_count, &old_tuple) != 0)
+	struct tuple *tmp_tuple;
+	if (index_get(index, key, part_count, &tmp_tuple) != 0)
 		return -1;
 
-	if (old_tuple == NULL) {
+	if (tmp_tuple == NULL) {
 		/**
 		 * Old tuple was not found. A write optimized
 		 * engine may only know this after commit, so
@@ -471,20 +509,20 @@ memtx_space_execute_upsert(struct space *space, struct txn *txn,
 		 *   we get it here, it's also OK to throw it
 		 * @sa https://github.com/tarantool/tarantool/issues/1156
 		 */
-		if (tuple_update_check_ops(region_aligned_alloc_cb, &fiber()->gc,
-				       request->ops, request->ops_end,
-				       request->index_base)) {
+		if (tuple_update_check_ops(region_aligned_alloc_cb,
+					   &fiber()->gc, request->ops,
+					   request->ops_end,
+					   request->index_base)) {
 			return -1;
 		}
-		stmt->new_tuple = memtx_tuple_new(space->format,
+		*new_tuple = memtx_tuple_new(space->format,
 						  request->tuple,
 						  request->tuple_end);
-		if (stmt->new_tuple == NULL)
+		if (*new_tuple == NULL)
 			return -1;
-		tuple_ref(stmt->new_tuple);
 	} else {
 		uint32_t new_size = 0, bsize;
-		const char *old_data = tuple_data_range(old_tuple, &bsize);
+		const char *old_data = tuple_data_range(tmp_tuple, &bsize);
 		/*
 		 * Update the tuple.
 		 * tuple_upsert_execute() fails on totally wrong
@@ -502,23 +540,22 @@ memtx_space_execute_upsert(struct space *space, struct txn *txn,
 		if (new_data == NULL)
 			return -1;
 
-		stmt->new_tuple = memtx_tuple_new(space->format, new_data,
-						  new_data + new_size);
-		if (stmt->new_tuple == NULL)
+		*new_tuple = memtx_tuple_new(space->format, new_data,
+					     new_data + new_size);
+		if (*new_tuple == NULL)
 			return -1;
-		tuple_ref(stmt->new_tuple);
 
 		struct index *pk = space->index[0];
 		if (!key_update_can_be_skipped(pk->def->key_def->column_mask,
 					       column_mask) &&
-		    tuple_compare(old_tuple, stmt->new_tuple,
+		    tuple_compare(tmp_tuple, *new_tuple,
 				  pk->def->key_def) != 0) {
 			/* Primary key is changed: log error and do nothing. */
 			diag_set(ClientError, ER_CANT_UPDATE_PRIMARY_KEY,
 				 pk->def->name, space_name(space));
 			diag_log();
-			tuple_unref(stmt->new_tuple);
-			stmt->new_tuple = NULL;
+			memtx_tuple_delete(space->format, *new_tuple);
+			*new_tuple = NULL;
 		}
 	}
 	/*
@@ -527,74 +564,184 @@ memtx_space_execute_upsert(struct space *space, struct txn *txn,
 	 * we checked this case explicitly and skipped the upsert
 	 * above.
 	 */
-	if (stmt->new_tuple != NULL &&
-	    memtx_space->replace(space, old_tuple, stmt->new_tuple,
-				 DUP_REPLACE_OR_INSERT, &stmt->old_tuple) != 0)
+	if (*new_tuple != NULL &&
+	    memtx_space->replace(space, tmp_tuple, *new_tuple,
+				 DUP_REPLACE_OR_INSERT, old_tuple) != 0)
 		return -1;
-	stmt->engine_savepoint = stmt;
 	/* Return nothing: UPSERT does not return data. */
 	return 0;
 }
 
+static int
+memtx_space_execute_replace(struct space *space, struct txn *txn,
+			    struct request *request, struct tuple **result)
+{
+	struct txn_stmt *stmt = txn_current_stmt(txn);
+	int rc = memtx_space_replace_impl(space, request, &stmt->new_tuple,
+					  &stmt->old_tuple, result);
+	if (stmt->new_tuple != NULL)
+		tuple_ref(stmt->new_tuple);
+	if (rc != 0)
+		return -1;
+	stmt->engine_savepoint = stmt;
+	return 0;
+}
+
+static int
+memtx_space_execute_delete(struct space *space, struct txn *txn,
+			   struct request *request, struct tuple **result)
+{
+	struct txn_stmt *stmt = txn_current_stmt(txn);
+	if (memtx_space_delete_impl(space, request, &stmt->old_tuple,
+				    result) != 0)
+		return -1;
+	stmt->engine_savepoint = stmt;
+	return 0;
+}
+
+static int
+memtx_space_execute_update(struct space *space, struct txn *txn,
+			   struct request *request, struct tuple **result)
+{
+	struct txn_stmt *stmt = txn_current_stmt(txn);
+	int rc = memtx_space_update_impl(space, request, &stmt->new_tuple,
+					 &stmt->old_tuple, result);
+	if (stmt->new_tuple != NULL)
+		tuple_ref(stmt->new_tuple);
+	if (rc != 0)
+		return -1;
+	stmt->engine_savepoint = stmt;
+	return 0;
+}
+
+static int
+memtx_space_execute_upsert(struct space *space, struct txn *txn,
+			   struct request *request)
+{
+	struct txn_stmt *stmt = txn_current_stmt(txn);
+	int rc = memtx_space_upsert_impl(space, request, &stmt->new_tuple,
+					 &stmt->old_tuple);
+	if (stmt->new_tuple != NULL)
+		tuple_ref(stmt->new_tuple);
+	if (rc != 0)
+		return -1;
+	stmt->engine_savepoint = stmt;
+	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.
+ * Executes INSERT and REPLACE operations for ephemeral spaces.
+ * This function isn't involved in any transaction routine.
+ *
+ * @param space space for which operation is executed.
+ * @param txn txn is NULL for ephemeral spaces.
+ * @param request request which defines operation.
+ * @param[out] result result tuple.
+ *
+ * @returns 0 Success.
+ * @returns -1 Error.
  */
 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)
 {
-	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;
-	struct tuple *old_tuple;
-	if (memtx_space->replace(space, NULL, new_tuple,
-				 DUP_REPLACE_OR_INSERT, &old_tuple) != 0) {
+	assert(txn == NULL);
+	(void)txn;
+	struct tuple *new_tuple = NULL;
+	struct tuple *old_tuple = NULL;
+	int rc = memtx_space_replace_impl(space, request, &new_tuple,
+					  &old_tuple, result);
+	if (rc != 0 && new_tuple != NULL)
 		memtx_tuple_delete(space->format, new_tuple);
+	if (rc != 0)
 		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.
+ * Executes DELETE operation for ephemeral space.
+ * This function isn't involved in any transaction routine.
+ *
+ * @param space space for which operation is executed.
+ * @param txn txn is NULL for ephemeral spaces.
+ * @param request request which defines operation.
+ * @param[out] result result tuple.
+ *
+ * @returns 0 Success.
+ * @returns -1 Error.
  */
 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)
 {
-	struct memtx_space *memtx_space = (struct memtx_space *)space;
-	struct index *primary_index = space_index(space, 0 /* primary index*/);
-	if (primary_index == NULL)
+	assert(txn == NULL);
+	(void)txn;
+	struct tuple *old_tuple = NULL;
+	if (memtx_space_delete_impl(space, request, &old_tuple, result) != 0)
 		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 0;
+}
+
+/**
+ * Executes UPDATE operation for ephemeral space.
+ * This function isn't involved in any transaction routine.
+ *
+ * @param space space for which operation is executed.
+ * @param txn txn is NULL for ephemeral spaces.
+ * @param request request which defines operation.
+ * @param[out] result result tuple.
+ *
+ * @returns 0 Success.
+ * @returns -1 Error.
+ */
+static int
+memtx_space_ephemeral_update(struct space *space, struct txn *txn,
+			     struct request *request, struct tuple **result)
+{
+	assert(txn == NULL);
+	(void)txn;
+	struct tuple *new_tuple = NULL;
+	struct tuple *old_tuple = NULL;
+	int rc = memtx_space_update_impl(space, request, &new_tuple,
+					 &old_tuple, result);
+	if (rc != 0 && new_tuple != NULL)
+		memtx_tuple_delete(space->format, new_tuple);
+	if (rc != 0)
 		return -1;
-	if (old_tuple != NULL &&
-	    memtx_space->replace(space, old_tuple, NULL,
-				 DUP_REPLACE, &old_tuple) != 0)
+	if (old_tuple != NULL)
+		tuple_unref(old_tuple);
+	return 0;
+}
+
+/**
+ * Executes UPSERT operation  for ephemral space.
+ * This function isn't involved in any transaction routine.
+ *
+ * @param space space for which operation is executed.
+ * @param txn txn is NULL for ephemeral spaces.
+ * @param request request which defines operation.
+ *
+ * @returns 0 Success.
+ * @returns -1 Error.
+ */
+static int
+memtx_space_ephemeral_upsert(struct space *space, struct txn *txn,
+			     struct request *request)
+{
+	assert(txn == NULL);
+	(void)txn;
+	struct tuple *old_tuple = NULL;
+	struct tuple *new_tuple = NULL;
+	int rc = memtx_space_upsert_impl(space, request, &new_tuple,
+					 &old_tuple);
+	if (rc != 0 && new_tuple != NULL)
+		memtx_tuple_delete(space->format, new_tuple);
+	if (rc != 0)
 		return -1;
-	tuple_unref(old_tuple);
+	if (old_tuple != NULL)
+		tuple_unref(old_tuple);
 	return 0;
 }
 
@@ -835,9 +982,14 @@ memtx_init_system_space(struct space *space)
 }
 
 static void
-memtx_init_ephemeral_space(struct space *space)
+memtx_init_ephemeral_space(struct space *space);
+
+static void
+memtx_init_unsupported_space(struct space *space)
 {
-	memtx_space_add_primary_key(space);
+	(void)space;
+	diag_set(ClientError, ER_UNSUPPORTED, space_name(space),
+		 "init_ephemeral_space");
 }
 
 static int
@@ -936,8 +1088,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,
@@ -950,6 +1100,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_unsupported_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/space.h b/src/box/space.h
index 01a4af7..da5f7c6 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 d48c3cf..4b38f98 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -451,7 +451,13 @@ 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)
+	struct request request;
+	memset(&request, 0, sizeof(request));
+	request.type = IPROTO_REPLACE;
+	request.tuple = tuple;
+	request.tuple_end = tuple_end;
+	struct tuple *result;
+	if (space_execute_dml(space, NULL, &request, &result) != 0)
 		return SQL_TARANTOOL_INSERT_FAIL;
 	return SQLITE_OK;
 }
@@ -516,11 +522,20 @@ int tarantoolSqlite3EphemeralDelete(BtCursor *pCur)
 	if (key == NULL)
 		return SQL_TARANTOOL_DELETE_FAIL;
 
-	int rc = space_ephemeral_delete(pCur->space, key);
-	if (rc != 0) {
+	mp_tuple_assert(key, key + key_size);
+	struct request request;
+	struct tuple *result;
+	memset(&request, 0, sizeof(request));
+	request.type = IPROTO_DELETE;
+	request.key = key;
+	request.key_end = key + key_size;
+
+	if (space_execute_dml(pCur->space, NULL, &request, &result) != 0) {
 		diag_log();
 		return SQL_TARANTOOL_DELETE_FAIL;
 	}
+	if (result != NULL)
+		box_tuple_unref(result);
 	return SQLITE_OK;
 }
 
@@ -596,14 +611,24 @@ int tarantoolSqlite3EphemeralClearTable(BtCursor *pCur)
 	struct tuple *tuple;
 	char *key;
 	uint32_t  key_size;
+	struct request request;
+	struct tuple *result;
+	memset(&request, 0, sizeof(request));
+	request.type = IPROTO_DELETE;
 
 	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) {
+		mp_tuple_assert(key, key + key_size);
+		request.key = key;
+		request.key_end = key + key_size;
+		if (space_execute_dml(pCur->space, NULL, &request,
+				      &result) != 0) {
 			iterator_delete(it);
 			return SQL_TARANTOOL_DELETE_FAIL;
 		}
+		if (result != NULL)
+			box_tuple_unref(result);
 	}
 	iterator_delete(it);
 
diff --git a/src/box/sysview.c b/src/box/sysview.c
index a215e9e..ce2b47e 100644
--- a/src/box/sysview.c
+++ b/src/box/sysview.c
@@ -482,8 +482,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 = */ generic_space_ephemeral_replace,
-	/* .ephemeral_delete = */ generic_space_ephemeral_delete,
 	/* .init_system_space = */ generic_init_system_space,
 	/* .init_ephemeral_space = */ generic_init_ephemeral_space,
 	/* .check_index_def = */ generic_space_check_index_def,
diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index 05321cd..3655378 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -4419,8 +4419,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 = */ generic_space_ephemeral_replace,
-	/* .ephemeral_delete = */ generic_space_ephemeral_delete,
 	/* .init_system_space = */ generic_init_system_space,
 	/* .init_ephemeral_space = */ generic_init_ephemeral_space,
 	/* .check_index_def = */ vinyl_space_check_index_def,
-- 
2.7.4





More information about the Tarantool-patches mailing list