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 5DF7026DCE for ; Thu, 12 Jul 2018 07:16:17 -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 AZnMpCOgJoG5 for ; Thu, 12 Jul 2018 07:16:17 -0400 (EDT) Received: from smtp14.mail.ru (smtp14.mail.ru [94.100.181.95]) (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 E908B26DCC for ; Thu, 12 Jul 2018 07:16:16 -0400 (EDT) Received: from [185.6.245.156] (port=42112 helo=mimeev-ThinkPad-T460p.mail.msk) by smtp14.mail.ru with esmtpa (envelope-from ) id 1fdZa3-00022q-Ey for tarantool-patches@freelists.org; Thu, 12 Jul 2018 14:16:15 +0300 From: imeevma@tarantool.org Subject: [tarantool-patches] [PATCH 4/5] Primary index for ephemeral spaces Date: Thu, 12 Jul 2018 14:16:15 +0300 Message-Id: <64b848161d6b598dba2b0ae40d89c4d4c744682f.1531393821.git.imeevma@gmail.com> 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/index_def.c | 42 +++++++ src/box/index_def.h | 18 +++ src/box/lua/schema.lua | 130 ++++++++++++++++++++++ src/box/lua/space.cc | 92 ++++++++++++++++ test/box/ephemeral_space.result | 225 ++++++++++++++++++++++++++++++++++++-- test/box/ephemeral_space.test.lua | 88 +++++++++++++-- test/engine/iterator.result | 2 +- 7 files changed, 582 insertions(+), 15 deletions(-) diff --git a/src/box/index_def.c b/src/box/index_def.c index e0d54c0..9622dce 100644 --- a/src/box/index_def.c +++ b/src/box/index_def.c @@ -31,6 +31,8 @@ #include "index_def.h" #include "schema_def.h" #include "identifier.h" +#include "fiber.h" +#include "space.h" const char *index_type_strs[] = { "HASH", "TREE", "BITSET", "RTREE" }; @@ -369,3 +371,43 @@ index_opts_decode(struct index_opts *opts, const char *map, } return 0; } + +struct index_def * +ephemeral_index_def(struct space *space, uint32_t index_id, + const char *name, const char *type_field, + const char *opts_field, const char *parts) +{ + const struct field_def *fields = space->def->fields; + uint32_t field_count = space->def->field_count; + struct index_opts opts; + struct key_def *key_def = NULL; + uint32_t part_count = mp_decode_array(&parts); + enum index_type type = STR2ENUM(index_type, type_field); + if(index_opts_decode(&opts, opts_field, &fiber()->gc) != 0) + return NULL; + if(identifier_check(name, strlen(name)) != 0) + return NULL; + struct key_part_def *part_def = (struct key_part_def *) + malloc(sizeof(*part_def) * part_count); + if (part_def == NULL) { + diag_set(OutOfMemory, sizeof(*part_def) * part_count, + "malloc", "key_part_def"); + return NULL; + } + if (key_def_decode_parts(part_def, part_count, &parts, + fields, field_count) != 0) { + free(part_def); + return NULL; + } + key_def = key_def_new_with_parts(part_def, part_count); + free(part_def); + if (key_def == NULL) + return NULL; + struct index_def *index_def = + index_def_new(0, index_id, name, strlen(name), + type, &opts, key_def, NULL); + key_def_delete(key_def); + if (index_def == NULL) + return NULL; + return index_def; +} diff --git a/src/box/index_def.h b/src/box/index_def.h index 4c3625b..9725a8e 100644 --- a/src/box/index_def.h +++ b/src/box/index_def.h @@ -39,6 +39,8 @@ extern "C" { #endif /* defined(__cplusplus) */ +struct space; + enum index_type { HASH = 0, /* HASH Index */ TREE, /* TREE Index */ @@ -366,6 +368,22 @@ int index_opts_decode(struct index_opts *opts, const char *map, struct region *region); +/** + * Create index definition for primary index + * of ephemeral space in Lua + * + * @param space - ephemeral space. + * @param index_id - index id. + * @param name - name of index. + * @param type_field - type of field as string. + * @param opts_field - options in msgpack format + * @param parts - parts in msgpack format + */ +struct index_def * +ephemeral_index_def(struct space *space, uint32_t index_id, + const char *name, const char *type_field, + const char *opts_field, const char *parts); + #if defined(__cplusplus) } /* extern "C" */ diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 81f0fa0..0fe109a 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -527,6 +527,9 @@ box.schema.space.drop_ephemeral = function(ephemeral_space) return end check_param(ephemeral_space.space, 'space', 'cdata') + if ephemeral_space.index ~= nil and ephemeral_space.index[0] ~= nil then + ephemeral_space.index[0]:drop() + end space_delete_ephemeral(ephemeral_space) for k,_ in pairs(ephemeral_space) do ephemeral_space[k] = nil @@ -1084,6 +1087,128 @@ 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_methods = box.schema.index_ephemeral_methods +box.schema.index_ephemeral_mt = nil +local index_ephemeral_mt = {} + +local index_ephemeral_create = function(ephemeral_space, name, options) + if type(ephemeral_space) ~= 'table' then + error("Usage: ephemeral_space:create_index(name, opts)") + end + check_param(name, 'name', 'string') + check_param_table(options, create_index_template) + local space = ephemeral_space + local format = space:format() + + local options_defaults = { + type = 'tree', + } + options = update_param_table(options, options_defaults) + local type_dependent_defaults = { + rtree = {parts = { 2, 'array' }, unique = false}, + bitset = {parts = { 2, 'unsigned' }, unique = false}, + other = {parts = { 1, 'unsigned' }, unique = true}, + } + options_defaults = type_dependent_defaults[options.type] + or type_dependent_defaults.other + if not options.parts then + local fieldno = options_defaults.parts[1] + if #format >= fieldno then + local t = format[fieldno].type + if t ~= 'any' then + options.parts = {{fieldno, format[fieldno].type}} + end + end + end + options = update_param_table(options, options_defaults) + if space.engine == 'vinyl' then + options_defaults = { + page_size = box.cfg.vinyl_page_size, + range_size = box.cfg.vinyl_range_size, + run_count_per_level = box.cfg.vinyl_run_count_per_level, + run_size_ratio = box.cfg.vinyl_run_size_ratio, + bloom_fpr = box.cfg.vinyl_bloom_fpr + } + else + options_defaults = {} + end + options = update_param_table(options, options_defaults) + + if ephemeral_space.index ~= nil and ephemeral_space.index[0] then + if options.if_not_exists then + return space.index[0], "not created" + else + error("Primary index for this ephemeral index already exists") + end + end + local iid = 0 + if options.id and options.id ~= 0 then + error("Ephemeral space can have only primary index.") + end + local parts, parts_can_be_simplified = + 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 + if parts_can_be_simplified then + parts = simplify_index_parts(parts) + end + space.space = index_new_ephemeral(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 + space.index[iid].ephemeral_space = space + space.index[name] = space.index[iid] + setmetatable(space.index[iid], index_ephemeral_mt) + return space.index[name] +end + +local index_ephemeral_drop = function(ephemeral_index) + if type(ephemeral_index) ~= 'table' then + error("Usage: ephemeral_space.index[0]:drop()") + end + ephemeral_index.ephemeral_space.space = index_delete_ephemeral(ephemeral_index) + ephemeral_index.ephemeral_space.index = {} + for k,_ in pairs(ephemeral_index) do + ephemeral_index[k] = nil + end +end + local iterator_gen = function(param, state) --[[ index:pairs() mostly conforms to the Lua for-in loop conventions and @@ -1563,6 +1688,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 = index_ephemeral_drop +index_ephemeral_mt.__index = index_ephemeral_mt + -- Metatable for ephemeral space space_ephemeral_mt.format = function(ephemeral_space) return ephemeral_space.space_format @@ -1571,6 +1700,7 @@ space_ephemeral_mt.run_triggers = function(ephemeral_space, yesno) builtin.space_run_triggers(ephemeral_space.space, yesno) end space_ephemeral_mt.frommap = space_ephemeral_methods.frommap +space_ephemeral_mt.create_index = index_ephemeral_create 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 955c465..4374db9 100644 --- a/src/box/lua/space.cc +++ b/src/box/lua/space.cc @@ -34,6 +34,7 @@ #include "lua/utils.h" #include "lua/trigger.h" #include "box/box.h" +#include "box/lua/misc.h" /* lbox_encode_tuple_on_gc() */ extern "C" { #include @@ -616,6 +617,93 @@ lbox_space_delete_ephemeral(struct lua_State *L) } /** + * Create an index for ephemeral space. + * @param Lua table - ephemeral space. + * @param Lua uint32_t id - id of index, for + * ephemeral spaces it is 0 as they can have only + * primary index. + * @param Lua const char *name - name of index. + * @param Lua const char *type_field - type of field. + * @param Lua const char *opts_field - options in + * msgpack format. + * @param Lua const char *parts - parts in msgpack + * format. + * @retval not nil - ephemeral space created. + * @retval nil - error, A reason is returned in + * the second value. + */ +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 = (struct 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); + assert(index_id == 0); + struct space_def *ephemeral_space_def = space_def_dup(space->def); + if (ephemeral_space_def == NULL) + return luaL_error(L, "Error with creating space_def"); + struct index_def *index_def_ephemeral = + ephemeral_index_def(space, index_id, name, type_field, + opts_field, parts); + if(index_def_ephemeral == NULL) + return luaT_error(L); + if(!index_def_is_valid(index_def_ephemeral, space_name(space)) || + space_check_index_def(space, index_def_ephemeral) != 0) { + index_def_delete(index_def_ephemeral); + return luaT_error(L); + } + struct rlist key_list; + rlist_create(&key_list); + rlist_add_entry(&key_list, index_def_ephemeral, link); + struct space *new_space = space_new_ephemeral(ephemeral_space_def, + &key_list); + index_def_delete(index_def_ephemeral); + space_def_delete(ephemeral_space_def); + if(new_space == NULL) { + return luaL_error(L, "Error with creating index for "\ + "ephemeral space"); + } + space_delete(space); + struct space **ptr = + (struct space **) luaL_pushcdata(L, CTID_STRUCT_SPACE_POINTER); + *ptr = new_space; + return 1; +} + +/** + * Drop primary index of ephemeral space. + * @param Lua ephemeral space. + */ +static int +lbox_index_drop_ephemeral(struct lua_State *L) +{ + struct space *space = (struct space *)lua_checkephemeralspace(L, 1); + struct space_def *ephemeral_space_def = space_def_dup(space->def); + if (ephemeral_space_def == NULL) + return luaL_error(L, "Error with creating space_def"); + struct rlist key_list; + rlist_create(&key_list); + struct space *new_space = space_new_ephemeral(ephemeral_space_def, + &key_list); + space_def_delete(ephemeral_space_def); + if(new_space == NULL) { + return luaL_error(L, "Error with creating index for "\ + "ephemeral space"); + } + space_delete(space); + struct space **ptr = + (struct space **) luaL_pushcdata(L, CTID_STRUCT_SPACE_POINTER); + *ptr = new_space; + return 1; +} + +/** * Make a tuple or a table Lua object by map. * @param Lua space object. * @param Lua map table object. @@ -769,12 +857,16 @@ box_lua_space_init(struct lua_State *L) lua_setfield(L, -2, "SQL_BIND_PARAMETER_MAX"); lua_newtable(L); lua_setfield(L, -2, "space_ephemeral_methods"); + lua_newtable(L); + lua_setfield(L, -2, "index_ephemeral_methods"); lua_pop(L, 2); /* box, schema */ static const struct luaL_Reg space_internal_lib[] = { {"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 135df3c..d958ffe 100644 --- a/test/box/ephemeral_space.result +++ b/test/box/ephemeral_space.result @@ -1,5 +1,5 @@ --- Ephemeral space: creation and dropping --- Simple creation +-- Ephemeral space: creation and dropping. +-- Simple creation. s = box.schema.space.create_ephemeral() --- ... @@ -22,7 +22,7 @@ s.engine s:drop() --- ... --- Creation with defined engine (only memtx for now) +-- Creation with defined engine (only memtx for now). s = box.schema.space.create_ephemeral({engine = 'memtx'}) --- ... @@ -49,7 +49,7 @@ s = box.schema.space.create_ephemeral({engine = 'other'}) --- - error: 'builtin/box/schema.lua:507: Error with creating space' ... --- Creation with defined field_count +-- Creation with defined field_count. s = box.schema.space.create_ephemeral({field_count = 10}) --- ... @@ -76,7 +76,7 @@ s = box.schema.space.create_ephemeral({field_count = 'asd'}) --- - error: Illegal parameters, options parameter 'field_count' should be of type number ... --- Creation with defined format +-- Creation with defined format. format = {{name='field1', type='unsigned'}, {name='field2', type='string'}} --- ... @@ -106,7 +106,7 @@ s = box.schema.space.create_ephemeral({format = 'a'}) --- - error: Illegal parameters, options parameter 'format' should be of type table ... --- All options defined +-- All options defined. format = {{name='field1', type='unsigned'}, {name='field2', type='string'}} --- ... @@ -185,7 +185,218 @@ s --- - [] ... --- Ephemeral space: methods +-- Ephemeral space: index creation and dropping. +s = box.schema.space.create_ephemeral() +--- +... +-- Simple creation +i = s:create_index('a') +--- +... +i.unique +--- +- true +... +i.parts +--- +- - - 0 + - unsigned +... +i.id +--- +- 0 +... +i.name +--- +- a +... +i:drop() +--- +... +-- Double creation of index for ephemeral space. +i = s:create_index('a') +--- +... +i = s:create_index('a') +--- +- error: 'builtin/box/schema.lua:1145: Primary index for this ephemeral index already + exists' +... +i:drop() +--- +... +-- Double creation of index for ephemeral space +-- but with if_not_exists=true. +i = s:create_index('a') +--- +... +i = s:create_index('a', {if_not_exists=true}) +--- +... +i:drop() +--- +... +-- Ephemeral space can have only primary. +-- index so its id == 0 +i = s:create_index('a', {id = 10}) +--- +- error: 'builtin/box/schema.lua:1150: Ephemeral space can have only primary index.' +... +-- Set parameters: parts. +i = s:create_index('a', {parts={1}}) +--- +... +i.unique +--- +- true +... +i.parts +--- +- - - 0 + - scalar +... +i.id +--- +- 0 +... +i.name +--- +- a +... +i:drop() +--- +... +i = s:create_index('a', {parts={1,"integer"}}) +--- +... +i.unique +--- +- true +... +i.parts +--- +- - - 0 + - integer +... +i.id +--- +- 0 +... +i.name +--- +- a +... +i:drop() +--- +... +i = s:create_index('a', {parts={1,'string',collation='Unicode'}}) +--- +... +i.unique +--- +- true +... +i.parts +--- +- - - 0 + - string +... +i.id +--- +- 0 +... +i.name +--- +- a +... +i:drop() +--- +... +i = s:create_index('a', {parts={1,'uint',2,'int',3,'str'}}) +--- +... +i.unique +--- +- true +... +i.parts +--- +- - - 0 + - unsigned + - - 1 + - integer + - - 2 + - string +... +i.id +--- +- 0 +... +i.name +--- +- a +... +i:drop() +--- +... +i = s:create_index('a', {parts={{5,'string',collation='Unicode'}}}) +--- +... +i.unique +--- +- true +... +i.parts +--- +- - field: 4 + collation: 1 + type: string +... +i.id +--- +- 0 +... +i.name +--- +- a +... +i:drop() +--- +... +i = s:create_index('a', {parts={3,"scalar"}}) +--- +... +i.unique +--- +- true +... +i.parts +--- +- - - 2 + - scalar +... +i.id +--- +- 0 +... +i.name +--- +- a +... +i:drop() +--- +... +i = s:create_index('a', {parts={{5,'uint',collation='Unicode'}}}) +--- +- error: 'Wrong index options (field 1): collation is reasonable only for string and + scalar parts' +... +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. format = {{name='field1', type='unsigned'}, {name='field2', type='string'}} --- ... diff --git a/test/box/ephemeral_space.test.lua b/test/box/ephemeral_space.test.lua index 3cc936f..211014c 100644 --- a/test/box/ephemeral_space.test.lua +++ b/test/box/ephemeral_space.test.lua @@ -1,6 +1,6 @@ --- Ephemeral space: creation and dropping +-- Ephemeral space: creation and dropping. --- Simple creation +-- Simple creation. s = box.schema.space.create_ephemeral() s.index s.temporary @@ -8,7 +8,7 @@ s.field_count s.engine s:drop() --- Creation with defined engine (only memtx for now) +-- Creation with defined engine (only memtx for now). s = box.schema.space.create_ephemeral({engine = 'memtx'}) s.index s.temporary @@ -18,7 +18,7 @@ s:drop() s = box.schema.space.create_ephemeral({engine = 'other'}) --- Creation with defined field_count +-- Creation with defined field_count. s = box.schema.space.create_ephemeral({field_count = 10}) s.index s.temporary @@ -28,7 +28,7 @@ s:drop() s = box.schema.space.create_ephemeral({field_count = 'asd'}) --- Creation with defined format +-- Creation with defined format. format = {{name='field1', type='unsigned'}, {name='field2', type='string'}} s = box.schema.space.create_ephemeral({format = format}) s.index @@ -39,7 +39,7 @@ s:drop() s = box.schema.space.create_ephemeral({format = 'a'}) --- All options defined +-- All options defined. format = {{name='field1', type='unsigned'}, {name='field2', type='string'}} options = {engine = 'memtx', field_count = 7, format = format} s = box.schema.space.create_ephemeral(options) @@ -70,7 +70,81 @@ box.schema.space.drop_ephemeral(s) s --- Ephemeral space: methods +-- Ephemeral space: index creation and dropping. +s = box.schema.space.create_ephemeral() + +-- Simple creation +i = s:create_index('a') +i.unique +i.parts +i.id +i.name +i:drop() + +-- Double creation of index for ephemeral space. +i = s:create_index('a') +i = s:create_index('a') +i:drop() + +-- Double creation of index for ephemeral space +-- but with if_not_exists=true. +i = s:create_index('a') +i = s:create_index('a', {if_not_exists=true}) +i:drop() + +-- Ephemeral space can have only primary. +-- index so its id == 0 +i = s:create_index('a', {id = 10}) + +-- Set parameters: parts. +i = s:create_index('a', {parts={1}}) +i.unique +i.parts +i.id +i.name +i:drop() + +i = s:create_index('a', {parts={1,"integer"}}) +i.unique +i.parts +i.id +i.name +i:drop() + +i = s:create_index('a', {parts={1,'string',collation='Unicode'}}) +i.unique +i.parts +i.id +i.name +i:drop() + +i = s:create_index('a', {parts={1,'uint',2,'int',3,'str'}}) +i.unique +i.parts +i.id +i.name +i:drop() + +i = s:create_index('a', {parts={{5,'string',collation='Unicode'}}}) +i.unique +i.parts +i.id +i.name +i:drop() + +i = s:create_index('a', {parts={3,"scalar"}}) +i.unique +i.parts +i.id +i.name +i:drop() + +i = s:create_index('a', {parts={{5,'uint',collation='Unicode'}}}) + +i = s:create_index('a', {type='bitset',parts={1,'unsigned',2,'unsigned'}}) + + +-- Ephemeral space: methods. format = {{name='field1', type='unsigned'}, {name='field2', type='string'}} options = {engine = 'memtx', field_count = 7, format = format} s = box.schema.space.create_ephemeral(options) diff --git a/test/engine/iterator.result b/test/engine/iterator.result index f9da661..e1bc7ca 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:1109: usage: next(param, state)' +- error: 'builtin/box/schema.lua:1234: usage: next(param, state)' ... value --- -- 2.7.4