From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 6D00E247AC for ; Tue, 24 Jul 2018 07:58:23 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id pZ05e9m_NL2e for ; Tue, 24 Jul 2018 07:58:23 -0400 (EDT) Received: from smtp21.mail.ru (smtp21.mail.ru [94.100.179.250]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id DF3B624986 for ; Tue, 24 Jul 2018 07:58:22 -0400 (EDT) Received: from [185.6.245.156] (port=43312 helo=mimeev-ThinkPad-T460p.mail.msk) by smtp21.mail.ru with esmtpa (envelope-from ) id 1fhvxN-0000en-7j for tarantool-patches@freelists.org; Tue, 24 Jul 2018 14:58:21 +0300 From: imeevma@tarantool.org Subject: [tarantool-patches] [PATCH v3 6/7] box: primary index for ephemeral spaces Date: Tue, 24 Jul 2018 14:58:20 +0300 Message-Id: In-Reply-To: References: Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org 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