Skip to content

Add the "lazy start" technique to initialization stage #131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 68 additions & 11 deletions queue/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,85 @@ end
queue = setmetatable({
driver = core_drivers,
register_driver = register_driver,
}, { __index = function() print(debug.traceback()) error("Please run box.cfg{} first") end })
}, { __index = function()
print(debug.traceback())
error('Please configure box.cfg{} in read/write mode first')
end
})

-- Used to store the original methods
local orig_cfg = nil
local orig_call = nil

local wrapper_impl

local function cfg_wrapper(...)
box.cfg = orig_cfg
return wrapper_impl(...)
end

if rawget(box, 'space') == nil then
local orig_cfg = box.cfg
box.cfg = function(...)
local result = { orig_cfg(...) }
local function cfg_call_wrapper(cfg, ...)
local cfg_mt = getmetatable(box.cfg)
cfg_mt.__call = orig_call
return wrapper_impl(...)
end

local function wrap_box_cfg()
if type(box.cfg) == 'function' then
-- box.cfg before the first box.cfg call
orig_cfg = box.cfg
box.cfg = cfg_wrapper
elseif type(box.cfg) == 'table' then
-- box.cfg after the first box.cfg call
local cfg_mt = getmetatable(box.cfg)
orig_call = cfg_mt.__call
cfg_mt.__call = cfg_call_wrapper
else
error('The box.cfg type is unexpected: ' .. type(box.cfg))
end
end

function wrapper_impl(...)
local result = { pcall(box.cfg,...) }
if result[1] then
table.remove(result, 1)
else
wrap_box_cfg()
error(result[2])
end

if box.info.ro == false then
local abstract = require 'queue.abstract'
for name, val in pairs(abstract) do
rawset(queue, name, val)
end
abstract.driver = queue.driver
setmetatable(queue, getmetatable(abstract))
queue.start()
else
-- Delay a start until the box will be configured
-- with read_only = false
wrap_box_cfg()
end
return unpack(result)
end

return unpack(result)
--- Implementation of the “lazy start” procedure.
-- The queue module is loaded immediately if the instance was
-- configured with read_only = false. Otherwise, a start is
-- delayed until the instance will be configured with read_only = false.
local function queue_init()
if rawget(box, 'space') ~= nil and box.info.ro == false then
-- The box was configured with read_only = false
queue = require('queue.abstract')
queue.register_driver = register_driver
queue.driver = core_drivers
queue.start()
else
wrap_box_cfg()
end
else
queue = require 'queue.abstract'
queue.register_driver = register_driver
queue.driver = core_drivers
queue.start()
end

queue_init()

return queue
2 changes: 1 addition & 1 deletion t/000-init.t
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ test:test('access to queue until box.cfg is started', function(test)

local s, e = pcall(function() return queue.tube end)
test:ok(not s, 'exception was generated')
test:ok(string.match(e, 'Please run box.cfg') ~= nil, 'Exception text')
test:ok(string.match(e, 'Please configure box.cfg') ~= nil, 'Exception text')
end)

local state = require('queue.abstract.state')
Expand Down
33 changes: 33 additions & 0 deletions t/150-lazy-start.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env tarantool
local tap = require('tap')
local tnt = require('t.tnt')

local test = tap.test('test driver register')
test:plan(3)

local function check_lazy_start()
-- Needed for bootstrap
tnt.cfg{}

tnt.cfg{read_only = true}
local queue = require('queue')

local err_msg = 'Please configure box.cfg{} in read/write mode first'
local res, err = pcall(function() queue.stats() end)
local check = not res and string.match(err,err_msg) ~= nil
test:ok(check, 'check queue delayed start')

tnt.cfg({read_only = true})
res, err = pcall(function() queue.stats() end)
check = not res and string.match(err, err_msg) ~= nil
test:ok(check, 'check box reconfiguration with read_only = true')

tnt.cfg({read_only = false})
res = pcall(function() queue.stats() end)
test:ok(res, 'queue has been started')
end

check_lazy_start()

tnt.finish()
os.exit(test:check() and 0 or 1)