[tarantool-patches] [PATCH] Updata replicaser mt on package reload

AKhatskevich avkhatskevich at tarantool.org
Mon Jun 4 19:27:55 MSK 2018


Update metatables of `replicaset` and `replica` objects on package
reload in a way that updates metatables of already existing objects.

Closes: #112
---
Branch: https://github.com/tarantool/vshard/tree/kh/gh-112-reload-mt
Issue: https://github.com/tarantool/vshard/issues/112

Note: There is an idea that all objects should be recreated instead.

 test/router/reload.result   | 43 +++++++++++++++++++++++++++++++++++++++++++
 test/router/reload.test.lua | 14 ++++++++++++++
 vshard/replicaset.lua       | 39 +++++++++++++++++++++++++++++++++++----
 3 files changed, 92 insertions(+), 4 deletions(-)

diff --git a/test/router/reload.result b/test/router/reload.result
index 19a9ead..9c0a19b 100644
--- a/test/router/reload.result
+++ b/test/router/reload.result
@@ -174,6 +174,49 @@ vshard.router.module_version()
 check_reloaded()
 ---
 ...
+assert(rawget(_G, '__module_vshard_replicaset') ~= nil)
+---
+- true
+...
+_, replicaset = next(vshard.router.internal.replicasets)
+---
+...
+old_mt_method = getmetatable(replicaset).__index.call
+---
+...
+M = require('vshard.replicaset').internal
+---
+...
+M.errinj.ERRINJ_RELOAD = true
+---
+...
+package.loaded["vshard.replicaset"] = nil
+---
+...
+ok, msg = pcall(require, 'vshard.replicaset')
+---
+...
+assert(ok == false)
+---
+- true
+...
+old_mt_method == getmetatable(replicaset).__index.call
+---
+- true
+...
+M.errinj.ERRINJ_RELOAD = false
+---
+...
+package.loaded["vshard.replicaset"] = nil
+---
+...
+_ = require('vshard.replicaset')
+---
+...
+old_mt_method == getmetatable(replicaset).__index.call
+---
+- false
+...
 test_run:switch('default')
 ---
 - true
diff --git a/test/router/reload.test.lua b/test/router/reload.test.lua
index 6e21b74..cdb5d50 100644
--- a/test/router/reload.test.lua
+++ b/test/router/reload.test.lua
@@ -86,6 +86,20 @@ _ = require('vshard.router')
 vshard.router.module_version()
 check_reloaded()
 
+assert(rawget(_G, '__module_vshard_replicaset') ~= nil)
+_, replicaset = next(vshard.router.internal.replicasets)
+old_mt_method = getmetatable(replicaset).__index.call
+M = require('vshard.replicaset').internal
+M.errinj.ERRINJ_RELOAD = true
+package.loaded["vshard.replicaset"] = nil
+ok, msg = pcall(require, 'vshard.replicaset')
+assert(ok == false)
+old_mt_method == getmetatable(replicaset).__index.call
+M.errinj.ERRINJ_RELOAD = false
+package.loaded["vshard.replicaset"] = nil
+_ = require('vshard.replicaset')
+old_mt_method == getmetatable(replicaset).__index.call
+
 test_run:switch('default')
 test_run:cmd('stop server router_1')
 test_run:cmd('cleanup server router_1')
diff --git a/vshard/replicaset.lua b/vshard/replicaset.lua
index 7fcf2df..62a9b9e 100644
--- a/vshard/replicaset.lua
+++ b/vshard/replicaset.lua
@@ -50,6 +50,21 @@ local luri = require('uri')
 local ffi = require('ffi')
 local gsc = require('vshard.util').generate_self_checker
 
+local M = rawget(_G, '__module_vshard_replicaset')
+if not M then
+    --
+    -- The module is loaded for the first time.
+    --
+    M = {
+        errinj = {
+            ERRINJ_RELOAD = false,
+        },
+        -- Cache metatables of old objects to update them.
+        replicaset_mt = {},
+        replica_mt = {},
+    }
+end
+
 --
 -- on_connect() trigger for net.box
 --
@@ -383,7 +398,7 @@ local replicaset_mt = {
 --
 local index = {}
 for name, func in pairs(replicaset_mt.__index) do
-    index[name] = gsc("replicaset", name, replicaset_mt, func)
+    index[name] = gsc("replicaset", name, M.replicaset_mt, func)
 end
 replicaset_mt.__index = index
 
@@ -408,7 +423,7 @@ local replica_mt = {
 }
 index = {}
 for name, func in pairs(replica_mt.__index) do
-    index[name] = gsc("replica", name, replica_mt, func)
+    index[name] = gsc("replica", name, M.replica_mt, func)
 end
 replica_mt.__index = index
 
@@ -523,7 +538,7 @@ local function buildall(sharding_cfg, old_replicasets)
             weight = replicaset.weight,
             bucket_count = 0,
             lock = replicaset.lock,
-        }, replicaset_mt)
+        }, M.replicaset_mt)
         local priority_list = {}
         for replica_uuid, replica in pairs(replicaset.replicas) do
             local old_replica = old_replicaset and
@@ -536,7 +551,7 @@ local function buildall(sharding_cfg, old_replicasets)
                 zone = replica.zone, net_timeout = consts.CALL_TIMEOUT_MIN,
                 net_sequential_ok = 0, net_sequential_fail = 0,
                 down_ts = curr_ts, old_replica = old_replica,
-            }, replica_mt)
+            }, M.replica_mt)
             new_replicaset.replicas[replica_uuid] = new_replica
             if replica.master then
                 new_replicaset.master = new_replica
@@ -592,8 +607,24 @@ local function wait_masters_connect(replicasets)
     end
 end
 
+if M.errinj.ERRINJ_RELOAD then
+    error('Error injection: reload')
+end
+
+--
+-- In case the module is loaded correctly, do externally-visible changes.
+--
+if not rawget(_G, '__module_vshard_replicaset') then
+    rawset(_G, '__module_vshard_replicaset', M)
+end
+M.replicaset_mt.__index = replicaset_mt.__index
+M.replicaset_mt.__tostring = replicaset_mt.__tostring
+M.replica_mt.__index = replica_mt.__index
+M.replica_mt.__tostring = replica_mt.__tostring
+
 return {
     buildall = buildall,
     calculate_etalon_balance = cluster_calculate_etalon_balance,
+    internal = M,
     wait_masters_connect = wait_masters_connect,
 }
-- 
2.14.1





More information about the Tarantool-patches mailing list