Skip to content
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

Auto-master detection for storages, rebalancer location selection, and bug fixes #439

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b2df47c
storage: fix too early drop of SENT buckets
Gerold103 Sep 26, 2023
1986fbd
storage: fix false-positive recovery of SENDING
Gerold103 Oct 20, 2023
6985ddc
replicaset: rename is_auto_master to is_master_auto
Gerold103 Oct 4, 2023
54c027e
storage: factor out check_is_master() function
Gerold103 Oct 4, 2023
1d5a824
rebalancer: return nil in rebalancer_apply_routes
Gerold103 Oct 4, 2023
ba75476
storage: use util.fiber_cond_wait everywhere
Gerold103 Oct 5, 2023
f4beb7e
storage: scatter some fiber cancellation points
Gerold103 Oct 5, 2023
3bf51b2
storage: move master management code
Gerold103 Oct 6, 2023
a56d360
storage: move rebalancer activation code
Gerold103 Oct 6, 2023
f976c0f
storage: refactor storage_cfg()
Gerold103 Aug 29, 2023
6de3cff
storage: move master and rebalancer role commit
Gerold103 Oct 9, 2023
9ef6c3b
storage: introduce is_master flag
Gerold103 Oct 9, 2023
f7126de
test: rename storage_2_test.lua
Gerold103 Oct 9, 2023
295b5dc
storage: introduce master='auto' for own rs
Gerold103 Oct 9, 2023
20ca1ca
storage: allow some internal funcs only on master
Gerold103 Sep 10, 2023
604b16b
storage: introduce recovery_bucket_stat()
Gerold103 Sep 11, 2023
dbc4a64
storage: introduce master_call() wrapper
Gerold103 Sep 10, 2023
760eb70
cfg: introduce extract_vshard and extract_box
Gerold103 Oct 13, 2023
0728c29
storage: add timeouts to all master_call()
Gerold103 Oct 13, 2023
0664937
replicaset: create missing conns in locate_master()
Gerold103 Oct 16, 2023
e1083fd
storage: introduce full master discovery
Gerold103 Oct 16, 2023
1cd2873
rebalancer: enable it on auto-master replicasets
Gerold103 Sep 15, 2023
a0d7ddc
storage: introduce no-activity timeout for conns
Gerold103 Sep 10, 2023
9380966
rebalancer: introduce rebalancer flag
Gerold103 Sep 28, 2023
201f1ee
rebalancer: introduce rebalancer_mode
Gerold103 Oct 3, 2023
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
77 changes: 62 additions & 15 deletions test/luatest_helpers/vtest.lua
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ local function cluster_new(g, cfg)
local all_servers = {}
local masters = {}
local replicas = {}
local master_map = {}
for replicaset_uuid, replicaset in pairs(cfg.sharding) do
-- Luatest depends on box.cfg being ready and listening. Need to
-- configure it before vshard.storage.cfg().
Expand All @@ -169,7 +170,21 @@ local function cluster_new(g, cfg)
box_cfg.replicaset_uuid = replicaset_uuid
box_cfg.listen = helpers.instance_uri(replica.name)
-- Need to specify read-only explicitly to know how is master.
box_cfg.read_only = not replica.master
local is_master
if replica.read_only ~= nil then
is_master = not replica.read_only
else
is_master = replica.master
end
if is_master then
local prev_uuid = master_map[replicaset_uuid]
if prev_uuid then
error('On bootstrap each replicaset has to have exactly '..
'one master')
end
master_map[replicaset_uuid] = replica_uuid
end
box_cfg.read_only = not is_master
box_cfg.memtx_use_mvcc_engine = cfg.memtx_use_mvcc_engine
local server = g.cluster:build_server({
alias = name,
Expand All @@ -184,7 +199,7 @@ local function cluster_new(g, cfg)
g.cluster:add_server(server)

table.insert(all_servers, server)
if replica.master then
if is_master then
table.insert(masters, server)
else
table.insert(replicas, server)
Expand Down Expand Up @@ -332,20 +347,29 @@ local function cluster_bootstrap(g, cfg)
local masters = {}
local etalon_balance = {}
local replicaset_count = 0
for rs_uuid, rs in pairs(cfg.sharding) do
local is_master_found = false
for _, rep in pairs(rs.replicas) do
if rep.master then
t.assert(not is_master_found, 'only one master')
local server = g[rep.name]
t.assert_not_equals(server, nil, 'find master instance')
t.assert_equals(server:replicaset_uuid(), rs_uuid,
'replicaset uuid')
masters[rs_uuid] = server
is_master_found = true
end
local master_info, err = cluster_exec_each(g, function()
local info = box.info
return {
is_master = ivshard.storage.internal.is_master,
rs_uuid = ivutil.replicaset_uuid(info),
uuid = info.uuid,
}
end)
t.assert_equals(err, nil)
for name, info in pairs(master_info) do
if info.is_master then
local rs_uuid = info.rs_uuid
local server = g[name]
t.assert_not_equals(server, nil, 'find master instance')
t.assert_equals(masters[rs_uuid], nil, 'only one master')
local rs_cfg = cfg.sharding[rs_uuid]
t.assert_not_equals(rs_cfg, nil)
t.assert_not_equals(rs_cfg.replicas[info.uuid], nil)
masters[info.rs_uuid] = server
end
t.assert(is_master_found, 'found master')
end
for rs_uuid, rs in pairs(cfg.sharding) do
t.assert_not_equals(masters[rs_uuid], nil, 'found master')
local weight = rs.weight
if weight == nil then
weight = 1
Expand Down Expand Up @@ -420,6 +444,7 @@ end
local function cluster_rebalancer_enable(g)
local _, err = cluster_exec_each(g, function()
ivshard.storage.rebalancer_enable()
ivshard.storage.rebalancer_wakeup()
end)
t.assert_equals(err, nil, 'rebalancer enable')
end
Expand Down Expand Up @@ -527,6 +552,26 @@ local function cluster_wait_fullsync(g)
end
end

local function cluster_rebalancer_find_all(g)
local map, err = cluster_exec_each(g, function()
return ivshard.storage.internal.rebalancer_fiber ~= nil
end)
t.assert_equals(err, nil)
local names = {}
for name, res in pairs(map) do
if res then
table.insert(names, name)
end
end
return names
end

local function cluster_rebalancer_find(g)
local names = cluster_rebalancer_find_all(g)
t.assert_lt(#names, 2)
return names[1]
end

--
-- Stop data node. Wrapped into a one-line function in case in the future would
-- want to do something more here.
Expand Down Expand Up @@ -768,6 +813,7 @@ return {
cluster_rebalancer_enable = cluster_rebalancer_enable,
cluster_wait_vclock_all = cluster_wait_vclock_all,
cluster_wait_fullsync = cluster_wait_fullsync,
cluster_rebalancer_find = cluster_rebalancer_find,
storage_first_bucket = storage_first_bucket,
storage_stop = storage_stop,
storage_start = storage_start,
Expand All @@ -782,6 +828,7 @@ return {
service_wait_for_new_ok = service_wait_for_new_ok,
service_wait_for_error = service_wait_for_error,
service_wait_for_new_error = service_wait_for_new_error,
service_wait_for_new_status = service_wait_for_new_status,
service_wait_for_activity = service_wait_for_activity,
wait_for_not_nil = wait_for_not_nil,
wait_for_nil = wait_for_nil,
Expand Down
10 changes: 7 additions & 3 deletions test/rebalancer/bucket_ref.result
Original file line number Diff line number Diff line change
Expand Up @@ -394,10 +394,14 @@ fiber_to_lock:cancel()
while not send_result do fiber.sleep(0.01) end
---
...
send_result
assert(not send_result[1])
---
- true
...
util.portable_error(send_result[2])
---
- - false
- fiber is cancelled
- type: FiberIsCancelled
message: fiber is cancelled
...
vshard.storage.buckets_info(1)
---
Expand Down
3 changes: 2 additions & 1 deletion test/rebalancer/bucket_ref.test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ while not vshard.storage.buckets_info(1)[1].rw_lock do fiber.sleep(0.01) end

fiber_to_lock:cancel()
while not send_result do fiber.sleep(0.01) end
send_result
assert(not send_result[1])
util.portable_error(send_result[2])
vshard.storage.buckets_info(1)

-- Cleanup after the test.
Expand Down
4 changes: 2 additions & 2 deletions test/rebalancer/rebalancer.result
Original file line number Diff line number Diff line change
Expand Up @@ -507,10 +507,10 @@ switch_rs1_master()
vshard.storage.cfg(cfg, util.name_to_uuid.box_2_b)
---
...
while not test_run:grep_log('box_2_a', "rebalancer_f has been started") do fiber.sleep(0.1) end
while not test_run:grep_log('box_2_a', "Starting the rebalancer") do fiber.sleep(0.1) end
---
...
while not test_run:grep_log('box_1_a', "Rebalancer location has changed") do fiber.sleep(0.1) end
while not test_run:grep_log('box_1_a', "Stopping the rebalancer") do fiber.sleep(0.1) end
---
...
--
Expand Down
4 changes: 2 additions & 2 deletions test/rebalancer/rebalancer.test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,8 @@ test_run:switch('box_2_b')
switch_rs1_master()
vshard.storage.cfg(cfg, util.name_to_uuid.box_2_b)

while not test_run:grep_log('box_2_a', "rebalancer_f has been started") do fiber.sleep(0.1) end
while not test_run:grep_log('box_1_a', "Rebalancer location has changed") do fiber.sleep(0.1) end
while not test_run:grep_log('box_2_a', "Starting the rebalancer") do fiber.sleep(0.1) end
while not test_run:grep_log('box_1_a', "Stopping the rebalancer") do fiber.sleep(0.1) end

--
-- gh-40: introduce custom replicaset weights. Weight allows to
Expand Down
35 changes: 35 additions & 0 deletions test/replicaset-luatest/replicaset_3_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,38 @@ test_group.test_map_call = function(g)
_G.test_sleep_is_called = nil
end)
end

test_group.test_locate_master_when_no_conn_object = function(g)
local new_cfg_template = table.deepcopy(cfg_template)
local rs_cfg = new_cfg_template.sharding[1]
rs_cfg.master = 'auto'
rs_cfg.replicas.replica_1_a.master = nil
local new_global_cfg = vtest.config_new(new_cfg_template)
local replicasets = vreplicaset.buildall(new_global_cfg)
local _, rs = next(replicasets)
t.assert_equals(rs.master, nil)
for _, r in pairs(rs.replicas) do
t.assert_equals(r.conn, nil)
end
t.assert(rs.is_master_auto)
--
-- First attempt to locate the masters only creates the connections, but
-- doesn't wait for their establishment. The call is supposed to be retried
-- later.
--
local is_all_done, is_all_nop, last_err =
vreplicaset.locate_masters(replicasets)
t.assert_equals(last_err, nil)
t.assert(not is_all_done)
t.assert(not is_all_nop)
for _, r in pairs(rs.replicas) do
t.assert_not_equals(r.conn, nil)
r.conn:wait_connected(vtest.wait_timeout)
end
is_all_done, is_all_nop, last_err =
vreplicaset.locate_masters(replicasets)
t.assert_equals(last_err, nil)
t.assert(is_all_done)
t.assert(not is_all_nop)
t.assert_equals(rs.master, rs.replicas[g.replica_1_a:instance_uuid()])
end
8 changes: 4 additions & 4 deletions test/router/master_discovery.result
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,7 @@ assert(rs.master.uuid == storage_a_uuid)
rs.master = nil
| ---
| ...
rs.is_auto_master = false
rs.is_master_auto = false
Serpentian marked this conversation as resolved.
Show resolved Hide resolved
| ---
| ...

Expand All @@ -861,7 +861,7 @@ assert(not rs.master)

-- With auto-search and not known master it is not assigned if a new master is
-- not reported.
rs.is_auto_master = true
rs.is_master_auto = true
| ---
| ...
-- But update returns true, because it makes sense to try a next request later
Expand Down Expand Up @@ -908,7 +908,7 @@ assert(rs.master.uuid == storage_b_uuid)
-- It does not depend on auto-search. Still returns true, because if the master
-- was changed since the request was sent, it means it could be retried and
-- might succeed.
rs.is_auto_master = false
rs.is_master_auto = false
| ---
| ...
assert(rs:update_master(storage_a_uuid))
Expand Down Expand Up @@ -936,7 +936,7 @@ assert(rs.master.uuid == storage_b_uuid)
-- the current master should be reset. Because makes no sense to send more RW
-- requests to him. But update returns true, because the current request could
-- be retried after waiting for a new master discovery.
rs.is_auto_master = true
rs.is_master_auto = true
| ---
| ...
assert(rs:update_master(storage_b_uuid))
Expand Down
8 changes: 4 additions & 4 deletions test/router/master_discovery.test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ storage_b_uuid = util.name_to_uuid.storage_1_b

assert(rs.master.uuid == storage_a_uuid)
rs.master = nil
rs.is_auto_master = false
rs.is_master_auto = false

-- When auto-search is disabled and master is not known, nothing will make it
-- known. It is up to the config.
Expand All @@ -398,7 +398,7 @@ assert(not rs.master)

-- With auto-search and not known master it is not assigned if a new master is
-- not reported.
rs.is_auto_master = true
rs.is_master_auto = true
-- But update returns true, because it makes sense to try a next request later
-- when the master is found.
assert(rs:update_master(storage_a_uuid))
Expand All @@ -419,7 +419,7 @@ assert(rs.master.uuid == storage_b_uuid)
-- It does not depend on auto-search. Still returns true, because if the master
-- was changed since the request was sent, it means it could be retried and
-- might succeed.
rs.is_auto_master = false
rs.is_master_auto = false
assert(rs:update_master(storage_a_uuid))
assert(rs.master.uuid == storage_b_uuid)

Expand All @@ -433,7 +433,7 @@ assert(rs.master.uuid == storage_b_uuid)
-- the current master should be reset. Because makes no sense to send more RW
-- requests to him. But update returns true, because the current request could
-- be retried after waiting for a new master discovery.
rs.is_auto_master = true
rs.is_master_auto = true
assert(rs:update_master(storage_b_uuid))
assert(rs.master == nil)

Expand Down
1 change: 1 addition & 0 deletions test/router/router.result
Original file line number Diff line number Diff line change
Expand Up @@ -1495,6 +1495,7 @@ error_messages
- Use replicaset:connect_master(...) instead of replicaset.connect_master(...)
- Use replicaset:connect_replica(...) instead of replicaset.connect_replica(...)
- Use replicaset:down_replica_priority(...) instead of replicaset.down_replica_priority(...)
- Use replicaset:locate_master(...) instead of replicaset.locate_master(...)
- Use replicaset:map_call(...) instead of replicaset.map_call(...)
- Use replicaset:up_replica_priority(...) instead of replicaset.up_replica_priority(...)
- Use replicaset:update_master(...) instead of replicaset.update_master(...)
Expand Down
Loading
Loading