[tarantool-patches] [PATCH v3 7/7] box: methods for ephemeral space and its index

imeevma at tarantool.org imeevma at tarantool.org
Tue Jul 24 14:58:22 MSK 2018


This patch defines most methods for index of
ephemeral space and ephemeral space.

Closes #3375.
---
 src/box/box.cc                    |  64 ++-
 src/box/box.h                     |  21 +
 src/box/index.cc                  | 158 ++++++++
 src/box/index.h                   | 137 +++++++
 src/box/lua/index.c               | 422 +++++++++++++++++++-
 src/box/lua/misc.cc               |  10 +-
 src/box/lua/misc.h                |   9 +
 src/box/lua/schema.lua            | 156 ++++++++
 test/box/ephemeral_space.result   | 802 +++++++++++++++++++++++++++++++++++++-
 test/box/ephemeral_space.test.lua | 240 ++++++++++++
 test/engine/iterator.result       |   2 +-
 11 files changed, 1992 insertions(+), 29 deletions(-)

diff --git a/src/box/box.cc b/src/box/box.cc
index e811496..40d0f24 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -1099,16 +1099,11 @@ box_process1(struct request *request, box_tuple_t **result)
 	return box_process_rw(request, space, result);
 }
 
-int
-box_select(uint32_t space_id, uint32_t index_id,
-	   int iterator, uint32_t offset, uint32_t limit,
-	   const char *key, const char *key_end,
-	   struct port *port)
+static inline int
+box_select_impl(struct space *space, uint32_t index_id,
+		int iterator, uint32_t offset, uint32_t limit,
+		const char *key, struct port *port)
 {
-	(void)key_end;
-
-	rmean_collect(rmean_box, IPROTO_SELECT, 1);
-
 	if (iterator < 0 || iterator >= iterator_type_MAX) {
 		diag_set(ClientError, ER_ILLEGAL_PARAMS,
 			 "Invalid iterator type");
@@ -1116,11 +1111,6 @@ box_select(uint32_t space_id, uint32_t index_id,
 		return -1;
 	}
 
-	struct space *space = space_cache_find(space_id);
-	if (space == NULL)
-		return -1;
-	if (access_check_space(space, PRIV_R) != 0)
-		return -1;
 	struct index *index = index_find(space, index_id);
 	if (index == NULL)
 		return -1;
@@ -1135,16 +1125,10 @@ box_select(uint32_t space_id, uint32_t index_id,
 		return -1;
 	});
 
-	struct txn *txn;
-	if (txn_begin_ro_stmt(space, &txn) != 0)
-		return -1;
-
 	struct iterator *it = index_create_iterator(index, type,
 						    key, part_count);
-	if (it == NULL) {
-		txn_rollback_stmt();
+	if (it == NULL)
 		return -1;
-	}
 
 	int rc = 0;
 	uint32_t found = 0;
@@ -1167,9 +1151,36 @@ box_select(uint32_t space_id, uint32_t index_id,
 
 	if (rc != 0) {
 		port_destroy(port);
+		return -1;
+	}
+	return 0;
+}
+
+int
+box_select(uint32_t space_id, uint32_t index_id,
+	   int iterator, uint32_t offset, uint32_t limit,
+	   const char *key, const char *key_end,
+	   struct port *port)
+{
+	(void)key_end;
+
+	rmean_collect(rmean_box, IPROTO_SELECT, 1);
+
+	struct space *space = space_cache_find(space_id);
+	if (space == NULL)
+		return -1;
+	if (access_check_space(space, PRIV_R) != 0)
+		return -1;
+	struct txn *txn;
+	if (txn_begin_ro_stmt(space, &txn) != 0)
+		return -1;
+
+	if (box_select_impl(space, index_id, iterator, offset, limit, key,
+			    port) != 0) {
 		txn_rollback_stmt();
 		return -1;
 	}
+
 	txn_commit_ro_stmt(txn);
 	return 0;
 }
@@ -1251,6 +1262,17 @@ box_upsert(uint32_t space_id, uint32_t index_id, const char *tuple,
 }
 
 int
+box_ephemeral_select(struct space *space, uint32_t index_id,
+		     int iterator, uint32_t offset, uint32_t limit,
+		     const char *key, const char *key_end,
+		     struct port *port)
+{
+	(void)key_end;
+	return box_select_impl(space, index_id, iterator, offset, limit, key,
+			       port);
+}
+
+int
 box_ephemeral_insert(struct space *space, const char *tuple,
 		     const char *tuple_end, box_tuple_t **result)
 {
diff --git a/src/box/box.h b/src/box/box.h
index e582fbc..40fc31b 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -404,6 +404,27 @@ int
 box_process1(struct request *request, box_tuple_t **result);
 
 /**
+ * Select the number of tuple matched conditions.
+ *
+ * \param space ephemeral space.
+ * \param index_id id of index for select.
+ * \param iterator iterator to use for select.
+ * \param offset offset for select.
+ * \param limit limit for select.
+ * \param key key for select.
+ * \param key_end end of \a key.
+ * \param port port to save result of select to.
+ *
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_ephemeral_select(struct space *space, uint32_t index_id,
+		     int iterator, uint32_t offset, uint32_t limit,
+		     const char *key, const char *key_end,
+		     struct port *port);
+
+/**
  * Execute an INSERT request for ephemeral spaces.
  *
  * \param space ephemeral space.
diff --git a/src/box/index.cc b/src/box/index.cc
index 372e0f3..e2cb4f0 100644
--- a/src/box/index.cc
+++ b/src/box/index.cc
@@ -198,6 +198,15 @@ box_index_len(uint32_t space_id, uint32_t index_id)
 }
 
 ssize_t
+box_index_len_ephemeral(struct space *space, uint32_t index_id)
+{
+	struct index *index = index_find(space, index_id);
+	if (index == NULL)
+		return -1;
+	return index_size(index);
+}
+
+ssize_t
 box_index_bsize(uint32_t space_id, uint32_t index_id)
 {
 	struct space *space;
@@ -208,6 +217,15 @@ box_index_bsize(uint32_t space_id, uint32_t index_id)
 	return index_bsize(index);
 }
 
+ssize_t
+box_index_bsize_ephemeral(struct space *space, uint32_t index_id)
+{
+	struct index *index = index_find(space, index_id);
+	if (index == NULL)
+		return 0;
+	return index_bsize(index);
+}
+
 int
 box_index_random(uint32_t space_id, uint32_t index_id, uint32_t rnd,
 		box_tuple_t **result)
@@ -226,6 +244,19 @@ box_index_random(uint32_t space_id, uint32_t index_id, uint32_t rnd,
 }
 
 int
+box_index_random_ephemeral(struct space *space, uint32_t index_id,
+			   uint32_t rnd, box_tuple_t **result)
+{
+	assert(result != NULL);
+	struct index *index = index_find(space, index_id);
+	if (index == NULL || index_random(index, rnd, result) != 0)
+		return -1;
+	if (*result != NULL)
+		tuple_bless(*result);
+	return 0;
+}
+
+int
 box_index_get(uint32_t space_id, uint32_t index_id, const char *key,
 	      const char *key_end, box_tuple_t **result)
 {
@@ -259,6 +290,29 @@ box_index_get(uint32_t space_id, uint32_t index_id, const char *key,
 }
 
 int
+box_index_get_ephemeral(struct space *space, uint32_t index_id, const char *key,
+			const char *key_end, box_tuple_t **result)
+{
+	assert(key != NULL && key_end != NULL && result != NULL);
+	mp_tuple_assert(key, key_end);
+	struct index *index = index_find(space, index_id);
+	if (index == NULL)
+		return -1;
+	if (!index->def->opts.is_unique) {
+		diag_set(ClientError, ER_MORE_THAN_ONE_TUPLE);
+		return -1;
+	}
+	uint32_t part_count = mp_decode_array(&key);
+	if (exact_key_validate(index->def->key_def, key, part_count))
+		return -1;
+	if (index_get(index, key, part_count, result) != 0)
+		return -1;
+	if (*result != NULL)
+		tuple_bless(*result);
+	return 0;
+}
+
+int
 box_index_min(uint32_t space_id, uint32_t index_id, const char *key,
 	      const char *key_end, box_tuple_t **result)
 {
@@ -291,6 +345,29 @@ box_index_min(uint32_t space_id, uint32_t index_id, const char *key,
 }
 
 int
+box_index_min_ephemeral(struct space *space, uint32_t index_id, const char *key,
+			const char *key_end, box_tuple_t **result)
+{
+	assert(key != NULL && key_end != NULL && result != NULL);
+	mp_tuple_assert(key, key_end);
+	struct index *index = index_find(space, index_id);
+	if (index == NULL)
+		return -1;
+	if (index->def->type != TREE) {
+		diag_set(UnsupportedIndexFeature, index->def, "min()");
+		return -1;
+	}
+	uint32_t part_count = mp_decode_array(&key);
+	if (key_validate(index->def, ITER_GE, key, part_count))
+		return -1;
+	if (index_min(index, key, part_count, result) != 0)
+		return -1;
+	if (*result != NULL)
+		tuple_bless(*result);
+	return 0;
+}
+
+int
 box_index_max(uint32_t space_id, uint32_t index_id, const char *key,
 	      const char *key_end, box_tuple_t **result)
 {
@@ -322,6 +399,29 @@ box_index_max(uint32_t space_id, uint32_t index_id, const char *key,
 	return 0;
 }
 
+int
+box_index_max_ephemeral(struct space *space, uint32_t index_id, const char *key,
+			const char *key_end, box_tuple_t **result)
+{
+	mp_tuple_assert(key, key_end);
+	assert(result != NULL);
+	struct index *index = index_find(space, index_id);
+	if (index == NULL)
+		return -1;
+	if (index->def->type != TREE) {
+		diag_set(UnsupportedIndexFeature, index->def, "max()");
+		return -1;
+	}
+	uint32_t part_count = mp_decode_array(&key);
+	if (key_validate(index->def, ITER_LE, key, part_count))
+		return -1;
+	if (index_max(index, key, part_count, result) != 0)
+		return -1;
+	if (*result != NULL)
+		tuple_bless(*result);
+	return 0;
+}
+
 ssize_t
 box_index_count(uint32_t space_id, uint32_t index_id, int type,
 		const char *key, const char *key_end)
@@ -354,6 +454,30 @@ box_index_count(uint32_t space_id, uint32_t index_id, int type,
 	return count;
 }
 
+ssize_t
+box_index_count_ephemeral(struct space *space, uint32_t index_id, int type,
+			  const char *key, const char *key_end)
+{
+	assert(key != NULL && key_end != NULL);
+	mp_tuple_assert(key, key_end);
+	if (type < 0 || type >= iterator_type_MAX) {
+		diag_set(ClientError, ER_ILLEGAL_PARAMS,
+			 "Invalid iterator type");
+		return -1;
+	}
+	enum iterator_type itype = (enum iterator_type) type;
+	struct index *index = index_find(space, index_id);
+	if (index == NULL)
+		return -1;
+	uint32_t part_count = mp_decode_array(&key);
+	if (key_validate(index->def, itype, key, part_count))
+		return -1;
+	ssize_t count = index_count(index, itype, key, part_count);
+	if (count < 0)
+		return -1;
+	return count;
+}
+
 /* }}} */
 
 /* {{{ Iterators ************************************************/
@@ -391,6 +515,30 @@ box_index_iterator(uint32_t space_id, uint32_t index_id, int type,
 	return it;
 }
 
+box_iterator_t *
+box_index_iterator_ephemeral(struct space *space, uint32_t index_id, int type,
+			     const char *key, const char *key_end)
+{
+	assert(key != NULL && key_end != NULL);
+	mp_tuple_assert(key, key_end);
+	if (type < 0 || type >= iterator_type_MAX) {
+		diag_set(ClientError, ER_ILLEGAL_PARAMS,
+			 "Invalid iterator type");
+		return NULL;
+	}
+	struct index *index = index_find(space, index_id);
+	if (index == NULL)
+		return NULL;
+	enum iterator_type itype = (enum iterator_type) type;
+	assert(mp_typeof(*key) == MP_ARRAY); /* checked by Lua */
+	uint32_t part_count = mp_decode_array(&key);
+	if (key_validate(index->def, itype, key, part_count))
+		return NULL;
+	struct iterator *it = index_create_iterator(index, itype,
+						    key, part_count);
+	return it;
+}
+
 int
 box_iterator_next(box_iterator_t *itr, box_tuple_t **result)
 {
@@ -435,6 +583,16 @@ box_index_compact(uint32_t space_id, uint32_t index_id)
 	return 0;
 }
 
+int
+box_index_compact_ephemeral(struct space *space, uint32_t index_id)
+{
+	struct index *index = index_find(space, index_id);
+	if (index == NULL)
+		return -1;
+	index_compact(index);
+	return 0;
+}
+
 /* }}} */
 
 /* {{{ Internal API */
diff --git a/src/box/index.h b/src/box/index.h
index 73ee000..83e30bf 100644
--- a/src/box/index.h
+++ b/src/box/index.h
@@ -236,6 +236,143 @@ box_index_stat(uint32_t space_id, uint32_t index_id,
 int
 box_index_compact(uint32_t space_id, uint32_t index_id);
 
+/**
+ * Return the number of element in the index.
+ *
+ * \param space - ephemeral space.
+ * \param index_id - index identifier.
+ *
+ * \retval -1 on error.
+ * \retval >= 0 on success.
+ */
+ssize_t
+box_index_len_ephemeral(struct space *space, uint32_t index_id);
+
+/**
+ * Return the number of bytes used in memory by the index.
+ * If space have no index it returns 0.
+ *
+ * \param space ephemeral space.
+ * \param index_id index identifier.
+ *
+ * \retval -1 on error.
+ * \retval >= 0 on success.
+ */
+ssize_t
+box_index_bsize_ephemeral(struct space *space, uint32_t index_id);
+
+/**
+ * Return a random tuple from the index.
+ *
+ * \param space ephemeral space.
+ * \param index_id index identifier.
+ * \param rnd random seed.
+ * \param[out] result a tuple or NULL if index is empty.
+ *
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_index_random_ephemeral(struct space *space, uint32_t index_id,
+			   uint32_t rnd, box_tuple_t **result);
+
+/**
+ * Get a tuple from index by the key.
+ *
+ * \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 a tuple or NULL if index is empty.
+ *
+ * \retval -1 on error.
+ * \retval 0 on success.
+ * \pre key != NULL
+ */
+int
+box_index_get_ephemeral(struct space *space, uint32_t index_id, const char *key,
+			const char *key_end, box_tuple_t **result);
+
+/**
+ * Return first (minimal) tuple matched the provided key.
+ *
+ * \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 a tuple or NULL if index is empty.
+ *
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_index_min_ephemeral(struct space *space, uint32_t index_id, const char *key,
+			const char *key_end, box_tuple_t **result);
+
+/**
+ * Return last (maximal) tuple matched the provided key.
+ *
+ * \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 a tuple or NULL if index is empty.
+ *
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_index_max_ephemeral(struct space *space, uint32_t index_id, const char *key,
+			const char *key_end, box_tuple_t **result);
+
+/**
+ * Count the number of tuple matched the provided key.
+ *
+ * \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 a tuple or NULL if index is empty.
+ *
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+ssize_t
+box_index_count_ephemeral(struct space *space, uint32_t index_id, int type,
+			  const char *key, const char *key_end);
+
+/**
+ * Allocate and initialize iterator for ephemeral space
+ *
+ * A returned iterator must be destroyed by box_iterator_free().
+ *
+ * \param space ephemeral space.
+ * \param index_id index identifier.
+ * \param type \link iterator_type iterator type \endlink
+ * \param key encoded key in MsgPack Array format ([part1, part2, ...]).
+ * \param key_end the end of encoded \a key
+ *
+ * \retval NULL on error (check box_error_last())
+ * \retval iterator otherwise
+ * \sa box_iterator_next()
+ * \sa box_iterator_free()
+ */
+box_iterator_t *
+box_index_iterator_ephemeral(struct space *space, uint32_t index_id, int type,
+			     const char *key, const char *key_end);
+
+/**
+ * Trigger index compaction.
+ *
+ * \param space ephemeral space.
+ * \param index_id index identifier.
+ *
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_index_compact_ephemeral(struct space *space, uint32_t index_id);
+
 struct iterator {
 	/**
 	 * Iterate to the next tuple.
diff --git a/src/box/lua/index.c b/src/box/lua/index.c
index ef89c39..79427e8 100644
--- a/src/box/lua/index.c
+++ b/src/box/lua/index.c
@@ -35,7 +35,9 @@
 #include "box/info.h"
 #include "box/lua/info.h"
 #include "box/lua/tuple.h"
-#include "box/lua/misc.h" /* lbox_encode_tuple_on_gc() */
+#include "box/lua/misc.h"
+#include "box/port.h"
+#include "box/box.h"
 
 /** {{{ box.index Lua library: access to spaces and indexes
  */
@@ -58,6 +60,30 @@ lbox_insert(lua_State *L)
 	return luaT_pushtupleornil(L, result);
 }
 
+/**
+ * Insert tuple into ephemeral space.
+ *
+ * @param L Lua stack to get space and tuple from.
+ *
+ * @retval not nil tuple that was inserted.
+ * @retval nil error.
+ */
+static int
+lbox_insert_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 2)
+		return luaL_error(L, "Usage space:insert(tuple)");
+
+	struct space *space = lua_checkephemeralspace(L, 1);
+	size_t tuple_len;
+	const char *tuple = lbox_encode_tuple_on_gc(L, 2, &tuple_len);
+
+	struct tuple *result;
+	if (box_ephemeral_insert(space, tuple, tuple + tuple_len, &result) != 0)
+		return luaT_error(L);
+	return luaT_pushtupleornil(L, result);
+}
+
 static int
 lbox_replace(lua_State *L)
 {
@@ -74,6 +100,31 @@ lbox_replace(lua_State *L)
 	return luaT_pushtupleornil(L, result);
 }
 
