[PATCH 2/2] schema: expose space_mt and index_mt on `box.schema` table

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Sun Apr 1 14:02:46 MSK 2018


This commit allows userland to extend the space and index
metatables with their own functions or even metamethods. Reducing
barriers for this kind of experimentation is vital for user
contribution toward the improvement of Tarantool's API.

Closes #3204
---
 src/box/lua/schema.lua          | 21 ++++++++---
 test/box-tap/schema_mt.test.lua | 79 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+), 5 deletions(-)
 create mode 100755 test/box-tap/schema_mt.test.lua

diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index 8b6f69ad8..6e325a5c5 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -1075,6 +1075,7 @@ end
 internal.check_iterator_type = check_iterator_type -- export for net.box
 
 local index_mt = {}
+box.schema.index_mt = index_mt
 -- __len and __index
 index_mt.len = function(index)
     check_index_arg(index, 'len')
@@ -1289,6 +1290,7 @@ index_mt.alter = function(index, options)
 end
 
 local space_mt = {}
+box.schema.space_mt = space_mt
 space_mt.len = function(space)
     check_space_arg(space, 'len')
     local pk = space.index[0]
@@ -1409,18 +1411,27 @@ 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)
+    -- At first, reference all global index functions. At second,
+    -- choose an implementation for read operations. They are not
+    -- in a global index_mt, because they are engine specific.
+    -- All common index_mt functions must be referenced here to
+    -- be able to get them using getmetatable(index_object) - if
+    -- they are only in index_mt, then getmetatable() returns only
+    -- read ops.
+    local local_index_mt = table.deepcopy(index_mt)
+    local_index_mt.__index = function(index, key)
+        return local_index_mt[key] or index_mt[key]
+    end
     -- true if reading operations may yield
     local read_yields = space.engine == 'vinyl'
     local read_ops = {'select', 'get', 'min', 'max', 'count', 'random', 'pairs'}
     for _, op in ipairs(read_ops) do
         if read_yields then
             -- use Lua/C implmenetation
-            index_mt[op] = index_mt[op .. "_luac"]
+            local_index_mt[op] = index_mt[op .. "_luac"]
         else
             -- use FFI implementation
-            index_mt[op] = index_mt[op .. "_ffi"]
+            local_index_mt[op] = index_mt[op .. "_ffi"]
         end
     end
     index_mt.__pairs = index_mt.pairs -- Lua 5.2 compatibility
@@ -1430,7 +1441,7 @@ function box.schema.space.bless(space)
     if type(space.index) == 'table' and space.enabled then
         for j, index in pairs(space.index) do
             if type(j) == 'number' then
-                setmetatable(index, index_mt)
+                setmetatable(index, local_index_mt)
             end
         end
     end
diff --git a/test/box-tap/schema_mt.test.lua b/test/box-tap/schema_mt.test.lua
new file mode 100755
index 000000000..096c4ad60
--- /dev/null
+++ b/test/box-tap/schema_mt.test.lua
@@ -0,0 +1,79 @@
+#!/usr/bin/env tarantool
+--
+-- pr-3204: expose space_mt, index_mt into box.schema.
+--
+
+local tap = require('tap')
+local test = tap.test('schema_mt')
+
+test:plan(7)
+
+box.cfg{
+  log="tarantool.log",
+}
+
+local sp1 = box.schema.space.create('test')
+local sp2 = box.schema.space.create('test2')
+
+test:is(
+  getmetatable(sp1),
+  getmetatable(sp2),
+  'all spaces use the same metatable'
+)
+
+local idx1 = sp1:create_index('primary')
+local idx2 = sp2:create_index('primary')
+
+test:isnt(
+  getmetatable(idx1),
+  getmetatable(idx2),
+  'all indexes have their own metatable'
+)
+
+test:is(
+  idx1.get,
+  idx2.get,
+  'memtx indexes share read methods'
+)
+
+local sp3 = box.schema.space.create('test3', {engine='vinyl'})
+local sp4 = box.schema.space.create('test4', {engine='vinyl'})
+
+local idx3 = sp3:create_index('primary')
+local idx4 = sp4:create_index('primary')
+
+test:is(
+  idx3.get,
+  idx4.get,
+  'vinyl indexes share read methods'
+)
+
+test:isnt(
+  idx1.get,
+  idx3.get,
+  'memtx and vinyl indexes have separate read methods'
+)
+
+function box.schema.space_mt.foo() end
+
+test:is(
+  sp1.foo,
+  box.schema.space_mt.foo,
+  'box.schema.space_mt is mutable'
+)
+
+function box.schema.index_mt.foo() end
+
+test:is(
+  idx1.foo,
+  box.schema.index_mt.foo,
+  'box.schema.index_mt is mutable'
+)
+
+test:check()
+
+sp1:drop()
+sp2:drop()
+sp3:drop()
+sp4:drop()
+os.exit(0)
-- 
2.14.3 (Apple Git-98)




More information about the Tarantool-patches mailing list