Skip to content

Commit 587c7a7

Browse files
committed
Add the "lazy start" technique to initialization stage
Previously, if an instance was started in read_only mode, it could throw an error when initializing the queue module, like this: "Can't modify data because this instance is in read-only mode". To avoid such behavior the "lazy start" technique has been added: 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. Closes #122
1 parent 103e947 commit 587c7a7

File tree

2 files changed

+89
-17
lines changed

2 files changed

+89
-17
lines changed

queue/init.lua

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,65 @@ queue = setmetatable({
2626
register_driver = register_driver,
2727
}, { __index = function() print(debug.traceback()) error("Please run box.cfg{} first") end })
2828

29-
local function queue_init()
30-
if rawget(box, 'space') == nil then
31-
local orig_cfg = box.cfg
32-
box.cfg = function(...)
33-
local result = { orig_cfg(...) }
34-
35-
local abstract = require 'queue.abstract'
36-
for name, val in pairs(abstract) do
37-
rawset(queue, name, val)
38-
end
39-
abstract.driver = queue.driver
40-
setmetatable(queue, getmetatable(abstract))
41-
queue.start()
42-
43-
return unpack(result)
44-
end
29+
-- Used to store the original methods
30+
local orig_cfg = nil
31+
local orig_call = nil
32+
33+
local wrapper_impl
34+
35+
local function cfg_wrapper(...)
36+
box.cfg = orig_cfg
37+
return wrapper_impl(...)
38+
end
39+
40+
local function cfg_call_wrapper(cfg, ...)
41+
local cfg_mt = getmetatable(box.cfg)
42+
cfg_mt.__call = orig_call
43+
return wrapper_impl(...)
44+
end
45+
46+
local function wrap_cfg_call()
47+
local cfg_mt = getmetatable(box.cfg)
48+
orig_call = cfg_mt.__call
49+
cfg_mt.__call = cfg_call_wrapper
50+
end
51+
52+
function wrapper_impl(...)
53+
local result = { box.cfg(...) }
54+
if box.cfg.read_only then
55+
-- Delay a start until the box will be configured
56+
-- with read_only = false
57+
wrap_cfg_call()
4558
else
46-
queue = require 'queue.abstract'
59+
local abstract = require 'queue.abstract'
60+
for name, val in pairs(abstract) do
61+
rawset(queue, name, val)
62+
end
63+
abstract.driver = queue.driver
64+
setmetatable(queue, getmetatable(abstract))
65+
queue.start()
66+
end
67+
return unpack(result)
68+
end
69+
70+
--- Implementation of the “lazy start” procedure.
71+
-- The queue module is loaded immediately if the instance was
72+
-- configured with read_only = false. Otherwise, a start is
73+
-- delayed until the instance will be configured with read_only = false.
74+
local function queue_init()
75+
if rawget(box, 'space') ~= nil and not box.cfg.read_only then
76+
-- The box was configured with read_only = false
77+
queue = require('queue.abstract')
4778
queue.register_driver = register_driver
4879
queue.driver = core_drivers
4980
queue.start()
81+
elseif rawget(box, 'space') == nil then
82+
-- The box is not configured yet
83+
orig_cfg = box.cfg
84+
box.cfg = cfg_wrapper
85+
else
86+
-- The box was configured with read_only = true
87+
wrap_cfg_call()
5088
end
5189
end
5290

t/150-lazy-start.t

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env tarantool
2+
local tap = require('tap')
3+
local tnt = require('t.tnt')
4+
5+
local test = tap.test('test driver register')
6+
test:plan(3)
7+
8+
local function check_lazy_start()
9+
-- Needed for bootstrap
10+
tnt.cfg{}
11+
12+
tnt.cfg{read_only = true}
13+
local queue = require('queue')
14+
15+
local res, err = pcall(function() queue.stats() end)
16+
local check = not res and
17+
string.match(err, 'Please run box.cfg{} first') ~= nil
18+
test:ok(check, 'check queue delayed start')
19+
20+
tnt.cfg({read_only = true})
21+
res, err = pcall(function() queue.stats() end)
22+
check = not res and
23+
string.match(err, 'Please run box.cfg{} first') ~= nil
24+
test:ok(check, 'check box reconfiguration with read_only = true')
25+
26+
tnt.cfg({read_only = false})
27+
res = pcall(function() queue.stats() end)
28+
test:ok(res, 'queue has been started')
29+
end
30+
31+
check_lazy_start()
32+
33+
tnt.finish()
34+
os.exit(test:check() and 0 or 1)

0 commit comments

Comments
 (0)