+/**
+ * Replace tuple from ephemeral space.
+ *
+ * @param L Lua stack to get space and tuple from.
+ *
+ * @retval not nil tuple that was inserted.
+ * @retval nil error.
+ */
+static int
+lbox_replace_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 2)
+		return luaL_error(L, "Usage space:replace(tuple)");
+
+	struct space *space = lua_checkephemeralspace(L, 1);
+	size_t tuple_len;
+	const char *tuple = lbox_encode_tuple_on_gc(L, 2, &tuple_len);
+
+	struct tuple *result;
+	if (box_ephemeral_replace(space, tuple, tuple + tuple_len,
+				  &result) != 0)
+		return luaT_error(L);
+	return luaT_pushtupleornil(L, result);
+}
+
 static int
 lbox_index_update(lua_State *L)
 {
@@ -96,6 +147,36 @@ lbox_index_update(lua_State *L)
 	return luaT_pushtupleornil(L, result);
 }
 
+/**
+ * Update tuple matched provided key.
+ *
+ * @param L Lua stack to get space, index_id, key and ops from.
+ *
+ * @retval not nil tuple - result of update.
+ * @retval nil error.
+ */
+static int
+lbox_index_update_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 4 || !lua_isnumber(L, 2) ||
+	    (!lua_istable(L, 3) && luaT_istuple(L, 3) == NULL) ||
+	    (!lua_istable(L, 4) && luaT_istuple(L, 4) == NULL))
+		return luaL_error(L, "Usage index:update(key, ops)");
+
+	struct space *space = lua_checkephemeralspace(L, 1);
+	uint32_t index_id = lua_tonumber(L, 2);
+	size_t key_len;
+	const char *key = lbox_encode_tuple_on_gc(L, 3, &key_len);
+	size_t ops_len;
+	const char *ops = lbox_encode_tuple_on_gc(L, 4, &ops_len);
+
+	struct tuple *result;
+	if (box_ephemeral_update(space, index_id, key, key + key_len,
+				 ops, ops + ops_len, 1, &result) != 0)
+		return luaT_error(L);
+	return luaT_pushtupleornil(L, result);
+}
+
 static int
 lbox_upsert(lua_State *L)
 {
@@ -117,6 +198,35 @@ lbox_upsert(lua_State *L)
 	return luaT_pushtupleornil(L, result);
 }
 
