[tarantool-patches] [PATCH v3 6/7] box: primary index for ephemeral spaces

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


Functions for creation and deletion primary index
of ephemeral space added.

Part of #3375.
---
 src/box/lua/schema.lua            | 163 ++++++++++++++++++++++++++++----------
 src/box/lua/space.cc              |  65 +++++++++++++++
 test/box/ephemeral_space.result   |  84 +++++++++++++++++++-
 test/box/ephemeral_space.test.lua |  33 ++++++++
 test/engine/iterator.result       |   2 +-
 5 files changed, 302 insertions(+), 45 deletions(-)

diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index 5962ce2..cc8c66b 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -765,23 +765,7 @@ for k, v in pairs(index_options) do
     alter_index_template[k] = v
 end
 
---
--- check_param_table() template for create_index(), includes
--- all index options and if_not_exists specifier
---
-local create_index_template = table.deepcopy(alter_index_template)
-create_index_template.if_not_exists = "boolean"
-
-box.schema.index.create = function(space_id, name, options)
-    check_param(space_id, 'space_id', 'number')
-    check_param(name, 'name', 'string')
-    check_param_table(options, create_index_template)
-    local space = box.space[space_id]
-    if not space then
-        box.error(box.error.NO_SUCH_SPACE, '#'..tostring(space_id))
-    end
-    local format = space:format()
-
+local create_index_options = function(options, format, engine)
     local options_defaults = {
         type = 'tree',
     }
@@ -803,7 +787,7 @@ box.schema.index.create = function(space_id, name, options)
         end
     end
     options = update_param_table(options, options_defaults)
