Skip to content

Commit 76d1375

Browse files
crud: support async bootstrap on storage
All Tarantool 3.x instances start in ro mode. Simple `if not box.info.ro` check isn't enough to properly bootstrap a user since it may pass before master instance became rw. box.watch is used to track the moment when instance became rw [1]. Watchers are supported since Tarantool 2.10+. This patch doesn't change existing behavior for Cartridge roles and `crud.init_storage()` calls. 1. https://www.tarantool.io/ru/doc/latest/reference/reference_lua/box_events/ Part of #412 Part of #415
1 parent 9d69b86 commit 76d1375

File tree

5 files changed

+48
-8
lines changed

5 files changed

+48
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1010
### Added
1111
* Storage-side API to wait for bootstrap:
1212
`crud.wait_until_storage_ready()` and `crud.init_storage{wait_until_ready = true}` (#412).
13+
* Asynchronous storage bootstrap for Tarantool 2.10+ (#412).
1314

1415
### Fixed
1516
* Compatibility with vshard configuration if UUIDs are omitted (#407).

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ enough access to modify some space, then you need to give access to the user.
9393
You can call `crud.init_storage{wait_until_ready = true}` or
9494
`crud.wait_until_storage_ready()` on storages to wait till API is bootstrapped.
9595

96+
You can call `crud.init_storage{async = true}` to bootstrap procedures grants
97+
asynchronously. It is useful in case your application master instances may
98+
start in ro mode (for example, if you use Tarantool 3.x). Use additional
99+
`wait_until_ready = true` flag or `crud.wait_until_storage_ready()`
100+
handle to wait for async bootstrap finish.
101+
96102
All VShard routers should call `crud.init_router()` after `vshard.router.cfg()`
97103
(or enable the `crud-router` role for Cartridge) to make `crud` functions
98104
callable via `net.box`. If a user is allowed to execute `crud` functions on

crud/storage.lua

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,20 @@ local function get_operation_user()
8888
return utils.get_this_replica_user() or 'guest'
8989
end
9090

91+
local function init_storage_api()
92+
local user = get_operation_user()
93+
94+
for _, module in ipairs(modules_with_storage_api) do
95+
init_storage_call(user, module.storage_api)
96+
end
97+
end
98+
9199
function storage.init(opts)
92-
checks({wait_until_ready = '?boolean', timeout = '?number'})
100+
checks({
101+
async = '?boolean',
102+
wait_until_ready = '?boolean',
103+
timeout = '?number',
104+
})
93105

94106
opts = opts or {}
95107

@@ -99,10 +111,11 @@ function storage.init(opts)
99111

100112
rawset(_G, utils.STORAGE_NAMESPACE, {})
101113

102-
local user = get_operation_user()
103-
104-
for _, module in ipairs(modules_with_storage_api) do
105-
init_storage_call(user, module.storage_api)
114+
if opts.async then
115+
-- It's ok if init_storage_api() will be triggered several times.
116+
box.watch('box.status', init_storage_api)
117+
else
118+
init_storage_api()
106119
end
107120

108121
if opts.wait_until_ready then

test/helper.lua

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ function helpers.start_default_cluster(g, srv_name)
708708
router_init = entrypoint_vshard(srv_name, 'router_init', false),
709709
all_init = entrypoint_vshard(srv_name, 'all_init', false),
710710
crud_init = true,
711+
async_storage_start = helpers.async_storage_start(),
711712
}
712713

713714
helpers.start_cluster(g, cartridge_cfg, vshard_cfg)
@@ -944,4 +945,18 @@ function helpers.assert_str_contains_pattern_with_replicaset_id(str, pattern)
944945
t.assert(found, ("string %q does not contain pattern %q"):format(str, pattern))
945946
end
946947

948+
949+
local function instance_start_in_ro_mode()
950+
local tarantool_version = luatest_utils.get_tarantool_version()
951+
return luatest_utils.version_ge(tarantool_version, luatest_utils.version(3, 0, 0))
952+
end
953+
954+
local function async_storage_start_supported()
955+
return box.watch ~= nil
956+
end
957+
958+
function helpers.async_storage_start()
959+
return instance_start_in_ro_mode() and async_storage_start_supported()
960+
end
961+
947962
return helpers

test/vshard_helpers/vtest.lua

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,11 +404,13 @@ local function cluster_new(g, cfg)
404404
local router_init = cfg.router_init
405405
local all_init = cfg.all_init
406406
local crud_init = cfg.crud_init
407+
local async_storage_start = cfg.async_storage_start
407408

408409
cfg.storage_init = nil
409410
cfg.router_init = nil
410411
cfg.all_init = nil
411412
cfg.crud_init = nil
413+
cfg.async_storage_start = nil
412414

413415
for replicaset_id, replicaset in pairs(cfg.sharding) do
414416
-- Luatest depends on box.cfg being ready and listening. Need to
@@ -548,9 +550,12 @@ local function cluster_new(g, cfg)
548550

549551
if crud_init then
550552
for _, replica in pairs(all_servers) do
551-
replica:exec(function()
552-
require('crud').init_storage{wait_until_ready = false}
553-
end)
553+
replica:exec(function(async)
554+
require('crud').init_storage{
555+
async = async,
556+
wait_until_ready = false,
557+
}
558+
end, {async_storage_start})
554559
end
555560

556561
for _, replica in pairs(all_servers) do

0 commit comments

Comments
 (0)