[PATCH v2 1/3] schema: move space_mt and index_mt definition out of space bless

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Tue Apr 3 19:50:45 MSK 2018


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)




More information about the Tarantool-patches mailing list