Skip to content

Commit

Permalink
connpool: mode option for call()
Browse files Browse the repository at this point in the history
This patch adds a "mode" option to experimental.call(). This option
allows to execute a function on instances with desired RO status.

Part of #9930

NO_DOC=will be added later
NO_CHANGELOG=will be added later
  • Loading branch information
ImeevMA committed Apr 12, 2024
1 parent 1978733 commit c0a4313
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 16 deletions.
44 changes: 28 additions & 16 deletions src/box/lua/experimental/connpool.lua
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,22 @@ local function filter(opts)
return dynamic_candidates
end

local function get_connection(all_candidates, prefer_local)
local candidates = table.copy(all_candidates)
if prefer_local ~= false then
local function get_connection(opts)
local mode = nil
if opts.mode == 'ro' or opts.mode == 'rw' then
mode = opts.mode
end
local candidates_opts = {
labels = opts.labels,
roles = opts.roles,
mode = mode,
}
local candidates = filter(candidates_opts)
if next(candidates) == nil then
return nil, "no candidates are available with these conditions"
end

if opts.prefer_local ~= false then
local candidate_idx = nil
for n, candidate in ipairs(candidates) do
if candidate == box.info.name then
Expand All @@ -219,14 +232,15 @@ local function get_connection(all_candidates, prefer_local)
return conn
end
end
return nil
return nil, "connection to candidates failed"
end

local function call(func_name, args, opts)
checks('string', '?table', {
labels = '?table',
roles = '?table',
prefer_local = '?boolean',
mode = '?string',
-- The following options passed directly to net.box.call().
timeout = '?',
buffer = '?',
Expand All @@ -235,23 +249,21 @@ local function call(func_name, args, opts)
is_async = '?boolean',
})
opts = opts or {}
if opts.mode ~= nil and opts.mode ~= 'ro' and opts.mode ~= 'rw' then
local msg = 'Expected nil, "ro" or "rw", got "%s"'
error(msg:format(opts.mode), 0)
end

local candidates_opts = {
local conn_opts = {
labels = opts.labels,
roles = opts.roles,
prefer_local = opts.prefer_local,
mode = opts.mode,
}
local candidates = filter(candidates_opts)
if next(candidates) == nil then
local msg = "Couldn't execute function %s: no candidates are " ..
"available with these conditions"
error(msg:format(func_name), 0)
end

local conn = get_connection(candidates, opts.prefer_local)
local conn, err = get_connection(conn_opts)
if conn == nil then
local msg = "Couldn't execute function %s: connection to " ..
"candidates failed"
error(msg:format(func_name), 0)
local msg = "Couldn't execute function %s: %s"
error(msg:format(func_name, err), 0)
end

local net_box_call_opts = {
Expand Down
93 changes: 93 additions & 0 deletions test/config-luatest/rpc_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -426,3 +426,96 @@ g.test_call = function(g)
g.server_3:exec(check)
g.server_4:exec(check)
end

g.test_call_mode = function(g)
local dir = treegen.prepare_directory(g, {}, {})
local config = [[
credentials:
users:
guest:
roles: [super]
iproto:
listen:
- uri: 'unix/:./{{ instance_name }}.iproto'
roles: [one]
groups:
group-001:
replicasets:
replicaset-001:
instances:
instance-001:
database:
mode: rw
labels:
l1: 'first'
instance-002: {}
replicaset-002:
replication:
failover: manual
leader: 'instance-003'
instances:
instance-003: {}
instance-004:
labels:
l1: 'first'
]]
treegen.write_script(dir, 'config.yaml', config)

local role = string.dump(function()
local function f()
return box.info.name
end

rawset(_G, 'f', f)

return {
stop = function() end,
apply = function() end,
validate = function() end,
}
end)
treegen.write_script(dir, 'one.lua', role)

local opts = {
env = {LUA_PATH = os.environ()['LUA_PATH']},
config_file = 'config.yaml',
chdir = dir,
}
g.server_1 = server:new(fun.chain(opts, {alias = 'instance-001'}):tomap())
g.server_2 = server:new(fun.chain(opts, {alias = 'instance-002'}):tomap())
g.server_3 = server:new(fun.chain(opts, {alias = 'instance-003'}):tomap())
g.server_4 = server:new(fun.chain(opts, {alias = 'instance-004'}):tomap())

g.server_1:start({wait_until_ready = false})
g.server_2:start({wait_until_ready = false})
g.server_3:start({wait_until_ready = false})
g.server_4:start({wait_until_ready = false})

g.server_1:wait_until_ready()
g.server_2:wait_until_ready()
g.server_3:wait_until_ready()
g.server_4:wait_until_ready()

local function check()
local connpool = require('experimental.connpool')
local opts = {
labels = {l1 = 'first'},
mode = 'rw',
}
t.assert_equals(connpool.call('f', nil, opts), 'instance-001')

opts = {
mode = 'ro',
}
local exp_list = {'instance-002', 'instance-004'}
t.assert_items_include(exp_list, {connpool.call('f', nil, opts)})
end

g.server_1:exec(check)
g.server_2:exec(check)
g.server_3:exec(check)
g.server_4:exec(check)
end

0 comments on commit c0a4313

Please sign in to comment.