-    if space.engine == 'vinyl' then
+    if engine == 'vinyl' then
         options_defaults = {
             page_size = box.cfg.vinyl_page_size,
             range_size = box.cfg.vinyl_range_size,
@@ -815,6 +799,57 @@ box.schema.index.create = function(space_id, name, options)
         options_defaults = {}
     end
     options = update_param_table(options, options_defaults)
+    return options
+end
+
+local update_index_options = function(options, parts)
+    -- create_index() options contains type, parts, etc,
+    -- stored separately. Remove these members from index_opts
+    local index_opts = {
+            dimension = options.dimension,
+            unique = options.unique,
+            distance = options.distance,
+            page_size = options.page_size,
+            range_size = options.range_size,
+            run_count_per_level = options.run_count_per_level,
+            run_size_ratio = options.run_size_ratio,
+            bloom_fpr = options.bloom_fpr,
+    }
+    local field_type_aliases = {
+        num = 'unsigned'; -- Deprecated since 1.7.2
+        uint = 'unsigned';
+        str = 'string';
+        int = 'integer';
+        ['*'] = 'any';
+    };
+    for _, part in pairs(parts) do
+        local field_type = part.type:lower()
+        part.type = field_type_aliases[field_type] or field_type
+        if field_type == 'num' then
+            log.warn("field type '%s' is deprecated since Tarantool 1.7, "..
+                     "please use '%s' instead", field_type, part.type)
+        end
+    end
+    return index_opts
+end
+
+--
+-- check_param_table() template for create_index(), includes
+-- all index options and if_not_exists specifier
+--
+local create_index_template = table.deepcopy(alter_index_template)
+create_index_template.if_not_exists = "boolean"
+
+box.schema.index.create = function(space_id, name, options)
+    check_param(space_id, 'space_id', 'number')
+    check_param(name, 'name', 'string')
+    check_param_table(options, create_index_template)
+    local space = box.space[space_id]
+    if not space then
+        box.error(box.error.NO_SUCH_SPACE, '#'..tostring(space_id))
+    end
+    local format = space:format()
+    options = create_index_options(options, format, space.engine)
 
     local _index = box.space[box.schema.INDEX_ID]
     local _vindex = box.space[box.schema.VINDEX_ID]
@@ -844,31 +879,7 @@ box.schema.index.create = function(space_id, name, options)
         update_index_parts(format, options.parts)
     -- create_index() options contains type, parts, etc,
     -- stored separately. Remove these members from index_opts
-    local index_opts = {
-            dimension = options.dimension,
-            unique = options.unique,
-            distance = options.distance,
-            page_size = options.page_size,
-            range_size = options.range_size,
-            run_count_per_level = options.run_count_per_level,
-            run_size_ratio = options.run_size_ratio,
-            bloom_fpr = options.bloom_fpr,
-    }
-    local field_type_aliases = {
-        num = 'unsigned'; -- Deprecated since 1.7.2
-        uint = 'unsigned';
-        str = 'string';
-        int = 'integer';
-        ['*'] = 'any';
-    };
-    for _, part in pairs(parts) do
-        local field_type = part.type:lower()
-        part.type = field_type_aliases[field_type] or field_type
-        if field_type == 'num' then
-            log.warn("field type '%s' is deprecated since Tarantool 1.7, "..
-                     "please use '%s' instead", field_type, part.type)
-        end
-    end
+    local index_opts = update_index_options(options, parts)
     local _space_sequence = box.space[box.schema.SPACE_SEQUENCE_ID]
     local sequence_is_generated = false
     local sequence = options.sequence or nil -- ignore sequence = false
@@ -1083,6 +1094,67 @@ ffi.metatype(iterator_t, {
     end;
 })
 
+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_mt = {}
+
+local create_ephemeral_index = function(space, name, options)
+    if type(space) ~= 'table' then
+        error("Usage: space:create_index(name, opts)")
+    end
+    check_param(name, 'name', 'string')
+    check_param_table(options, create_index_template)
+    local format = space:format()
+    options = create_index_options(options, format, space.engine)
+    local iid = options.id or 0
+    if space.index[iid] then
+        if options.if_not_exists then
+            return space.index[iid], "not created"
+        else
+            box.error(box.error.INDEX_EXISTS, name)
+        end
+    end
+    local parts, parts_can_be_simplified =
+        update_index_parts(format, options.parts)
+    local index_opts = update_index_options(options, parts)
+    if parts_can_be_simplified then
+        parts = simplify_index_parts(parts)
+    end
+    space.space = index_new_ephemeral(space.space, iid, name, options.type,
+                                      msgpack.encode(index_opts),
+                                      msgpack.encode(parts))
+    space.index[iid] = {}
+    space.index[iid].unique = index_opts.unique or true
+    space.index[iid].parts = parts
+    space.index[iid].id = iid
+    space.index[iid].name = name
+    space.index[iid].type = type
+    space.index[iid].options = options
+    space.index[iid].space = space
+    space.index[name] = space.index[iid]
+    setmetatable(space.index[iid], index_ephemeral_mt)
+    return space.index[name]
+end
+
+local drop_ephemeral_index = function(index)
+    if type(index) ~= 'table' then
+        error("Usage: index:drop()")
+    end
+    index.space.space = index_delete_ephemeral(index.space.space)
+    index.space.index[index.name] = nil
+    index.space.index[index.id] = nil
+    for k,_ in pairs(index) do
+        index[k] = nil
+    end
+    local dropped_mt = {
+        __index = function()
+            error('The index is dropped and can not be used')
+        end
+    }
+end
+
 local iterator_gen = function(param, state)
     --[[
         index:pairs() mostly conforms to the Lua for-in loop conventions and
@@ -1568,6 +1640,10 @@ end
 space_mt.frommap = box.internal.space.frommap
 space_mt.__index = space_mt
 
+-- Metatable for primary index of ephemeral space
+index_ephemeral_mt.drop = drop_ephemeral_index
+index_ephemeral_mt.__index = index_ephemeral_mt
+
 -- Metatable for ephemeral space
 space_ephemeral_mt.format = function(space)
     check_ephemeral_space_arg(space, 'format')
@@ -1589,6 +1665,7 @@ space_ephemeral_mt.bsize = function(space)
     check_ephemeral_space_arg(space, 'bsize')
     return builtin.space_bsize(space.space)
 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
 
diff --git a/src/box/lua/space.cc b/src/box/lua/space.cc
index 6f21907..db746ab 100644
--- a/src/box/lua/space.cc
+++ b/src/box/lua/space.cc
@@ -534,6 +534,69 @@ lbox_space_delete_ephemeral(struct lua_State *L)
 }
 
 /**
+ * Create an index for ephemeral space.
+ *
+ * @param L Lua stack to next get arguments from:
+ * struct space *space, uint32_t iid, const char *name,
+ * const char *type_field, tuple index_opts, tuple parts
+ *
+ * @retval not nil index for ephemeral space created.
+ * @retval nil error
+ */
+static int
+lbox_index_new_ephemeral(struct lua_State *L)
+{
+	uint32_t argc = lua_gettop(L);
+	if (argc != 6)
+		return luaL_error(L, "Using: ephemeral:create_index(opts");
+	struct space *space = lua_checkephemeralspace(L, 1);
+	uint32_t index_id = luaL_checknumber (L, 2);
+	const char *name = luaL_checkstring (L, 3);
+	const char *type_field = luaL_checkstring(L, 4);
+	const char *opts_field = luaL_checkstring(L, 5);
+	const char *parts = luaL_checkstring(L, 6);
+	if (index_id != 0) {
+		diag_set(ClientError, ER_UNSUPPORTED, "Ephemeral space",
+			 "non-primary index");
+		return luaT_error(L);
+	}
+
+	struct space_def *space_def = space_def_dup(space->def);
+	if (space_def == NULL)
+		return luaT_error(L);
+	struct index_def *index_def =
+		index_def_new_decode(0, index_id, space->def->fields,
+				     space->def->field_count, name,
+				     strlen(name), type_field, opts_field,
+				     parts, space_name(space), NULL);
+	if (index_def == NULL)
+		return luaT_error(L);
+	if (!index_def_is_valid(index_def, space_name(space)) ||
+	    space_check_index_def(space, index_def) != 0) {
+		index_def_delete(index_def);
+		return luaT_error(L);
+	}
+	space_delete(space);
+	return box_space_new_ephemeral(L, space_def, index_def);
+}
+
+/**
+ * Drop primary index of ephemeral space.
+ *
+ * @param L Lua stack to get space from.
+ */
+static int
+lbox_index_drop_ephemeral(struct lua_State *L)
+{
+	struct space *space = lua_checkephemeralspace(L, 1);
+	struct space_def *space_def = space_def_dup(space->def);
+	if (space_def == NULL)
+		return luaT_error(L);
+	space_delete(space);
+	return box_space_new_ephemeral(L, space_def, NULL);
+}
+
+/**
  * Make a tuple or a table Lua object by map.
  *
  * @param L Lua stack to next get table map from.
@@ -740,6 +803,8 @@ box_lua_space_init(struct lua_State *L)
 		{"frommap", lbox_space_frommap},
 		{"space_new_ephemeral", lbox_space_new_ephemeral},
 		{"space_delete_ephemeral", lbox_space_delete_ephemeral},
+		{"index_new_ephemeral", lbox_index_new_ephemeral},
+		{"index_delete_ephemeral", lbox_index_drop_ephemeral},
 		{NULL, NULL}
 	};
 	luaL_register(L, "box.internal.space", space_internal_lib);
diff --git a/test/box/ephemeral_space.result b/test/box/ephemeral_space.result
index b0e91bb..4ef395f 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:1583: Usage: space:frommap(map, opts)'
+- error: 'builtin/box/schema.lua:1659: Usage: space:frommap(map, opts)'
 ...
 s:frommap({})
 ---
@@ -163,3 +163,85 @@ s:frommap({ddd = 1, aaa = 2, ccc = 3, bbb = 4}, {dummy = true})
 s:drop()
 ---
 ...
+-- Ephemeral space: index create and drop.
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a')
+---
+...
+i.unique
+---
+- true
+...
+i.parts
+---
+- - - 0
+    - unsigned
+...
+i.id
+---
+- 0
+...
+i.name
+---
+- a
+...
+i:drop()
+---
+...
+i = s:create_index('a', {parts={{5,'string', collation='Unicode'}}})
+---
+...
+i.parts
+---
+- - field: 4
+    collation: 1
+    type: string
+...
+i:drop()
+---
+...
+i = s:create_index('a', {parts={2, 'unsigned', 3, 'unsigned'}})
+---
+...
+i.parts
+---
+- - - 1
+    - unsigned
+  - - 2
+    - unsigned
+...
+i:drop()
+---
+...
+-- Double creation of index for ephemeral space.
+i = s:create_index('a')
+---
+...
+i = s:create_index('a')
+---
+- error: Index 'a' already exists
+...
+i:drop()
+---
+...
+i = s:create_index('a')
+---
+...
+i = s:create_index('a', {if_not_exists=true})
+---
+...
+i:drop()
+---
+...
+-- Ephemeral space can have only primary index with id == 0.
+i = s:create_index('a', {id = 10})
+---
+- error: Ephemeral space does not support non-primary index
+...
+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'
+...
diff --git a/test/box/ephemeral_space.test.lua b/test/box/ephemeral_space.test.lua
index a7e3404..93211c6 100644
--- a/test/box/ephemeral_space.test.lua
+++ b/test/box/ephemeral_space.test.lua
@@ -56,3 +56,36 @@ s:frommap({ddd = 1, aaa = 2, ccc = 3, bbb = 4}, {table = false})
 s:frommap({ddd = 1, aaa = 2, ccc = 3, bbb = box.NULL})
 s:frommap({ddd = 1, aaa = 2, ccc = 3, bbb = 4}, {dummy = true})
 s:drop()
+
+
+-- Ephemeral space: index create and drop.
+s = box.schema.space.create_ephemeral()
+
+i = s:create_index('a')
+i.unique
+i.parts
+i.id
+i.name
+i:drop()
+
+i = s:create_index('a', {parts={{5,'string', collation='Unicode'}}})
+i.parts
+i:drop()
+
+i = s:create_index('a', {parts={2, 'unsigned', 3, 'unsigned'}})
+i.parts
+i:drop()
+
+-- Double creation of index for ephemeral space.
+i = s:create_index('a')
+i = s:create_index('a')
+i:drop()
+
+i = s:create_index('a')
+i = s:create_index('a', {if_not_exists=true})
+i:drop()
+
+-- Ephemeral space can have only primary index with id == 0.
+i = s:create_index('a', {id = 10})
+
+i = s:create_index('a', {type = 'bitset', parts = {1, 'unsigned', 2, 'unsigned'}})
diff --git a/test/engine/iterator.result b/test/engine/iterator.result
index 2552ddd..f39a15a 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:1108: usage: next(param, state)'
+- error: 'builtin/box/schema.lua:1180: usage: next(param, state)'
 ...
 value
 ---
-- 
2.7.4





More information about the Tarantool-patches mailing list