+/**
+ * Insert or update tuple from ephemeral space.
+ *
+ * @param L Lua stack to get space, tuple and ops from.
+ *
+ * @retval not nil tuple - result of upsert.
+ * @retval nil error.
+ */
+static int
+lbox_upsert_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 3 ||
+	    (!lua_istable(L, 2) && luaT_istuple(L, 2) == NULL) ||
+	    (!lua_istable(L, 3) && luaT_istuple(L, 3) == NULL))
+		return luaL_error(L, "Usage index:upsert(key, ops)");
+
+	struct space *space = lua_checkephemeralspace(L, 1);
+	size_t tuple_len;
+	const char *tuple = lbox_encode_tuple_on_gc(L, 2, &tuple_len);
+	size_t ops_len;
+	const char *ops = lbox_encode_tuple_on_gc(L, 3, &ops_len);
+
+	struct tuple *result;
+	if (box_ephemeral_upsert(space, 0, tuple, tuple + tuple_len,
+				 ops, ops + ops_len, 1, &result) != 0)
+		return luaT_error(L);
+	return luaT_pushtupleornil(L, result);
+}
+
 static int
 lbox_index_delete(lua_State *L)
 {
@@ -135,6 +245,73 @@ lbox_index_delete(lua_State *L)
 	return luaT_pushtupleornil(L, result);
 }
 
+/**
+ * Delete tuple matched the provided key.
+ *
+ * @param L Lua stack to get space, index_id and key from.
+ *
+ * @retval not nil tuple that was deleted.
+ * @retval nil error.
+ */
+static int
+lbox_index_delete_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 3 || !lua_isnumber(L, 2) ||
+	    (!lua_istable(L, 3) && luaT_istuple(L, 3) == NULL))
+		return luaL_error(L, "Usage index:delete(key)");
+
+	struct space *space = lua_checkephemeralspace(L, 1);
+	uint32_t index_id = lua_tonumber(L, 2);
+	size_t key_len;
+	const char *key = lbox_encode_tuple_on_gc(L, 3, &key_len);
+
+	struct tuple *result;
+	if (box_ephemeral_delete(space, index_id, key, key + key_len,
+				 &result) != 0)
+		return luaT_error(L);
+	return luaT_pushtupleornil(L, result);
+}
+
+/**
+ * Push number of element in the index on stack.
+ *
+ * @param L Lua stack to get space from.
+ *
+ * @retval number number number of return values.
+ */
+static int
+lbox_index_len_ephemeral(struct lua_State *L)
+{
+	if (lua_gettop(L) != 2 || !lua_isnumber(L, 2))
+		return luaL_error(L, "Usage: index:len()");
+
+	struct space *space = lua_checkephemeralspace(L, 1);
+	uint32_t index_id = lua_tonumber(L, 2);
+
+	lua_pushnumber(L, box_index_len_ephemeral(space, index_id));
+	return 1;
+}
+
+/**
+ * Push number of bytes used in memory by index on stack.
+ * 
+ * @param L Lua stack to get space from.
+ *
+ * @retval number number of return values.
+ */
+static int
+lbox_index_bsize_ephemeral(struct lua_State *L)
+{
+	if (lua_gettop(L) != 2 || !lua_isnumber(L, 2))
+		return luaL_error(L, "Usage: index:bsize()");
+
+	struct space *space = lua_checkephemeralspace(L, 1);
+	uint32_t index_id = lua_tonumber(L, 2);
+
+	lua_pushnumber(L, box_index_bsize_ephemeral(space, index_id));
+	return 1;
+}
+
 static int
 lbox_index_random(lua_State *L)
 {
@@ -152,6 +329,30 @@ lbox_index_random(lua_State *L)
 	return luaT_pushtupleornil(L, tuple);
 }
 
