@@ -12,14 +12,70 @@ local call = {}
1212
1313local DEFAULT_VSHARD_CALL_TIMEOUT = 2
1414
15- local function call_impl (vshard_call , func_name , func_args , opts )
16- dev_checks (' string' , ' string' , ' ?table' , {
15+ local function get_vshard_call_name (mode , prefer_replica , balance )
16+ dev_checks (' string' , ' ?boolean' , ' ?boolean' )
17+
18+ if mode == ' write' then
19+ return ' callrw'
20+ end
21+
22+ if not prefer_replica and not balance then
23+ return ' callro'
24+ end
25+
26+ if not prefer_replica and balance then
27+ return ' callbro'
28+ end
29+
30+ if prefer_replica and not balance then
31+ return ' callre'
32+ end
33+
34+ -- prefer_replica and balance
35+ return ' callbre'
36+ end
37+
38+ local function wrap_vshard_err (err , func_name , replicaset_uuid , bucket_id )
39+ if err .type == ' ClientError' and type (err .message ) == ' string' then
40+ if err .message == string.format (" Procedure '%s' is not defined" , func_name ) then
41+ if func_name :startswith (' _crud.' ) then
42+ err = NotInitializedError :new (" crud isn't initialized on replicaset: %q" , replicaset_uuid )
43+ else
44+ err = NotInitializedError :new (" Function %s is not registered" , func_name )
45+ end
46+ end
47+ end
48+
49+ if replicaset_uuid == nil then
50+ local replicaset , _ = vshard .router .route (bucket_id )
51+ if replicaset == nil then
52+ return CallError :new (
53+ " Function returned an error, but we couldn't figure out the replicaset: %s" , err
54+ )
55+ end
56+
57+ replicaset_uuid = replicaset .uuid
58+ end
59+
60+ err = errors .wrap (err )
61+
62+ return CallError :new (utils .format_replicaset_error (
63+ replicaset_uuid , " Function returned an error: %s" , err
64+ ))
65+ end
66+
67+ function call .map (func_name , func_args , opts )
68+ dev_checks (' string' , ' ?table' , {
69+ mode = ' string' ,
70+ prefer_replica = ' ?boolean' ,
71+ balance = ' ?boolean' ,
1772 timeout = ' ?number' ,
1873 replicasets = ' ?table' ,
1974 })
20-
2175 opts = opts or {}
2276
77+ local vshard_call_name = get_vshard_call_name (opts .mode , opts .prefer_replica , opts .balance )
78+
2379 local timeout = opts .timeout or DEFAULT_VSHARD_CALL_TIMEOUT
2480
2581 local replicasets , err
@@ -35,7 +91,7 @@ local function call_impl(vshard_call, func_name, func_args, opts)
3591 local futures_by_replicasets = {}
3692 local call_opts = {is_async = true }
3793 for _ , replicaset in pairs (replicasets ) do
38- local future = replicaset [vshard_call ](replicaset , func_name , func_args , call_opts )
94+ local future = replicaset [vshard_call_name ](replicaset , func_name , func_args , call_opts )
3995 futures_by_replicasets [replicaset .uuid ] = future
4096 end
4197
@@ -53,101 +109,33 @@ local function call_impl(vshard_call, func_name, func_args, opts)
53109 end
54110
55111 if err ~= nil then
56- if err .type == ' ClientError' and type (err .message ) == ' string' then
57- if err .message == string.format (" Procedure '%s' is not defined" , func_name ) then
58- if func_name :startswith (' _crud.' ) then
59- err = NotInitializedError :new (" crud isn't initialized on replicaset: %q" , replicaset_uuid )
60- else
61- err = NotInitializedError :new (" Function %s is not registered" , func_name )
62- end
63- end
64- end
65- err = errors .wrap (err )
66- return nil , CallError :new (utils .format_replicaset_error (
67- replicaset_uuid , " Function returned an error: %s" , err
68- ))
112+ return nil , wrap_vshard_err (err , func_name , replicaset_uuid )
69113 end
114+
70115 results [replicaset_uuid ] = result [1 ]
71116 end
72117
73118 return results
74119end
75120
76- --- Calls specified function on all cluster storages.
77- --
78- -- Allowed functions to call can be specified by `crud.register` call.
79- -- If function with specified `opts.func_name` isn't registered,
80- -- global function with this name is called.
81- --
82- -- Uses vshard `replicaset:callrw`
83- --
84- -- @function rw
85- --
86- -- @param string func_name
87- -- A function name
88- --
89- -- @param ?table func_args
90- -- Array of arguments to be passed to the function
91- --
92- -- @tparam table opts Available options are:
93- --
94- -- @tparam ?number opts.timeout
95- -- Function call timeout
96- --
97- -- @tparam ?table opts.replicasets
98- -- vshard replicasets to call the function.
99- -- By default, function is called on the all storages.
100- --
101- -- Returns map {replicaset_uuid: result} with all specified replicasets results
102- --
103- -- @return [1] table
104- -- @treturn [2] nil
105- -- @treturn [2] table Error description
106- --
107- function call .rw (func_name , func_args , opts )
108- return call_impl (' callrw' , func_name , func_args , opts )
109- end
121+ function call .single (bucket_id , func_name , func_args , opts )
122+ dev_checks (' number' , ' string' , ' ?table' , {
123+ mode = ' string' ,
124+ prefer_replica = ' ?boolean' ,
125+ balance = ' ?boolean' ,
126+ timeout = ' ?number' ,
127+ })
110128
111- --- Calls specified function on all cluster storages.
112- --
113- -- The same as `rw`, but uses vshard `replicaset:callro`
114- --
115- -- @function ro
116- --
117- function call .ro (func_name , func_args , opts )
118- return call_impl (' callro' , func_name , func_args , opts )
119- end
129+ local vshard_call_name = get_vshard_call_name (opts .mode , opts .prefer_replica , opts .balance , opts .mode )
120130
121- --- Calls specified function on a node according to bucket_id.
122- --
123- -- Exactly mimics the contract of vshard.router.callrw, but adds
124- -- better error hangling
125- --
126- -- @function rw_single
127- --
128- function call .rw_single (bucket_id , func_name , func_args , options )
129- local res , err = vshard .router .callrw (bucket_id , func_name , func_args , options )
130-
131- -- This is a workaround, until vshard supports telling us where the error happened
132- if err ~= nil then
133- if type (err ) == ' table' and err .type == ' ClientError' and type (err .message ) == ' string' then
134- if err .message == string.format (" Procedure '%s' is not defined" , func_name ) then
135- err = NotInitializedError :new (" crud isn't initialized on replicaset" )
136- end
137- end
138-
139- local replicaset , _ = vshard .router .route (bucket_id )
140- if replicaset == nil then
141- return nil , CallError :new (
142- " Function returned an error, but we couldn't figure out the replicaset: %s" , err
143- )
144- end
131+ local timeout = opts .timeout or DEFAULT_VSHARD_CALL_TIMEOUT
145132
146- err = errors .wrap (err )
133+ local res , err = vshard .router [vshard_call_name ](bucket_id , func_name , func_args , {
134+ timeout = timeout ,
135+ })
147136
148- return nil , CallError :new (utils .format_replicaset_error (
149- replicaset .uuid , " Function returned an error: %s" , err
150- ))
137+ if err ~= nil then
138+ return nil , wrap_vshard_err (err , func_name , nil , bucket_id )
151139 end
152140
153141 if res == box .NULL then
0 commit comments