From c64a02eb642dbdf47ea98cc0bb2486e77b24c194 Mon Sep 17 00:00:00 2001
From: Konstantin Osipov <kostja@tarantool.org>
Date: Thu, 5 Sep 2013 18:20:38 +0400
Subject: [PATCH] Convert errinj.test to space-by-name usage.

Modify 'space' object contents when altering it, rather
than create a new Lua table.
In Lua, when saving a copy of a table in a local variable
a shallow copy is saved, in other words, table variables
initialized from each other share state.

Make use of this feature in the following scenario:

space = box.schema.create_space()
space:create_index() -- modifies box.space[id] which 'space' is a
shared ptr to
space.index[0] - great, space.index[0] has the added index.
---
 src/box/box_lua_space.cc | 62 ++++++++++++++++++++++++++--------------
 src/box/lua/schema.lua   |  9 +++---
 test/box/errinj.result   | 48 +++++++++++++++----------------
 test/box/errinj.test.lua | 46 ++++++++++++++---------------
 test/box/test_init.lua   |  7 ++---
 5 files changed, 95 insertions(+), 77 deletions(-)

diff --git a/src/box/box_lua_space.cc b/src/box/box_lua_space.cc
index 1e72c86f72..12e2e58efc 100644
--- a/src/box/box_lua_space.cc
+++ b/src/box/box_lua_space.cc
@@ -44,33 +44,46 @@ extern "C" {
  * @return A new table representing a space on top of the Lua
  * stack.
  */
-static int
-lbox_pushspace(struct lua_State *L, struct space *space)
+static void
+lbox_fillspace(struct lua_State *L, struct space *space, int i)
 {
-	lua_newtable(L);
-
 	/* space.arity */
 	lua_pushstring(L, "arity");
 	lua_pushnumber(L, space->def.arity);
-	lua_settable(L, -3);
+	lua_settable(L, i);
 
 	/* space.n */
 	lua_pushstring(L, "n");
 	lua_pushnumber(L, space_id(space));
-	lua_settable(L, -3);
+	lua_settable(L, i);
 
 	/* space.name */
 	lua_pushstring(L, "name");
 	lua_pushstring(L, space_name(space));
-	lua_settable(L, -3);
+	lua_settable(L, i);
 
 	lua_pushstring(L, "enabled");
 	lua_pushboolean(L, space->engine.state != READY_NO_KEYS);
-	lua_settable(L, -3);
+	lua_settable(L, i);
 
-	/* space.index */
-	lua_pushstring(L, "index");
-	lua_newtable(L);
+	lua_getfield(L, i, "index");
+	if (lua_isnil(L, -1)) {
+		lua_pop(L, 1);
+		/* space.index */
+		lua_pushstring(L, "index");
+		lua_newtable(L);
+		lua_settable(L, i);	/* push space.index */
+		lua_getfield(L, i, "index");
+	} else {
+		/* Empty the table. */
+		lua_pushnil(L);  /* first key */
+		while (lua_next(L, -2) != 0) {
+			lua_pop(L, 1); /* remove the value. */
+			lua_pushnil(L); /* set the key to nil. */
+			lua_settable(L, -3);
+			lua_pushnil(L); /* start over. */
+		}
+	}
 	/*
 	 * Fill space.index table with
 	 * all defined indexes.
@@ -88,7 +101,6 @@ lbox_pushspace(struct lua_State *L, struct space *space)
 		lua_settable(L, -3);
 
 		lua_pushstring(L, "type");
-
 		lua_pushstring(L, index_type_strs[key_def->type]);
 		lua_settable(L, -3);
 
@@ -111,12 +123,12 @@ lbox_pushspace(struct lua_State *L, struct space *space)
 			lua_settable(L, -3);
 		}
 
-		lua_settable(L, -3);	/* space[i].key_field */
+		lua_settable(L, -3);	/* index[i].key_field */
 
-		lua_settable(L, -3);	/* space[i] */
+		lua_settable(L, -3);	/* space.index[i] */
 	}
 
-	lua_settable(L, -3);	/* push space.index */
+	lua_pop(L, 1); /* pop the index field */
 
 	lua_getfield(L, LUA_GLOBALSINDEX, "box");
 	lua_pushstring(L, "schema");
@@ -126,11 +138,9 @@ lbox_pushspace(struct lua_State *L, struct space *space)
 	lua_pushstring(L, "bless");
 	lua_gettable(L, -2);
 
-	lua_pushvalue(L, -5);	/* box, schema, space, bless, space */
+	lua_pushvalue(L, i);	/* space */
 	lua_call(L, 1, 0);
 	lua_pop(L, 3);	/* cleanup stack - box, schema, space */
-
-	return 1;
 }
 
 /** Export a space to Lua */
@@ -147,10 +157,20 @@ box_lua_space_new(struct lua_State *L, struct space *space)
 		lua_getfield(L, -1, "space");
 	}
 