+/**
+ * Return a random tuple from the index.
+ *
+ * @param L Lua stack to get space and seed from.
+ *
+ * @retval not nil random tuple.
+ * @retval nil error.
+ */
+static int
+lbox_index_random_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 3 || !lua_isnumber(L, 2) || !lua_isnumber(L, 3))
+		return luaL_error(L, "Usage index:random(seed)");
+
+	struct space *space = lua_checkephemeralspace(L, 1);
+	uint32_t index_id = lua_tonumber(L, 2);
+	uint32_t rnd = lua_tonumber(L, 3);
+
+	struct tuple *tuple;
+	if (box_index_random_ephemeral(space, index_id, rnd, &tuple) != 0)
+		return luaT_error(L);
+	return luaT_pushtupleornil(L, tuple);
+}
+
 static int
 lbox_index_get(lua_State *L)
 {
@@ -169,6 +370,32 @@ lbox_index_get(lua_State *L)
 	return luaT_pushtupleornil(L, tuple);
 }
 
+/**
+ * Return a tuple from the index by given key.
+ *
+ * @param L Lua stack to get space and key from.
+ *
+ * @retval not nil matched tuple.
+ * @retval nil error.
+ */
+static int
+lbox_index_get_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 3 || !lua_isnumber(L, 2))
+		return luaL_error(L, "Usage index:get(key)");
+
+	struct space *space = lua_checkephemeralspace(L, 1);
+	uint32_t index_id = lua_tonumber(L, 2);
+	size_t key_len;
+	const char *key = lbox_encode_tuple_on_gc(L, 3, &key_len);
+
+	struct tuple *tuple;
+	if (box_index_get_ephemeral(space, index_id, key, key + key_len,
+				    &tuple) != 0)
+		return luaT_error(L);
+	return luaT_pushtupleornil(L, tuple);
+}
+
 static int
 lbox_index_min(lua_State *L)
 {
@@ -186,6 +413,32 @@ lbox_index_min(lua_State *L)
 	return luaT_pushtupleornil(L, tuple);
 }
 
+/**
+ * Return first (minimal) tuple from the index matched provided
+ * key.
+ *
+ * @param L Lua stack to get space and key from.
+ *
+ * @retval not nil matched tuple.
+ * @retval nil error.
+ */
+static int
+lbox_index_min_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 3 || !lua_isnumber(L, 2))
+		return luaL_error(L, "Usage index:min(key)");
+	struct space *space = lua_checkephemeralspace(L, 1);
+	uint32_t index_id = lua_tonumber(L, 2);
+	size_t key_len;
+	const char *key = lbox_encode_tuple_on_gc(L, 3, &key_len);
+
+	struct tuple *tuple;
+	if (box_index_min_ephemeral(space, index_id, key, key + key_len,
+				    &tuple) != 0)
+		return luaT_error(L);
+	return luaT_pushtupleornil(L, tuple);
+}
+
 static int
 lbox_index_max(lua_State *L)
 {
@@ -203,6 +456,33 @@ lbox_index_max(lua_State *L)
 	return luaT_pushtupleornil(L, tuple);
 }
 
+/**
+ * Return last (maximal) tuple from the index matched provided
+ * key.
+ *
+ * @param L Lua stack to get space and key from.
+ *
+ * @retval not nil matched tuple.
+ * @retval nil error.
+ */
+static int
+lbox_index_max_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 3 || !lua_isnumber(L, 2))
+		return luaL_error(L, "Usage index:max(key)");
+
+	struct space *space = lua_checkephemeralspace(L, 1);
+	uint32_t index_id = lua_tonumber(L, 2);
+	size_t key_len;
+	const char *key = lbox_encode_tuple_on_gc(L, 3, &key_len);
+
+	struct tuple *tuple;
+	if (box_index_max_ephemeral(space, index_id, key, key + key_len,
+				    &tuple) != 0)
+		return luaT_error(L);
+	return luaT_pushtupleornil(L, tuple);
+}
+
 static int
 lbox_index_count(lua_State *L)
 {
@@ -226,6 +506,65 @@ lbox_index_count(lua_State *L)
 	return 1;
 }
 
+/**
+ * Count tuples matched provided key and push this number on
+ * stack.
+ *
+ * @param L Lua stack to get space and key from.
+ *
+ * @retval number number of return values.
+ */
+static int
+lbox_index_count_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 4 || !lua_isnumber(L, 2) || !lua_isnumber(L, 3))
+		return luaL_error(L, "Usage index:count(type, key)");
+
+	struct space *space = lua_checkephemeralspace(L, 1);
+	uint32_t index_id = lua_tonumber(L, 2);
+	uint32_t iterator = lua_tonumber(L, 3);
+	size_t key_len;
+	const char *key = lbox_encode_tuple_on_gc(L, 4, &key_len);
+
+	ssize_t count = box_index_count_ephemeral(space, index_id, iterator,
+						  key, key + key_len);
+	if (count == -1)
+		return luaT_error(L);
+	lua_pushinteger(L, count);
+	return 1;
+}
+
+/**
+ * Select tuples matched conditions and push them on stack as
+ * table.
+ *
+ * @param L Lua stack to get space, iterator, offset, limit and
+ * key from.
+ *
+ * @retval number number of return values.
+ */
+static int
+lbox_index_select_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 5) {
+		return luaL_error(L, "Usage index:select(iterator, offset, "\
+				  "limit, key)");
+	}
+	struct space *space = lua_checkephemeralspace(L, 1);
+	int iterator = luaL_checknumber(L, 2);
+	uint32_t offset = luaL_checknumber(L, 3);
+	uint32_t limit = luaL_checknumber(L, 4);
+	size_t key_len;
+	const char *key = lbox_encode_tuple_on_gc(L, 5, &key_len);
+	struct port port;
+	if (box_ephemeral_select(space, 0, iterator, offset, limit,
+				 key, key + key_len, &port) != 0)
+		return luaT_error(L);
+	lbox_port_to_table(L, &port);
+	port_destroy(&port);
+	return 1; /* lua table with tuples */
+}
+
 static void
 box_index_init_iterator_types(struct lua_State *L, int idx)
 {
@@ -264,6 +603,40 @@ lbox_index_iterator(lua_State *L)
 	return 1;
 }
 
+/**
+ * Creates iterator for ephemeral space according to given type
+ * and pushes it on stack.
+ *
+ * @param L Lua stack to get space, index_id, iterator type and
+ * encoded with msgpack key from.
+ *
+ * @retval number number of return values.
+ */
+static int
+lbox_index_iterator_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 4 || !lua_isnumber(L, 2) || !lua_isnumber(L, 3))
+		return luaL_error(L, "Usage index:iterator(type, key)");
+
+	struct space *space = lua_checkephemeralspace(L, 1);
+	uint32_t index_id = lua_tonumber(L, 2);
+	uint32_t iterator = lua_tonumber(L, 3);
+	size_t mpkey_len;
+	/* Key encoded by Lua */
+	const char *mpkey = lua_tolstring(L, 4, &mpkey_len);
+	struct iterator *it =
+		box_index_iterator_ephemeral(space, index_id, iterator, mpkey,
+					     mpkey + mpkey_len);
+	if (it == NULL)
+		return luaT_error(L);
+
+	assert(CTID_STRUCT_ITERATOR_REF != 0);
+	struct iterator **ptr =
+		(struct iterator **)luaL_pushcdata(L, CTID_STRUCT_ITERATOR_REF);
+	*ptr = it; /* NULL handled by Lua, gc also set by Lua */
+	return 1;
+}
+
 static int
 lbox_iterator_next(lua_State *L)
 {
@@ -328,6 +701,24 @@ lbox_index_compact(lua_State *L)
 	return 0;
 }
 
