From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Vladislav Shpilevoy Subject: [PATCH v2 1/3] schema: move space_mt and index_mt definition out of space bless Date: Tue, 3 Apr 2018 19:50:45 +0300 Message-Id: <1e3314f4ae80227b432bd85b71cb7782781e083d.1522774214.git.v.shpilevoy@tarantool.org> In-Reply-To: References: <20180402112843.k5szaedwomi4gtl3@esperanza> In-Reply-To: References: To: tarantool-patches@freelists.org Cc: vdavydov.dev@gmail.com, Vladislav Shpilevoy List-ID: Space_mt and index_mt are created individually for each space inside a giant space.bless function. It makes impossible to implement #3204: exposing space and index metatables to a user, because for this they must be global and shared between all spaces and indexes. Lets move their definition out of space.bless function, and do their duplicate inside. Needed #3204 --- src/box/lua/schema.lua | 619 +++++++++++++++++++++++++------------------------ 1 file changed, 311 insertions(+), 308 deletions(-) diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 5a0f71559..8b6f69ad8 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -1074,220 +1074,343 @@ end internal.check_iterator_type = check_iterator_type -- export for net.box -function box.schema.space.bless(space) - local index_mt = {} - -- __len and __index - index_mt.len = function(index) - check_index_arg(index, 'len') - local ret = builtin.box_index_len(index.space_id, index.id) - if ret == -1 then - box.error() - end - return tonumber(ret) - end - -- index.bsize - index_mt.bsize = function(index) - check_index_arg(index, 'bsize') - local ret = builtin.box_index_bsize(index.space_id, index.id) - if ret == -1 then - box.error() - end - return tonumber(ret) - end - index_mt.__len = index_mt.len -- Lua 5.2 compatibility - index_mt.__newindex = function(table, index) - return error('Attempt to modify a read-only table') end - index_mt.__index = index_mt - -- min and max - index_mt.min_ffi = function(index, key) - check_index_arg(index, 'min') - local pkey, pkey_end = tuple_encode(key) - if builtin.box_index_min(index.space_id, index.id, - pkey, pkey_end, ptuple) ~= 0 then - box.error() -- error - elseif ptuple[0] ~= nil then - return tuple_bless(ptuple[0]) - else - return - end +local index_mt = {} +-- __len and __index +index_mt.len = function(index) + check_index_arg(index, 'len') + local ret = builtin.box_index_len(index.space_id, index.id) + if ret == -1 then + box.error() end - index_mt.min_luac = function(index, key) - check_index_arg(index, 'min') - key = keify(key) - return internal.min(index.space_id, index.id, key); + return tonumber(ret) +end +-- index.bsize +index_mt.bsize = function(index) + check_index_arg(index, 'bsize') + local ret = builtin.box_index_bsize(index.space_id, index.id) + if ret == -1 then + box.error() end - index_mt.max_ffi = function(index, key) - check_index_arg(index, 'max') - local pkey, pkey_end = tuple_encode(key) - if builtin.box_index_max(index.space_id, index.id, - pkey, pkey_end, ptuple) ~= 0 then - box.error() -- error - elseif ptuple[0] ~= nil then - return tuple_bless(ptuple[0]) - else - return - end + return tonumber(ret) +end +index_mt.__len = index_mt.len -- Lua 5.2 compatibility +index_mt.__newindex = function(table, index) + return error('Attempt to modify a read-only table') +end +index_mt.__index = index_mt +-- min and max +index_mt.min_ffi = function(index, key) + check_index_arg(index, 'min') + local pkey, pkey_end = tuple_encode(key) + if builtin.box_index_min(index.space_id, index.id, + pkey, pkey_end, ptuple) ~= 0 then + box.error() -- error + elseif ptuple[0] ~= nil then + return tuple_bless(ptuple[0]) + else + return end - index_mt.max_luac = function(index, key) - check_index_arg(index, 'max') - key = keify(key) - return internal.max(index.space_id, index.id, key); +end +index_mt.min_luac = function(index, key) + check_index_arg(index, 'min') + key = keify(key) + return internal.min(index.space_id, index.id, key); +end +index_mt.max_ffi = function(index, key) + check_index_arg(index, 'max') + local pkey, pkey_end = tuple_encode(key) + if builtin.box_index_max(index.space_id, index.id, + pkey, pkey_end, ptuple) ~= 0 then + box.error() -- error + elseif ptuple[0] ~= nil then + return tuple_bless(ptuple[0]) + else + return end - index_mt.random_ffi = function(index, rnd) - check_index_arg(index, 'random') - rnd = rnd or math.random() - if builtin.box_index_random(index.space_id, index.id, rnd, - ptuple) ~= 0 then - box.error() -- error - elseif ptuple[0] ~= nil then - return tuple_bless(ptuple[0]) - else - return - end +end +index_mt.max_luac = function(index, key) + check_index_arg(index, 'max') + key = keify(key) + return internal.max(index.space_id, index.id, key); +end +index_mt.random_ffi = function(index, rnd) + check_index_arg(index, 'random') + rnd = rnd or math.random() + if builtin.box_index_random(index.space_id, index.id, rnd, + ptuple) ~= 0 then + box.error() -- error + elseif ptuple[0] ~= nil then + return tuple_bless(ptuple[0]) + else + return end - index_mt.random_luac = function(index, rnd) - check_index_arg(index, 'random') - rnd = rnd or math.random() - return internal.random(index.space_id, index.id, rnd); - end - -- iteration - index_mt.pairs_ffi = function(index, key, opts) - check_index_arg(index, 'pairs') - local pkey, pkey_end = tuple_encode(key) - local itype = check_iterator_type(opts, pkey + 1 >= pkey_end); - - local keybuf = ffi.string(pkey, pkey_end - pkey) - local pkeybuf = ffi.cast('const char *', keybuf) - local cdata = builtin.box_index_iterator(index.space_id, index.id, - itype, pkeybuf, pkeybuf + #keybuf); - if cdata == nil then - box.error() - end - return fun.wrap(iterator_gen, keybuf, - ffi.gc(cdata, builtin.box_iterator_free)) - end - index_mt.pairs_luac = function(index, key, opts) - check_index_arg(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 = internal.iterator(index.space_id, index.id, itype, keymp); - return fun.wrap(iterator_gen_luac, keybuf, - ffi.gc(cdata, builtin.box_iterator_free)) - end - - -- index subtree size - index_mt.count_ffi = function(index, key, opts) - check_index_arg(index, 'count') - local pkey, pkey_end = tuple_encode(key) - local itype = check_iterator_type(opts, pkey + 1 >= pkey_end); - local count = builtin.box_index_count(index.space_id, index.id, - itype, pkey, pkey_end); - if count == -1 then - box.error() - end - return tonumber(count) - end - index_mt.count_luac = function(index, key, opts) - check_index_arg(index, 'count') - key = keify(key) - local itype = check_iterator_type(opts, #key == 0); - return internal.count(index.space_id, index.id, itype, key); - end - - index_mt.get_ffi = function(index, key) - check_index_arg(index, 'get') - local key, key_end = tuple_encode(key) - if builtin.box_index_get(index.space_id, index.id, - key, key_end, ptuple) ~= 0 then - return box.error() -- error - elseif ptuple[0] ~= nil then - return tuple_bless(ptuple[0]) - else - return - end +end +index_mt.random_luac = function(index, rnd) + check_index_arg(index, 'random') + rnd = rnd or math.random() + return internal.random(index.space_id, index.id, rnd); +end +-- iteration +index_mt.pairs_ffi = function(index, key, opts) + check_index_arg(index, 'pairs') + local pkey, pkey_end = tuple_encode(key) + local itype = check_iterator_type(opts, pkey + 1 >= pkey_end); + + local keybuf = ffi.string(pkey, pkey_end - pkey) + local pkeybuf = ffi.cast('const char *', keybuf) + local cdata = builtin.box_index_iterator(index.space_id, index.id, + itype, pkeybuf, pkeybuf + #keybuf); + if cdata == nil then + box.error() end - index_mt.get_luac = function(index, key) - check_index_arg(index, 'get') - key = keify(key) - return internal.get(index.space_id, index.id, key) + return fun.wrap(iterator_gen, keybuf, + ffi.gc(cdata, builtin.box_iterator_free)) +end +index_mt.pairs_luac = function(index, key, opts) + check_index_arg(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 = internal.iterator(index.space_id, index.id, itype, keymp); + return fun.wrap(iterator_gen_luac, keybuf, + ffi.gc(cdata, builtin.box_iterator_free)) +end + +-- index subtree size +index_mt.count_ffi = function(index, key, opts) + check_index_arg(index, 'count') + local pkey, pkey_end = tuple_encode(key) + local itype = check_iterator_type(opts, pkey + 1 >= pkey_end); + local count = builtin.box_index_count(index.space_id, index.id, + itype, pkey, pkey_end); + if count == -1 then + box.error() end + return tonumber(count) +end +index_mt.count_luac = function(index, key, opts) + check_index_arg(index, 'count') + key = keify(key) + local itype = check_iterator_type(opts, #key == 0); + return internal.count(index.space_id, index.id, itype, key); +end - local function check_select_opts(opts, key_is_nil) - local offset = 0 - local limit = 4294967295 - local iterator = check_iterator_type(opts, key_is_nil) - if opts ~= nil then - if opts.offset ~= nil then - offset = opts.offset - end - if opts.limit ~= nil then - limit = opts.limit - end +index_mt.get_ffi = function(index, key) + check_index_arg(index, 'get') + local key, key_end = tuple_encode(key) + if builtin.box_index_get(index.space_id, index.id, + key, key_end, ptuple) ~= 0 then + return box.error() -- error + elseif ptuple[0] ~= nil then + return tuple_bless(ptuple[0]) + else + return + end +end +index_mt.get_luac = function(index, key) + check_index_arg(index, 'get') + key = keify(key) + return internal.get(index.space_id, index.id, key) +end + +local function check_select_opts(opts, key_is_nil) + local offset = 0 + local limit = 4294967295 + local iterator = check_iterator_type(opts, key_is_nil) + if opts ~= nil then + if opts.offset ~= nil then + offset = opts.offset + end + if opts.limit ~= nil then + limit = opts.limit end - return iterator, offset, limit end + return iterator, offset, limit +end - index_mt.select_ffi = function(index, key, opts) - check_index_arg(index, 'select') - local key, key_end = tuple_encode(key) - local iterator, offset, limit = check_select_opts(opts, key + 1 >= key_end) +index_mt.select_ffi = function(index, key, opts) + check_index_arg(index, 'select') + local key, key_end = tuple_encode(key) + local iterator, offset, limit = check_select_opts(opts, key + 1 >= key_end) - local port = ffi.cast('struct port *', port_tuple) + local port = ffi.cast('struct port *', port_tuple) - if builtin.box_select(index.space_id, index.id, - iterator, offset, limit, key, key_end, port) ~= 0 then - return box.error() - end + if builtin.box_select(index.space_id, index.id, + iterator, offset, limit, key, key_end, port) ~= 0 then + return box.error() + end - local ret = {} - local entry = port_tuple.first - for i=1,tonumber(port_tuple.size),1 do - ret[i] = tuple_bless(entry.tuple) - entry = entry.next - end - builtin.port_destroy(port); - return ret + local ret = {} + local entry = port_tuple.first + for i=1,tonumber(port_tuple.size),1 do + ret[i] = tuple_bless(entry.tuple) + entry = entry.next end + builtin.port_destroy(port); + return ret +end + +index_mt.select_luac = function(index, key, opts) + check_index_arg(index, 'select') + local key = keify(key) + local iterator, offset, limit = check_select_opts(opts, #key == 0) + return internal.select(index.space_id, index.id, iterator, + offset, limit, key) +end - index_mt.select_luac = function(index, key, opts) - check_index_arg(index, 'select') - local key = keify(key) - local iterator, offset, limit = check_select_opts(opts, #key == 0) - return internal.select(index.space_id, index.id, iterator, - offset, limit, key) +index_mt.update = function(index, key, ops) + check_index_arg(index, 'update') + return internal.update(index.space_id, index.id, keify(key), ops); +end +index_mt.delete = function(index, key) + check_index_arg(index, 'delete') + return internal.delete(index.space_id, index.id, keify(key)); +end + +index_mt.info = function(index) + return internal.info(index.space_id, index.id); +end + +index_mt.drop = function(index) + check_index_arg(index, 'drop') + return box.schema.index.drop(index.space_id, index.id) +end +index_mt.rename = function(index, name) + check_index_arg(index, 'rename') + return box.schema.index.rename(index.space_id, index.id, name) +end +index_mt.alter = function(index, options) + check_index_arg(index, 'alter') + if index.id == nil or index.space_id == nil then + box.error(box.error.PROC_LUA, "Usage: index:alter{opts}") end + return box.schema.index.alter(index.space_id, index.id, options) +end - index_mt.update = function(index, key, ops) - check_index_arg(index, 'update') - return internal.update(index.space_id, index.id, keify(key), ops); +local space_mt = {} +space_mt.len = function(space) + check_space_arg(space, 'len') + local pk = space.index[0] + if pk == nil then + return 0 -- empty space without indexes, return 0 end - index_mt.delete = function(index, key) - check_index_arg(index, 'delete') - return internal.delete(index.space_id, index.id, keify(key)); + return space.index[0]:len() +end +space_mt.count = function(space, key, opts) + check_space_arg(space, 'count') + local pk = space.index[0] + if pk == nil then + return 0 -- empty space without indexes, return 0 end - - index_mt.info = function(index) - return internal.info(index.space_id, index.id); + return pk:count(key, opts) +end +space_mt.bsize = function(space) + check_space_arg(space, 'bsize') + local s = builtin.space_by_id(space.id) + if s == nil then + box.error(box.error.NO_SUCH_SPACE, space.name) end + return builtin.space_bsize(s) +end +space_mt.__newindex = index_mt.__newindex - index_mt.drop = function(index) - check_index_arg(index, 'drop') - return box.schema.index.drop(index.space_id, index.id) +space_mt.get = function(space, key) + check_space_arg(space, 'get') + return check_primary_index(space):get(key) +end +space_mt.select = function(space, key, opts) + check_space_arg(space, 'select') + return check_primary_index(space):select(key, opts) +end +space_mt.insert = function(space, tuple) + check_space_arg(space, 'insert') + return internal.insert(space.id, tuple); +end +space_mt.replace = function(space, tuple) + check_space_arg(space, 'replace') + return internal.replace(space.id, tuple); +end +space_mt.put = space_mt.replace; -- put is an alias for replace +space_mt.update = function(space, key, ops) + check_space_arg(space, 'update') + return check_primary_index(space):update(key, ops) +end +space_mt.upsert = function(space, tuple_key, ops, deprecated) + check_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 - index_mt.rename = function(index, name) - check_index_arg(index, 'rename') - return box.schema.index.rename(index.space_id, index.id, name) + return internal.upsert(space.id, tuple_key, ops); +end +space_mt.delete = function(space, key) + check_space_arg(space, 'delete') + return check_primary_index(space):delete(key) +end +-- Assumes that spaceno has a TREE (NUM) primary key +-- inserts a tuple after getting the next value of the +-- primary key and returns it back to the user +space_mt.auto_increment = function(space, tuple) + check_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 - index_mt.alter = function(index, options) - check_index_arg(index, 'alter') - if index.id == nil or index.space_id == nil then - box.error(box.error.PROC_LUA, "Usage: index:alter{opts}") - end - return box.schema.index.alter(index.space_id, index.id, options) + table.insert(tuple, 1, max + 1) + return space:insert(tuple) +end + +space_mt.pairs = function(space, key, opts) + check_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_mt.__pairs = space_mt.pairs -- Lua 5.2 compatibility +space_mt.__ipairs = space_mt.pairs -- Lua 5.2 compatibility +space_mt.truncate = function(space) + check_space_arg(space, 'truncate') + return internal.truncate(space.id) +end +space_mt.format = function(space, format) + check_space_arg(space, 'format') + return box.schema.space.format(space.id, format) +end +space_mt.drop = function(space) + check_space_arg(space, 'drop') + check_space_exists(space) + return box.schema.space.drop(space.id, space.name) +end +space_mt.rename = function(space, name) + check_space_arg(space, 'rename') + check_space_exists(space) + return box.schema.space.rename(space.id, name) +end +space_mt.create_index = function(space, name, options) + check_space_arg(space, 'create_index') + check_space_exists(space) + return box.schema.index.create(space.id, name, options) +end +space_mt.run_triggers = function(space, yesno) + check_space_arg(space, 'run_triggers') + local s = builtin.space_by_id(space.id) + if s == nil then + box.error(box.error.NO_SUCH_SPACE, space.name) end + builtin.space_run_triggers(s, yesno) +end +space_mt.__index = space_mt +function box.schema.space.bless(space) + local index_mt = table.deepcopy(index_mt) + local space_mt = table.deepcopy(space_mt) -- true if reading operations may yield local read_yields = space.engine == 'vinyl' local read_ops = {'select', 'get', 'min', 'max', 'count', 'random', 'pairs'} @@ -1302,126 +1425,6 @@ function box.schema.space.bless(space) end index_mt.__pairs = index_mt.pairs -- Lua 5.2 compatibility index_mt.__ipairs = index_mt.pairs -- Lua 5.2 compatibility - -- - local space_mt = {} - space_mt.len = function(space) - check_space_arg(space, 'len') - local pk = space.index[0] - if pk == nil then - return 0 -- empty space without indexes, return 0 - end - return space.index[0]:len() - end - space_mt.count = function(space, key, opts) - check_space_arg(space, 'count') - local pk = space.index[0] - if pk == nil then - return 0 -- empty space without indexes, return 0 - end - return pk:count(key, opts) - end - space_mt.bsize = function(space) - check_space_arg(space, 'bsize') - local s = builtin.space_by_id(space.id) - if s == nil then - box.error(box.error.NO_SUCH_SPACE, space.name) - end - return builtin.space_bsize(s) - end - space_mt.__newindex = index_mt.__newindex - - space_mt.get = function(space, key) - check_space_arg(space, 'get') - return check_primary_index(space):get(key) - end - space_mt.select = function(space, key, opts) - check_space_arg(space, 'select') - return check_primary_index(space):select(key, opts) - end - space_mt.insert = function(space, tuple) - check_space_arg(space, 'insert') - return internal.insert(space.id, tuple); - end - space_mt.replace = function(space, tuple) - check_space_arg(space, 'replace') - return internal.replace(space.id, tuple); - end - space_mt.put = space_mt.replace; -- put is an alias for replace - space_mt.update = function(space, key, ops) - check_space_arg(space, 'update') - return check_primary_index(space):update(key, ops) - end - space_mt.upsert = function(space, tuple_key, ops, deprecated) - check_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 internal.upsert(space.id, tuple_key, ops); - end - space_mt.delete = function(space, key) - check_space_arg(space, 'delete') - return check_primary_index(space):delete(key) - end --- Assumes that spaceno has a TREE (NUM) primary key --- inserts a tuple after getting the next value of the --- primary key and returns it back to the user - space_mt.auto_increment = function(space, tuple) - check_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_mt.pairs = function(space, key, opts) - check_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_mt.__pairs = space_mt.pairs -- Lua 5.2 compatibility - space_mt.__ipairs = space_mt.pairs -- Lua 5.2 compatibility - space_mt.truncate = function(space) - check_space_arg(space, 'truncate') - return internal.truncate(space.id) - end - space_mt.format = function(space, format) - check_space_arg(space, 'format') - return box.schema.space.format(space.id, format) - end - space_mt.drop = function(space) - check_space_arg(space, 'drop') - check_space_exists(space) - return box.schema.space.drop(space.id, space.name) - end - space_mt.rename = function(space, name) - check_space_arg(space, 'rename') - check_space_exists(space) - return box.schema.space.rename(space.id, name) - end - space_mt.create_index = function(space, name, options) - check_space_arg(space, 'create_index') - check_space_exists(space) - return box.schema.index.create(space.id, name, options) - end - space_mt.run_triggers = function(space, yesno) - check_space_arg(space, 'run_triggers') - local s = builtin.space_by_id(space.id) - if s == nil then - box.error(box.error.NO_SUCH_SPACE, space.name) - end - builtin.space_run_triggers(s, yesno) - end - space_mt.__index = space_mt setmetatable(space, space_mt) if type(space.index) == 'table' and space.enabled then -- 2.14.3 (Apple Git-98)