@@ -123,10 +123,44 @@ local function get_replicaset_by_replica_id(replicasets, id)
123123 return nil , nil
124124end
125125
126- function utils .get_spaces (vshard_router , timeout , replica_id )
127- local replicasets , replicaset , replicaset_id , master
126+ local function find_any_healthy_replica_conn (replicasets )
127+ for _ , replicaset in pairs (replicasets ) do
128+ for _ , replica in pairs (replicaset .replicas ) do
129+ if replica :is_connected () then
130+ return replica .conn
131+ end
132+ end
133+ end
134+ return nil
135+ end
136+
137+ --- Returns all spaces existing in the schema.
138+ --
139+ -- @function get_spaces
140+ --
141+ -- @param table vshard_router
142+ -- A vshard router instance to route requests.
143+ --
144+ -- @tparam ?number opts.timeout
145+ -- Function call timeout. If not specified, `const.DEFAULT_VSHARD_CALL_TIMEOUT` is used.
146+ --
147+ -- @tparam ?boolean opts.read_only
148+ -- If true, the function will try to fetch spaces from any available healthy replica.
149+ --
150+ -- @tparam ?string opts.replica_id
151+ -- The exact replica ID to fetch the replicaset from.
152+ --
153+ -- @return [1] table map of spaces
154+ -- @return [1] nil
155+ -- @return [1] number schema version
156+ -- @treturn [2] nil
157+ -- @treturn [2] table Error description
158+ function utils .get_spaces (vshard_router , opts )
159+ local replicasets , replicaset , replicaset_id , master , ro_replica_conn
160+
161+ opts = opts or {}
128162
129- timeout = timeout or const .DEFAULT_VSHARD_CALL_TIMEOUT
163+ local timeout = opts . timeout or const .DEFAULT_VSHARD_CALL_TIMEOUT
130164 local deadline = fiber .clock () + timeout
131165 local iter_sleep = math.min (timeout / 100 , 0.1 )
132166 while (
@@ -136,12 +170,12 @@ function utils.get_spaces(vshard_router, timeout, replica_id)
136170 ) do
137171 -- Try to get master with timeout.
138172 replicasets = vshard_router :routeall ()
139- if replica_id ~= nil then
173+ if opts . replica_id ~= nil then
140174 -- Get the same replica on which the last DML operation was performed.
141175 -- This approach is temporary and is related to [1], [2].
142176 -- [1] https://github.com/tarantool/crud/issues/236
143177 -- [2] https://github.com/tarantool/crud/issues/361
144- replicaset_id , replicaset = get_replicaset_by_replica_id (replicasets , replica_id )
178+ replicaset_id , replicaset = get_replicaset_by_replica_id (replicasets , opts . replica_id )
145179 break
146180 else
147181 replicaset_id , replicaset = next (replicasets )
@@ -155,9 +189,22 @@ function utils.get_spaces(vshard_router, timeout, replica_id)
155189 end
156190 end
157191
192+ -- If the master check above didn't succeed (or master is dead),
193+ -- and this is a read-only operation, try to find any available healthy replica.
194+ if opts .read_only then
195+ ro_replica_conn = find_any_healthy_replica_conn (replicasets )
196+ if ro_replica_conn ~= nil then
197+ break
198+ end
199+ end
200+
158201 fiber .sleep (iter_sleep )
159202 end
160203
204+ if opts .read_only and ro_replica_conn ~= nil then
205+ return ro_replica_conn .space , nil , ro_replica_conn .schema_version
206+ end
207+
161208 if replicaset == nil then
162209 return nil , GetSpaceError :new (
163210 ' The router returned empty replicasets: ' ..
@@ -184,8 +231,32 @@ function utils.get_spaces(vshard_router, timeout, replica_id)
184231 return master .conn .space , nil , master .conn .schema_version
185232end
186233
187- function utils .get_space (space_name , vshard_router , timeout , replica_id )
188- local spaces , err , schema_version = utils .get_spaces (vshard_router , timeout , replica_id )
234+ --- Returns a specific space by its name.
235+ --
236+ -- @function get_space
237+ --
238+ -- @param string space_name
239+ -- A space name to fetch.
240+ --
241+ -- @param table vshard_router
242+ -- A vshard router instance to route requests.
243+ --
244+ -- @tparam ?number opts.timeout
245+ -- Function call timeout.
246+ --
247+ -- @tparam ?boolean opts.read_only
248+ -- If true, the function will try to fetch the space from any available healthy replica.
249+ --
250+ -- @tparam ?string opts.replica_id
251+ -- The exact replica ID to fetch the replicaset from.
252+ --
253+ -- @return [1] table space object
254+ -- @return [1] nil
255+ -- @return [1] number schema version
256+ -- @treturn [2] nil
257+ -- @treturn [2] table Error description
258+ function utils .get_space (space_name , vshard_router , opts )
259+ local spaces , err , schema_version = utils .get_spaces (vshard_router , opts )
189260
190261 if spaces == nil then
191262 return nil , err
0 commit comments