+/**
+ * Run index compaction.
+ *
+ * @param L Lua stack to get space and key from.
+ */
+static int
+lbox_index_compact_ephemeral(lua_State *L)
+{
+	if (lua_gettop(L) != 2 || !lua_isnumber(L, 2))
+		return luaL_error(L, "Usage index:compact()");
+	struct space *space = lua_checkephemeralspace(L, 1);
+	uint32_t index_id = lua_tonumber(L, 2);
+
+	if (box_index_compact_ephemeral(space, index_id) != 0)
+		return luaT_error(L);
+	return 0;
+}
+
 /* }}} */
 
 void
@@ -340,6 +731,12 @@ box_lua_index_init(struct lua_State *L)
 	CTID_STRUCT_ITERATOR_REF = luaL_ctypeid(L, "struct iterator&");
 	assert(CTID_STRUCT_ITERATOR_REF != 0);
 
+	lua_getfield(L, LUA_GLOBALSINDEX, "box");
+	lua_getfield(L, -1, "internal");
+	lua_newtable(L);
+	lua_setfield(L, -2, "index_ephemeral_methods");
+	lua_pop(L, 2); /* box, internal */
+
 	static const struct luaL_Reg indexlib [] = {
 		{NULL, NULL}
 	};
@@ -370,4 +767,27 @@ box_lua_index_init(struct lua_State *L)
 
 	luaL_register(L, "box.internal", boxlib_internal);
 	lua_pop(L, 1);
+
+	static const struct luaL_Reg ephemeral_index_lib[] = {
+		{"insert", lbox_insert_ephemeral},
+		{"replace",  lbox_replace_ephemeral},
+		{"update", lbox_index_update_ephemeral},
+		{"upsert",  lbox_upsert_ephemeral},
+		{"delete",  lbox_index_delete_ephemeral},
+		{"len",  lbox_index_len_ephemeral},
+		{"bsize", lbox_index_bsize_ephemeral},
+		{"random", lbox_index_random_ephemeral},
+		{"select",  lbox_index_select_ephemeral},
+		{"get",  lbox_index_get_ephemeral},
+		{"min", lbox_index_min_ephemeral},
+		{"max", lbox_index_max_ephemeral},
+		{"count", lbox_index_count_ephemeral},
+		{"iterator", lbox_index_iterator_ephemeral},
+		{"compact", lbox_index_compact_ephemeral},
+		{NULL, NULL}
+	};
+
+	luaL_register(L, "box.internal.index_ephemeral_methods",
+		      ephemeral_index_lib);
+	lua_pop(L, 1);
 }
diff --git a/src/box/lua/misc.cc b/src/box/lua/misc.cc
index 13ca18c..32ffb20 100644
--- a/src/box/lua/misc.cc
+++ b/src/box/lua/misc.cc
@@ -70,11 +70,7 @@ lua_checkephemeralspace(struct lua_State *L, int idx)
 	return *(struct space **) data;
 }
 
-/* }}} */
-
-/** {{{ Lua/C implementation of index:select(): used only by Vinyl **/
-
-static inline void
+void
 lbox_port_to_table(lua_State *L, struct port *port_base)
 {
 	struct port_tuple *port = port_tuple(port_base);
@@ -87,6 +83,10 @@ lbox_port_to_table(lua_State *L, struct port *port_base)
 	}
 }
 