-	lbox_pushspace(L, space);
-	lua_rawseti(L, -2, space_id(space));
+	lua_rawgeti(L, -1, space_id(space));
+	if (lua_isnil(L, -1)) {
+		/*
+		 * Important: if the space already exists,
+		 * modify it, rather than create a new one.
+		 */
+		lua_pop(L, 1);
+		lua_newtable(L);
+		lua_rawseti(L, -2, space_id(space));
+		lua_rawgeti(L, -1, space_id(space));
+	}
+	lbox_fillspace(L, space, lua_gettop(L));
 	lua_pushstring(L, space_name(space));
-	lua_rawgeti(L, -2, space_id(space));
+	lua_insert(L, -2);
 	lua_rawset(L, -3);
 
 	lua_pop(L, 2); /* box, space */
diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index c4859c5130..774e288a5b 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -58,13 +58,14 @@ box.schema.index.create = function(space_id, name, index_type, options)
     end
     local part_count = #options.parts/2
     local parts = options.parts
-    local iid
+    local iid = 0
     -- max
     local tuple = _index.index[0]:select_reverse_range(1, space_id)
     if tuple then
-        iid = box.unpack('i', tuple[1]) + 1
-    else
-        iid = 0
+        local id = box.unpack('i', tuple[0])
+        if id == space_id then
+            iid = box.unpack('i', tuple[1]) + 1
+        end
     end
     if options.id then
         iid = options.id
diff --git a/test/box/errinj.result b/test/box/errinj.result
index 344e976039..f07602205d 100644
--- a/test/box/errinj.result
+++ b/test/box/errinj.result
@@ -1,10 +1,8 @@
-box.insert(box.schema.SPACE_ID, 0, 0, 'tweedledum')
+space = box.schema.create_space('tweedledum')
 ---
-- [0, 0, 'tweedledum']
 ...
-box.insert(box.schema.INDEX_ID, 0, 0, 'primary', 'hash', 1, 1, 0, 'num')
+space:create_index('primary', 'hash', { parts = { 0, 'num' }})
 ---
-- [0, 0, 'primary', 1752392040, 1, 1, 0, 'num']
 ...
 box.errinj.info()
 ---
@@ -25,14 +23,14 @@ box.errinj.set("some-injection") -- check error
 ---
 - 'error: can''t find error injection ''some-injection'''
 ...
-box.space[0]:select(0,222444)
+space:select(0,222444)
 ---
 ...
 box.errinj.set("ERRINJ_TESTING", true)
 ---
 - ok
 ...
-box.space[0]:select(0,222444)
+space:select(0,222444)
 ---
 - error: Error injection 'ERRINJ_TESTING'
 ...
@@ -45,18 +43,18 @@ box.errinj.set("ERRINJ_WAL_IO", true)
 ---
 - ok
 ...
-box.space[0]:insert(1)
+space:insert(1)
 ---
 - error: Failed to write to disk
 ...
-box.space[0]:select(0,1)
+space:select(0,1)
 ---
 ...
 box.errinj.set("ERRINJ_WAL_IO", false)
 ---
 - ok
 ...
-box.space[0]:insert(1)
+space:insert(1)
 ---
 - [1]
 ...
@@ -64,22 +62,22 @@ box.errinj.set("ERRINJ_WAL_IO", true)
 ---
 - ok
 ...
-box.space[0]:update(1, '=p', 0, 2)
+space:update(1, '=p', 0, 2)
 ---
 - error: Failed to write to disk
 ...
-box.space[0]:select(0,1)
+space:select(0,1)
 ---
 - [1]
 ...
-box.space[0]:select(0,2)
+space:select(0,2)
 ---
 ...
 box.errinj.set("ERRINJ_WAL_IO", false)
 ---
 - ok
 ...
-box.space[0]:truncate()
+space:truncate()
 ---
 ...
 -- Check a failed log rotation
@@ -87,18 +85,18 @@ box.errinj.set("ERRINJ_WAL_ROTATE", true)
 ---
 - ok
 ...
-box.space[0]:insert(1)
+space:insert(1)
 ---
 - error: Failed to write to disk
 ...
-box.space[0]:select(0,1)
+space:select(0,1)
 ---
 ...
 box.errinj.set("ERRINJ_WAL_ROTATE", false)
 ---
 - ok
 ...
-box.space[0]:insert(1)
+space:insert(1)
 ---
 - [1]
 ...
@@ -106,29 +104,29 @@ box.errinj.set("ERRINJ_WAL_ROTATE", true)
 ---
 - ok
 ...
-box.space[0]:update(1, '=p', 0, 2)
+space:update(1, '=p', 0, 2)
 ---
 - error: Failed to write to disk
 ...
-box.space[0]:select(0,1)
+space:select(0,1)
 ---
 - [1]
 ...
-box.space[0]:select(0,2)
+space:select(0,2)
 ---
 ...
 box.errinj.set("ERRINJ_WAL_ROTATE", false)
 ---
 - ok
 ...
