diff --git a/test/router/router.result b/test/router/router.result index 4032e6e7..2f66b4f5 100644 --- a/test/router/router.result +++ b/test/router/router.result @@ -1465,6 +1465,8 @@ error_messages - Use replicaset:callbro(...) instead of replicaset.callbro(...) - Use replicaset:callre(...) instead of replicaset.callre(...) - Use replicaset:callro(...) instead of replicaset.callro(...) + - Use replicaset:callbzre(...) instead of replicaset.callbzre(...) + - Use replicaset:callbzro(...) instead of replicaset.callbzro(...) - Use replicaset:callrw(...) instead of replicaset.callrw(...) - Use replicaset:connect(...) instead of replicaset.connect(...) - Use replicaset:connect_all(...) instead of replicaset.connect_all(...) diff --git a/vshard/replicaset.lua b/vshard/replicaset.lua index 7f27f06c..e71bfcaa 100644 --- a/vshard/replicaset.lua +++ b/vshard/replicaset.lua @@ -577,13 +577,33 @@ local function replicaset_template_multicallro(prefer_replica, balance) local function pick_next_replica(replicaset, now) local r local master = replicaset.master + if balance then + local prefered_zone = replicaset.priority_list[1].zone local i = #replicaset.priority_list while i > 0 do r = replicaset_balance_replica(replicaset) i = i - 1 if r:is_connected() and (not prefer_replica or r ~= master) and - replica_check_backoff(r, now) then + replica_check_backoff(r, now) + then + -- Pick a replica according prefered zone (highest priority replica zone) in round-robin manner + if balance == "prefer_zone" and prefered_zone then + local cbi = replicaset.balance_i + local nr = replicaset_balance_replica(replicaset) + + if prefered_zone and r.zone and r.zone == prefered_zone + and nr.zone and nr.zone ~= prefered_zone + and (not prefer_replica or nr ~= master) + then + -- Reset cursor to the main position if next replica is in different zone. + replicaset.balance_i = 1 + else + -- Restore rr-cursor position. + replicaset.balance_i = cbi + end + end + return r end end @@ -637,6 +657,7 @@ local function replicaset_template_multicallro(prefer_replica, balance) end end opts.timeout = timeout + net_status, storage_status, retval, err = replica_call(replica, func, args, opts) now = fiber_clock() @@ -990,8 +1011,10 @@ local replicaset_mt = { callrw = replicaset_master_call; callro = replicaset_template_multicallro(false, false); callbro = replicaset_template_multicallro(false, true); + callbzro = replicaset_template_multicallro(false, "prefer_zone"); callre = replicaset_template_multicallro(true, false); callbre = replicaset_template_multicallro(true, true); + callbzre = replicaset_template_multicallro(true, "prefer_zone"); map_call = replicaset_map_call, update_master = replicaset_update_master, }; @@ -1235,6 +1258,7 @@ local function buildall(sharding_cfg) local function replica_cmp_weight(r1, r2) -- Master has priority over replicas with the same -- weight. + if r1.weight == r2.weight then return r1 == new_replicaset.master else diff --git a/vshard/router/init.lua b/vshard/router/init.lua index bd686afa..9fbe6162 100644 --- a/vshard/router/init.lua +++ b/vshard/router/init.lua @@ -576,11 +576,15 @@ local function router_call_impl(router, bucket_id, mode, prefer_replica, local call if mode == 'read' then if prefer_replica then - if balance then + if balance == "prefer_zone" then + call = 'callbzre' + elseif balance then call = 'callbre' else call = 'callre' end + elseif balance == "prefer_zone" then + call = 'callbzro' elseif balance then call = 'callbro' else @@ -698,6 +702,10 @@ local function router_callbro(router, bucket_id, ...) return router_call_impl(router, bucket_id, 'read', false, true, ...) end +local function router_callbzro(router, bucket_id, ...) + return router_call_impl(router, bucket_id, 'read', false, "prefer_zone", ...) +end + local function router_callrw(router, bucket_id, ...) return router_call_impl(router, bucket_id, 'write', false, false, ...) end @@ -710,6 +718,10 @@ local function router_callbre(router, bucket_id, ...) return router_call_impl(router, bucket_id, 'read', true, true, ...) end +local function router_callbzre(router, bucket_id, ...) + return router_call_impl(router, bucket_id, 'read', true, "prefer_zone", ...) +end + local function router_call(router, bucket_id, opts, ...) local mode, prefer_replica, balance if opts then @@ -1660,6 +1672,8 @@ local router_mt = { call = router_make_api(router_call), callro = router_make_api(router_callro), callbro = router_make_api(router_callbro), + callbzro = router_make_api(router_callbzro), + callbzre = router_make_api(router_callbzre), callrw = router_make_api(router_callrw), callre = router_make_api(router_callre), callbre = router_make_api(router_callbre),