+/* }}} */
+
+/** {{{ Lua/C implementation of index:select(): used only by Vinyl **/
+
 static int
 lbox_select(lua_State *L)
 {
diff --git a/src/box/lua/misc.h b/src/box/lua/misc.h
index 6162baa..6859142 100644
--- a/src/box/lua/misc.h
+++ b/src/box/lua/misc.h
@@ -54,6 +54,15 @@ lbox_encode_tuple_on_gc(struct lua_State *L, int idx, size_t *p_len);
 struct space *
 lua_checkephemeralspace(struct lua_State *L, int idx);
 
+/**
+ * Transform given port to Lua table.
+ *
+ * @param L Lua stack to push table to.
+ * @param port_base port to transform.
+ */
+void
+lbox_port_to_table(lua_State *L, struct port *port_base);
+
 void
 box_lua_misc_init(struct lua_State *L);
 
diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index cc8c66b..3b40401 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -1098,6 +1098,8 @@ local index_new_ephemeral = box.internal.space.index_new_ephemeral
 box.internal.space.index_new_ephemeral = nil
 local index_delete_ephemeral = box.internal.space.index_delete_ephemeral
 box.internal.space.index_delete_ephemeral = nil
+local index_ephemeral_methods = box.internal.index_ephemeral_methods
+box.internal.index_ephemeral_methods = nil
 local index_ephemeral_mt = {}
 
 local create_ephemeral_index = function(space, name, options)
@@ -1234,6 +1236,13 @@ local function check_index_arg(index, method)
         error(string.format(fmt, method, method))
     end
 end
+local function check_index_arg_ephemeral(index, method)
+    if type(index) ~= 'table' or type(index.space) ~= 'table' or
+       param_type(index.space.space) ~= 'cdata' then
+        local fmt = 'Use index:%s(...) instead of index.%s(...)'
+        error(string.format(fmt, method, method))
+    end
+end
 box.internal.check_index_arg = check_index_arg -- for net.box
 
 -- Helper function to check that space have primary key and return it
@@ -1642,6 +1651,81 @@ space_mt.__index = space_mt
 
 -- Metatable for primary index of ephemeral space
 index_ephemeral_mt.drop = drop_ephemeral_index
+index_ephemeral_mt.update = function(index, key, ops)
+    check_index_arg_ephemeral(index, 'update')
+    key = keify(key)
+    return index_ephemeral_methods.update(index.space.space, index.id, key, ops)
+end
+index_ephemeral_mt.delete = function(index, key)
+    check_index_arg_ephemeral(index, 'delete')
+    key = keify(key)
+    return index_ephemeral_methods.delete(index.space.space, index.id, key)
+end
+index_ephemeral_mt.len = function(index)
+    check_index_arg_ephemeral(index, 'len')
+    local ret = index_ephemeral_methods.len(index.space.space, index.id)
+    if ret == -1 then
+        box.error()
+    end
+    return tonumber(ret)
+end
+index_ephemeral_mt.__len = index_ephemeral_mt.len
+index_ephemeral_mt.bsize = function(index)
+    check_index_arg_ephemeral(index, 'bsize')
+    local ret = index_ephemeral_methods.bsize(index.space.space, index.id)
+    if ret == -1 then
+        box.error()
+    end
+    return tonumber(ret)
+end
+index_ephemeral_mt.random = function(index, rnd)
+    check_index_arg_ephemeral(index, 'random')
+    rnd = rnd or math.random()
+    return index_ephemeral_methods.random(index.space.space, index.id, rnd);
+end
+index_ephemeral_mt.get = function(index, key)
+    check_index_arg_ephemeral(index, 'get')
+    key = keify(key)
+    return index_ephemeral_methods.get(index.space.space, index.id, key)
+end
+index_ephemeral_mt.select = function(index, key, opts)
+    check_index_arg_ephemeral(index, 'select')
+    local key = keify(key)
+    local iterator, offset, limit = check_select_opts(opts, #key == 0)
+    return index_ephemeral_methods.select(index.space.space, iterator, offset, limit, key)
+end
+index_ephemeral_mt.min = function(index, key)
+    check_index_arg_ephemeral(index, 'min')
+    key = keify(key)
+    return index_ephemeral_methods.min(index.space.space, index.id, key);
+end
+index_ephemeral_mt.max = function(index, key)
+    check_index_arg_ephemeral(index, 'max')
+    key = keify(key)
+    return index_ephemeral_methods.max(index.space.space, index.id, key);
+end
+index_ephemeral_mt.count = function(index, key, opts)
+    check_index_arg_ephemeral(index, 'count')
+    key = keify(key)
+    local itype = check_iterator_type(opts, #key == 0);
+    return index_ephemeral_methods.count(index.space.space, index.id, itype,
+                                         key);
+end
+index_ephemeral_mt.pairs = function(index, key, opts)
+    check_index_arg_ephemeral(index, 'pairs')
+    key = keify(key)
+    local itype = check_iterator_type(opts, #key == 0);
+    local keymp = msgpack.encode(key)
+    local keybuf = ffi.string(keymp, #keymp)
+    local cdata = index_ephemeral_methods.iterator(index.space.space, index.id,
+                                                   itype, keymp);
+    return fun.wrap(iterator_gen_luac, keybuf,
+        ffi.gc(cdata, builtin.box_iterator_free))
+end
+index_ephemeral_mt.compact = function(index)
+    check_index_arg_ephemeral(index, 'compact')
+    return index_ephemeral_methods.compact(index.space.space, index.id)
+end
 index_ephemeral_mt.__index = index_ephemeral_mt
 
 -- Metatable for ephemeral space
@@ -1665,9 +1749,81 @@ space_ephemeral_mt.bsize = function(space)
     check_ephemeral_space_arg(space, 'bsize')
     return builtin.space_bsize(space.space)
 end
+space_ephemeral_mt.auto_increment = function(space, tuple)
+    check_ephemeral_space_arg(space, 'auto_increment')
+    local max_tuple = check_primary_index(space):max()
+    local max = 0
+    if max_tuple ~= nil then
+        max = max_tuple[1]
+    end
+    table.insert(tuple, 1, max + 1)
+    return space:insert(tuple)
+end
+space_ephemeral_mt.insert = function(space, tuple)
+    check_ephemeral_space_arg(space, 'insert')
+    return index_ephemeral_methods.insert(space.space, tuple);
+end
+space_ephemeral_mt.replace = function(space, tuple)
+    check_ephemeral_space_arg(space, 'replace')
+    return index_ephemeral_methods.replace(space.space, tuple);
+end
+space_ephemeral_mt.upsert = function(space, tuple_key, ops, deprecated)
+    check_ephemeral_space_arg(space, 'upsert')
+    if deprecated ~= nil then
+        local msg = "Error: extra argument in upsert call: "
+        msg = msg .. tostring(deprecated)
+        msg = msg .. ". Usage :upsert(tuple, operations)"
+        box.error(box.error.PROC_LUA, msg)
+    end
+    return index_ephemeral_methods.upsert(space.space, tuple_key, ops);
+end
+space_ephemeral_mt.pairs = function(space, key, opts)
+    check_ephemeral_space_arg(space, 'pairs')
+    local pk = space.index[0]
+    if pk == nil then
+        -- empty space without indexes, return empty iterator
+        return fun.iter({})
+    end
+    return pk:pairs(key, opts)
+end
+space_ephemeral_mt.__pairs = space_ephemeral_mt.pairs -- Lua 5.2 compatibility
+space_ephemeral_mt.__ipairs = space_ephemeral_mt.pairs -- Lua 5.2 compatibility
+space_ephemeral_mt.truncate = function(space)
+    check_ephemeral_space_arg(space, 'truncate')
+    local index = space.index[0]
+    local name = index.name
+    local options = index.options
+    index:drop()
+    space:create_index(name, options)
+end
 space_ephemeral_mt.create_index = create_ephemeral_index
 space_ephemeral_mt.drop = box.schema.space.drop_ephemeral
 space_ephemeral_mt.__index = space_ephemeral_mt
+space_ephemeral_mt.put = space_ephemeral_methods.replace
+space_ephemeral_mt.update = function(space, key, ops)
+    check_ephemeral_space_arg(space, 'update')
+    return check_primary_index(space):update(key, ops)
+end
+space_ephemeral_mt.delete = function(space, key)
+    check_ephemeral_space_arg(space, 'delete')
+    return check_primary_index(space):delete(key)
+end
+space_ephemeral_mt.get = function(space, key)
+    check_ephemeral_space_arg(space, 'get')
+    return check_primary_index(space):get(key)
+end
+space_ephemeral_mt.select = function(space, key, opts)
+    check_ephemeral_space_arg(space, 'select')
+    return check_primary_index(space):select(key, opts)
+end
+space_ephemeral_mt.count = function(space, key, opts)
+    check_ephemeral_space_arg(space, 'count')
+    return check_primary_index(space):count(key, opts)
+end
+space_ephemeral_mt.len = function(space)
+    check_ephemeral_space_arg(space, 'len')
+    return check_primary_index(space):len()
+end
 
 box.schema.index_mt = base_index_mt
 box.schema.memtx_index_mt = memtx_index_mt
diff --git a/test/box/ephemeral_space.result b/test/box/ephemeral_space.result
index 4ef395f..3137f63 100644
--- a/test/box/ephemeral_space.result
+++ b/test/box/ephemeral_space.result
@@ -135,7 +135,7 @@ s:frommap({ddd = 1, aaa = 2, ccc = 3, eee = 4})
 ...
 s:frommap()
 ---
-- error: 'builtin/box/schema.lua:1659: Usage: space:frommap(map, opts)'
+- error: 'builtin/box/schema.lua:1743: Usage: space:frommap(map, opts)'
 ...
 s:frommap({})
 ---
@@ -245,3 +245,803 @@ i = s:create_index('a', {type = 'bitset', parts = {1, 'unsigned', 2, 'unsigned'}
 - error: 'Can''t create or modify index ''a'' in space ''ephemeral'': primary key
     must be unique'
 ...
+-- Ephemeral space: methods
+s = box.schema.space.create_ephemeral({field_count = 3})
+---
+...
+i = s:create_index('a')
+---
+...
+s:insert{1}
+---
+- error: Tuple field count 1 does not match space field count 3
+...
+s:insert{2,2,2}
+---
+- [2, 2, 2]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:insert{'1'}
+---
+- ['1']
+...
+s:get{'1'}
+---
+- ['1']
+...
+s:insert{'1'}
+---
+- error: Duplicate key exists in unique index 'a' in space 'ephemeral'
+...
+s:insert{1}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected string'
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:insert{1}
+---
+- [1]
+...
+s:get{1}
+---
+- [1]
+...
+s:insert{1}
+---
+- error: Duplicate key exists in unique index 'a' in space 'ephemeral'
+...
+s:insert{'1'}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:replace{'1'}
+---
+- ['1']
+...
+s:get{'1'}
+---
+- ['1']
+...
+s:replace{'1'}
+---
+- ['1']
+...
+s:replace{1}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected string'
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{1}
+---
+- [1]
+...
+s:get{1}
+---
+- [1]
+...
+s:replace{1}
+---
+- [1]
+...
+s:replace{'1'}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:replace{'1'}
+---
+- ['1']
+...
+s:get{'1'}
+---
+- ['1']
+...
+s:replace{'1'}
+---
+- ['1']
+...
+s:replace{1}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected string'
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:upsert({1, 0}, {{'+', 2, 1}})
+---
+...
+s:get{1}
+---
+- [1, 0]
+...
+s:upsert({1, 0}, {{'+', 2, 1}})
+---
+...
+s:get{1}
+---
+- [1, 1]
+...
+s:upsert({1, 0}, {{'+', 1, 1}})
+---
+...
+s:get{1}
+---
+- [1, 1]
+...
+s:get{2}
+---
+...
+s:upsert({'1'}, {{'!', 2, 100}})
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
+...
+s:upsert({1}, {{'a', 2, 100}})
+---
+- error: Unknown UPDATE operation
+...
+i:drop()
+---
+...
+i = s:create_index('a')
+---
+...
+s:insert{1, 2, 3, 4, 5}
+---
+- [1, 2, 3, 4, 5]
+...
+s:update({1}, {{'#', 1, 1}})
+---
+- error: Attempt to modify a tuple field which is part of index 'a' in space 'ephemeral'
+...
+s:update({1}, {{'#', 1, "only one record please"}})
+---
+- error: 'Argument type in operation ''#'' on field 1 does not match field type: expected
+    a number of fields to delete'
+...
+i:drop()
+---
+...
+i = s:create_index('a')
+---
+...
+s:insert{1, 0}
+---
+- [1, 0]
+...
+s:update(1, {{'+', 2, 10}})
+---
+- [1, 10]
+...
+s:update(1, {{'+', 2, 15}})
+---
+- [1, 25]
+...
+s:update(1, {{'-', 2, 5}})
+---
+- [1, 20]
+...
+s:update(1, {{'-', 2, 20}})
+---
+- [1, 0]
+...
+s:update(1, {{'|', 2, 0x9}})
+---
+- [1, 9]
+...
+s:update(1, {{'|', 2, 0x6}})
+---
+- [1, 15]
+...
+s:update(1, {{'&', 2, 0xabcde}})
+---
+- [1, 14]
+...
+s:update(1, {{'&', 2, 0x2}})
+---
+- [1, 2]
+...
+s:update(1, {{'^', 2, 0xa2}})
+---
+- [1, 160]
+...
+s:update(1, {{'^', 2, 0xa2}})
+---
+- [1, 2]
+...
+i:drop()
+---
+...
+i = s:create_index('a')
+---
+...
+s:insert{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+---
+- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
+...
+s:update({0}, {{'#', 42, 1}})
+---
+- error: Field 42 was not found in the tuple
+...
+s:update({0}, {{'#', 4, 'abirvalg'}})
+---
+- error: 'Argument type in operation ''#'' on field 4 does not match field type: expected
+    a number of fields to delete'
+...
+s:update({0}, {{'#', 2, 1}, {'#', 4, 2}, {'#', 6, 1}})
+---
+- [0, 2, 3, 6, 7, 9, 10, 11, 12, 13, 14, 15]
+...
+s:update({0}, {{'#', 4, 3}})
+---
+- [0, 2, 3, 10, 11, 12, 13, 14, 15]
+...
+s:update({0}, {{'#', 5, 123456}})
+---
+- [0, 2, 3, 10]
+...
+s:update({0}, {{'#', 3, 4294967295}})
+---
+- [0, 2]
+...
+s:update({0}, {{'#', 2, 0}})
+---
+- error: 'Field 2 UPDATE error: cannot delete 0 fields'
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:insert{'1'}
+---
+- ['1']
+...
+s:insert{'5'}
+---
+- ['5']
+...
+s:insert{'6'}
+---
+- ['6']
+...
+s:insert{'11'}
+---
+- ['11']
+...
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['1']
+  - ['11']
+  - ['5']
+  - ['6']
+...
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['1']
+  - ['11']
+  - ['5']
+  - ['6']
+...
+t = {} for state, v in i:pairs('5', {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['5']
+  - ['6']
+...
+t = {} for state, v in i:pairs('5', {iterator = 'GT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['6']
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['6']
+  - ['5']
+  - ['11']
+  - ['1']
+...
+t = {} for state, v in i:pairs('5', {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['5']
+  - ['11']
+  - ['1']
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['6']
+  - ['5']
+  - ['11']
+  - ['1']
+...
+t = {} for state, v in i:pairs('5', {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['11']
+  - ['1']
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:insert{1}
+---
+- [1]
+...
+s:insert{5}
+---
+- [5]
+...
+s:insert{11}
+---
+- [11]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1]
+  - [5]
+  - [11]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1]
+  - [5]
+  - [11]
+...
+t = {} for state, v in i:pairs(5, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [5]
+  - [11]
+...
+t = {} for state, v in i:pairs(5, {iterator = 'GT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [11]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [11]
+  - [5]
+  - [1]
+...
+t = {} for state, v in i:pairs(5, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [5]
+  - [1]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [11]
+  - [5]
+  - [1]
+...
+t = {} for state, v in i:pairs(5, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1]
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+---
+...
+s:insert{1, 1}
+---
+- [1, 1]
+...
+s:insert{5, 5}
+---
+- [5, 5]
+...
+s:insert{11, 11}
+---
+- [11, 11]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1, 1]
+  - [5, 5]
+  - [11, 11]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1, 1]
+  - [5, 5]
+  - [11, 11]
+...
+t = {} for state, v in i:pairs({5, 5}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [5, 5]
+  - [11, 11]
+...
+t = {} for state, v in i:pairs({5, 5}, {iterator = 'GT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [11, 11]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [11, 11]
+  - [5, 5]
+  - [1, 1]
+...
+t = {} for state, v in i:pairs({5, 5}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [5, 5]
+  - [1, 1]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [11, 11]
+  - [5, 5]
+  - [1, 1]
+...
+t = {} for state, v in i:pairs({5, 5}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1, 1]
+...
+i:drop()
+---
+...
+i = s:create_index('a')
+---
+...
+s:auto_increment{1}
+---
+- [1, 1]
+...
+s:auto_increment{2}
+---
+- [2, 2]
+...
+s:auto_increment{3}
+---
+- [3, 3]
+...
+s:pairs(2, 'GE'):totable()
+---
+- - [2, 2]
+  - [3, 3]
+...
+i:count({2}, 'GT')
+---
+- 1
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{1}
+---
+- [1]
+...
+s:replace{2}
+---
+- [2]
+...
+s:delete{1}
+---
+- [1]
+...
+s:delete{2}
+---
+- [2]
+...
+s:select()
+---
+- []
+...
+i:drop()
+---
+...
+s:drop()
+---
+...
+test_run = require('test_run').new()
+---
+...
+utils = dofile('utils.lua')
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+idx = s:create_index('a')
+---
+...
+for i = 1, 13 do s:insert{ i, string.rep('x', i) } end
+---
+...
+s:len()
+---
+- 13
+...
+s:bsize()
+---
+- 130
+...
+utils.space_bsize(s)
+---
+- 130
+...
+for i = 1, 13, 2 do s:delete{ i } end
+---
+...
+s:len()
+---
+- 6
+...
+s:bsize()
+---
+- 60
+...
+utils.space_bsize(s)
+---
+- 60
+...
+for i = 2, 13, 2 do s:update( { i }, {{ ":", 2, i, 0, string.rep('y', i) }} ) end
+---
+...
+s:len()
+---
+- 6
+...
+s:bsize()
+---
+- 102
+...
+utils.space_bsize(s)
+---
+- 102
+...
+idx:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:insert({'1', "AAAA"})
+---
+- ['1', 'AAAA']
+...
+s:insert({'2', "AAAA"})
+---
+- ['2', 'AAAA']
+...
+s:insert({'3', "AAAA"})
+---
+- ['3', 'AAAA']
+...
+s:insert({'4', "AAAA"})
+---
+- ['4', 'AAAA']
+...
+i:select()
+---
+- - ['1', 'AAAA']
+  - ['2', 'AAAA']
+  - ['3', 'AAAA']
+  - ['4', 'AAAA']
+...
+i:max('2')
+---
+- ['2', 'AAAA']
+...
+i:min('2')
+---
+- ['2', 'AAAA']
+...
+i:count('2')
+---
+- 1
+...
+i:max()
+---
+- ['4', 'AAAA']
+...
+i:min()
+---
+- ['1', 'AAAA']
+...
+i:count()
+---
+- 4
+...
+s:insert({'20', "AAAA"})
+---
+- ['20', 'AAAA']
+...
+s:insert({'30', "AAAA"})
+---
+- ['30', 'AAAA']
+...
+s:insert({'40', "AAAA"})
+---
+- ['40', 'AAAA']
+...
+s:select()
+---
+- - ['1', 'AAAA']
+  - ['2', 'AAAA']
+  - ['20', 'AAAA']
+  - ['3', 'AAAA']
+  - ['30', 'AAAA']
+  - ['4', 'AAAA']
+  - ['40', 'AAAA']
+...
+i:max('15')
+---
+...
+i:min('15')
+---
+...
+s:count('15')
+---
+- 0
+...
+i:max()
+---
+- ['40', 'AAAA']
+...
+i:min()
+---
+- ['1', 'AAAA']
+...
+s:count()
+---
+- 7
+...
+s:insert({'-2', "AAAA"})
+---
+- ['-2', 'AAAA']
+...
+s:insert({'-3', "AAAA"})
+---
+- ['-3', 'AAAA']
+...
+s:insert({'-4', "AAAA"})
+---
+- ['-4', 'AAAA']
+...
+i:select()
+---
+- - ['-2', 'AAAA']
+  - ['-3', 'AAAA']
+  - ['-4', 'AAAA']
+  - ['1', 'AAAA']
+  - ['2', 'AAAA']
+  - ['20', 'AAAA']
+  - ['3', 'AAAA']
+  - ['30', 'AAAA']
+  - ['4', 'AAAA']
+  - ['40', 'AAAA']
+...
+i:max('0')
+---
+...
+i:min('0')
+---
+...
+i:count('0')
+---
+- 0
+...
+i:max()
+---
+- ['40', 'AAAA']
+...
+i:min()
+---
+- ['-2', 'AAAA']
+...
+i:count()
+---
+- 10
+...
+s:drop()
+---
+...
+test_run:cmd("restart server default")
diff --git a/test/box/ephemeral_space.test.lua b/test/box/ephemeral_space.test.lua
index 93211c6..4c2bf22 100644
--- a/test/box/ephemeral_space.test.lua
+++ b/test/box/ephemeral_space.test.lua
@@ -89,3 +89,243 @@ i:drop()
 i = s:create_index('a', {id = 10})
 
 i = s:create_index('a', {type = 'bitset', parts = {1, 'unsigned', 2, 'unsigned'}})
+
+-- Ephemeral space: methods
+
+s = box.schema.space.create_ephemeral({field_count = 3})
+i = s:create_index('a')
+
+s:insert{1}
+s:insert{2,2,2}
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:insert{'1'}
+s:get{'1'}
+s:insert{'1'}
+s:insert{1}
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:insert{1}
+s:get{1}
+s:insert{1}
+s:insert{'1'}
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:replace{'1'}
+s:get{'1'}
+s:replace{'1'}
+s:replace{1}
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{1}
+s:get{1}
+s:replace{1}
+s:replace{'1'}
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:replace{'1'}
+s:get{'1'}
+s:replace{'1'}
+s:replace{1}
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:upsert({1, 0}, {{'+', 2, 1}})
+s:get{1}
+s:upsert({1, 0}, {{'+', 2, 1}})
+s:get{1}
+s:upsert({1, 0}, {{'+', 1, 1}})
+s:get{1}
+s:get{2}
+
+s:upsert({'1'}, {{'!', 2, 100}})
+s:upsert({1}, {{'a', 2, 100}})
+
+i:drop()
+
+i = s:create_index('a')
+s:insert{1, 2, 3, 4, 5}
+s:update({1}, {{'#', 1, 1}})
+s:update({1}, {{'#', 1, "only one record please"}})
+i:drop()
+
+i = s:create_index('a')
+s:insert{1, 0}
+s:update(1, {{'+', 2, 10}})
+s:update(1, {{'+', 2, 15}})
+s:update(1, {{'-', 2, 5}})
+s:update(1, {{'-', 2, 20}})
+s:update(1, {{'|', 2, 0x9}})
+s:update(1, {{'|', 2, 0x6}})
+s:update(1, {{'&', 2, 0xabcde}})
+s:update(1, {{'&', 2, 0x2}})
+s:update(1, {{'^', 2, 0xa2}})
+s:update(1, {{'^', 2, 0xa2}})
+i:drop()
+
+i = s:create_index('a')
+s:insert{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+s:update({0}, {{'#', 42, 1}})
+s:update({0}, {{'#', 4, 'abirvalg'}})
+s:update({0}, {{'#', 2, 1}, {'#', 4, 2}, {'#', 6, 1}})
+s:update({0}, {{'#', 4, 3}})
+s:update({0}, {{'#', 5, 123456}})
+s:update({0}, {{'#', 3, 4294967295}})
+s:update({0}, {{'#', 2, 0}})
+i:drop()
+
+
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:insert{'1'}
+s:insert{'5'}
+s:insert{'6'}
+s:insert{'11'}
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs('5', {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs('5', {iterator = 'GT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs('5', {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs('5', {iterator = 'LT'}) do table.insert(t, v) end
+t
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:insert{1}
+s:insert{5}
+s:insert{11}
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(5, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(5, {iterator = 'GT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(5, {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(5, {iterator = 'LT'}) do table.insert(t, v) end
+t
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+s:insert{1, 1}
+s:insert{5, 5}
+s:insert{11, 11}
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({5, 5}, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({5, 5}, {iterator = 'GT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({5, 5}, {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({5, 5}, {iterator = 'LT'}) do table.insert(t, v) end
+t
+i:drop()
+
+i = s:create_index('a')
+s:auto_increment{1}
+s:auto_increment{2}
+s:auto_increment{3}
+s:pairs(2, 'GE'):totable()
+i:count({2}, 'GT')
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{1}
+s:replace{2}
+s:delete{1}
+s:delete{2}
+s:select()
+i:drop()
+s:drop()
+
+test_run = require('test_run').new()
+utils = dofile('utils.lua')
+
+s = box.schema.space.create_ephemeral()
+idx = s:create_index('a')
+for i = 1, 13 do s:insert{ i, string.rep('x', i) } end
+s:len()
+s:bsize()
+utils.space_bsize(s)
+
+for i = 1, 13, 2 do s:delete{ i } end
+s:len()
+s:bsize()
+utils.space_bsize(s)
+
+for i = 2, 13, 2 do s:update( { i }, {{ ":", 2, i, 0, string.rep('y', i) }} ) end
+s:len()
+s:bsize()
+utils.space_bsize(s)
+idx:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:insert({'1', "AAAA"})
+s:insert({'2', "AAAA"})
+s:insert({'3', "AAAA"})
+s:insert({'4', "AAAA"})
+
+i:select()
+i:max('2')
+i:min('2')
+i:count('2')
+i:max()
+i:min()
+i:count()
+
+s:insert({'20', "AAAA"})
+s:insert({'30', "AAAA"})
+s:insert({'40', "AAAA"})
+
+s:select()
+i:max('15')
+i:min('15')
+s:count('15')
+i:max()
+i:min()
+s:count()
+
+s:insert({'-2', "AAAA"})
+s:insert({'-3', "AAAA"})
+s:insert({'-4', "AAAA"})
+
+i:select()
+i:max('0')
+i:min('0')
+i:count('0')
+i:max()
+i:min()
+i:count()
+
+s:drop()
+
+test_run:cmd("restart server default")
diff --git a/test/engine/iterator.result b/test/engine/iterator.result
index f39a15a..9e39a32 100644
--- a/test/engine/iterator.result
+++ b/test/engine/iterator.result
@@ -4213,7 +4213,7 @@ s:replace{35}
 ...
 state, value = gen(param,state)
 ---
-- error: 'builtin/box/schema.lua:1180: usage: next(param, state)'
+- error: 'builtin/box/schema.lua:1182: usage: next(param, state)'
 ...
 value
 ---
-- 
2.7.4





More information about the Tarantool-patches mailing list