-box.space[0]:update(1, '=p', 0, 2)
+space:update(1, '=p', 0, 2)
 ---
 - [2]
 ...
-box.space[0]:select(0,1)
+space:select(0,1)
 ---
 ...
-box.space[0]:select(0,2)
+space:select(0,2)
 ---
 - [2]
 ...
@@ -136,7 +134,7 @@ box.errinj.set("ERRINJ_WAL_ROTATE", true)
 ---
 - ok
 ...
-box.space[0]:truncate()
+space:truncate()
 ---
 - error: Failed to write to disk
 ...
@@ -144,9 +142,9 @@ box.errinj.set("ERRINJ_WAL_ROTATE", false)
 ---
 - ok
 ...
-box.space[0]:truncate()
+space:truncate()
 ---
 ...
-box.space[0]:drop()
+space:drop()
 ---
 ...
diff --git a/test/box/errinj.test.lua b/test/box/errinj.test.lua
index 838c188343..ba5a1d4f99 100644
--- a/test/box/errinj.test.lua
+++ b/test/box/errinj.test.lua
@@ -1,44 +1,44 @@
-box.insert(box.schema.SPACE_ID, 0, 0, 'tweedledum')
-box.insert(box.schema.INDEX_ID, 0, 0, 'primary', 'hash', 1, 1, 0, 'num')
+space = box.schema.create_space('tweedledum')
+space:create_index('primary', 'hash', { parts = { 0, 'num' }})
 
 box.errinj.info()
 box.errinj.set("some-injection", true)
 box.errinj.set("some-injection") -- check error
-box.space[0]:select(0,222444)
+space:select(0,222444)
 box.errinj.set("ERRINJ_TESTING", true)
-box.space[0]:select(0,222444)
+space:select(0,222444)
 box.errinj.set("ERRINJ_TESTING", false)
 
 -- Check how well we handle a failed log write
 box.errinj.set("ERRINJ_WAL_IO", true)
-box.space[0]:insert(1)
-box.space[0]:select(0,1)
+space:insert(1)
+space:select(0,1)
 box.errinj.set("ERRINJ_WAL_IO", false)
-box.space[0]:insert(1)
+space:insert(1)
 box.errinj.set("ERRINJ_WAL_IO", true)
-box.space[0]:update(1, '=p', 0, 2)
-box.space[0]:select(0,1)
-box.space[0]:select(0,2)
+space:update(1, '=p', 0, 2)
+space:select(0,1)
+space:select(0,2)
 box.errinj.set("ERRINJ_WAL_IO", false)
-box.space[0]:truncate()
+space:truncate()
 
 -- Check a failed log rotation
 box.errinj.set("ERRINJ_WAL_ROTATE", true)
-box.space[0]:insert(1)
-box.space[0]:select(0,1)
+space:insert(1)
+space:select(0,1)
 box.errinj.set("ERRINJ_WAL_ROTATE", false)
-box.space[0]:insert(1)
+space:insert(1)
 box.errinj.set("ERRINJ_WAL_ROTATE", true)
-box.space[0]:update(1, '=p', 0, 2)
-box.space[0]:select(0,1)
-box.space[0]:select(0,2)
+space:update(1, '=p', 0, 2)
+space:select(0,1)
+space:select(0,2)
 box.errinj.set("ERRINJ_WAL_ROTATE", false)
-box.space[0]:update(1, '=p', 0, 2)
-box.space[0]:select(0,1)
-box.space[0]:select(0,2)
+space:update(1, '=p', 0, 2)
+space:select(0,1)
+space:select(0,2)
 box.errinj.set("ERRINJ_WAL_ROTATE", true)
-box.space[0]:truncate()
+space:truncate()
 box.errinj.set("ERRINJ_WAL_ROTATE", false)
-box.space[0]:truncate()
+space:truncate()
 
-box.space[0]:drop()
+space:drop()
diff --git a/test/box/test_init.lua b/test/box/test_init.lua
index a0b4045886..a0cd11435c 100644
--- a/test/box/test_init.lua
+++ b/test/box/test_init.lua
@@ -22,9 +22,8 @@ local function do_insert()
     box.insert(0, 1, 2, 4, 8)
 end
 
-box.insert(box.schema.SPACE_ID, 0, 0, 'tweedledum')
-box.insert(box.schema.INDEX_ID, 0, 0, 'primary', 'hash', 1, 1, 0, 'num')
-
+space = box.schema.create_space('tweedledum', { id = 0 })
+space:create_index('primary', 'hash', { parts = { 0, 'num' }})
 
 fiber = box.fiber.create(do_insert)
 box.fiber.resume(fiber)
@@ -33,4 +32,4 @@ box.fiber.resume(fiber)
 -- Test insert from start-up script
 --
 
-box.insert(0, 2, 4, 8, 16)
+space:insert(2, 4, 8, 16)
-- 
GitLab