@@ -65,7 +65,12 @@ struct ClientInfo {
65
65
66
66
std::ostream& operator <<(std::ostream& os, const ClientOptions& opt) {
67
67
os << " Client(" << opt.user << ' @' << opt.host << " :" << opt.port
68
- << " ping_before_query:" << opt.ping_before_query
68
+ << " Endpoints :" ;
69
+ for (size_t i = 0 ; i < opt.endpoints .size (); i++)
70
+ os << opt.user << ' @' << opt.endpoints [i].host << " :" << opt.endpoints [i].port
71
+ << ((i == opt.endpoints .size () - 1 ) ? " " : " , " );
72
+
73
+ os << " ping_before_query:" << opt.ping_before_query
69
74
<< " send_retries:" << opt.send_retries
70
75
<< " retry_timeout:" << opt.retry_timeout .count ()
71
76
<< " compression_method:"
@@ -111,6 +116,15 @@ std::unique_ptr<SocketFactory> GetSocketFactory(const ClientOptions& opts) {
111
116
return std::make_unique<NonSecureSocketFactory>();
112
117
}
113
118
119
+ std::unique_ptr<EndpointsIteratorBase> GetEndpointsIterator (const ClientOptions& opts) {
120
+ if (opts.endpoints .empty ())
121
+ {
122
+ throw ValidationError (" The list of endpoints is empty" );
123
+ }
124
+
125
+ return std::make_unique<RoundRobinEndpointsIterator>(opts.endpoints );
126
+ }
127
+
114
128
}
115
129
116
130
class Client ::Impl {
@@ -130,8 +144,12 @@ class Client::Impl {
130
144
131
145
void ResetConnection ();
132
146
147
+ void ResetConnectionEndpoint ();
148
+
133
149
const ServerInfo& GetServerInfo () const ;
134
150
151
+ const std::optional<Endpoint>& GetCurrentEndpoint () const ;
152
+
135
153
private:
136
154
bool Handshake ();
137
155
@@ -155,13 +173,22 @@ class Client::Impl {
155
173
156
174
void WriteBlock (const Block& block, OutputStream& output);
157
175
176
+ void CreateConnection ();
177
+
158
178
void InitializeStreams (std::unique_ptr<SocketBase>&& socket);
159
179
180
+ inline size_t GetConnectionAttempts () const
181
+ {
182
+ return options_.endpoints .size () * options_.send_retries ;
183
+ }
184
+
160
185
private:
161
186
// / In case of network errors tries to reconnect to server and
162
187
// / call fuc several times.
163
188
void RetryGuard (std::function<void ()> func);
164
189
190
+ void RetryConnectToTheEndpoint (std::function<void ()>& func);
191
+
165
192
private:
166
193
class EnsureNull {
167
194
public:
@@ -194,32 +221,34 @@ class Client::Impl {
194
221
std::unique_ptr<InputStream> input_;
195
222
std::unique_ptr<OutputStream> output_;
196
223
std::unique_ptr<SocketBase> socket_;
224
+ std::unique_ptr<EndpointsIteratorBase> endpoints_iterator;
225
+
226
+ std::optional<Endpoint> current_endpoint_;
197
227
198
228
ServerInfo server_info_;
199
229
};
200
230
231
+ ClientOptions modifyClientOptions (ClientOptions opts)
232
+ {
233
+ if (opts.host .empty ())
234
+ return opts;
235
+
236
+ Endpoint default_endpoint ({opts.host , opts.port });
237
+ opts.endpoints .emplace (opts.endpoints .begin (), default_endpoint);
238
+ return opts;
239
+ }
201
240
202
241
Client::Impl::Impl (const ClientOptions& opts)
203
242
: Impl(opts, GetSocketFactory(opts)) {}
204
243
205
244
Client::Impl::Impl (const ClientOptions& opts,
206
245
std::unique_ptr<SocketFactory> socket_factory)
207
- : options_(opts)
246
+ : options_(modifyClientOptions( opts) )
208
247
, events_(nullptr )
209
248
, socket_factory_(std::move(socket_factory))
249
+ , endpoints_iterator(GetEndpointsIterator(options_))
210
250
{
211
- for (unsigned int i = 0 ; ; ) {
212
- try {
213
- ResetConnection ();
214
- break ;
215
- } catch (const std::system_error&) {
216
- if (++i > options_.send_retries ) {
217
- throw ;
218
- }
219
-
220
- socket_factory_->sleepFor (options_.retry_timeout );
221
- }
222
- }
251
+ CreateConnection ();
223
252
224
253
if (options_.compression_method != CompressionMethod::None) {
225
254
compression_ = CompressionState::Enable;
@@ -329,17 +358,57 @@ void Client::Impl::Ping() {
329
358
}
330
359
331
360
void Client::Impl::ResetConnection () {
332
- InitializeStreams (socket_factory_->connect (options_));
361
+ InitializeStreams (socket_factory_->connect (options_, current_endpoint_. value () ));
333
362
334
363
if (!Handshake ()) {
335
364
throw ProtocolError (" fail to connect to " + options_.host );
336
365
}
337
366
}
338
367
368
+ void Client::Impl::ResetConnectionEndpoint () {
369
+ current_endpoint_.reset ();
370
+ for (size_t i = 0 ; i < options_.endpoints .size ();)
371
+ {
372
+ try
373
+ {
374
+ current_endpoint_ = endpoints_iterator->Next ();
375
+ ResetConnection ();
376
+ return ;
377
+ } catch (const std::system_error&) {
378
+ if (++i == options_.endpoints .size ())
379
+ {
380
+ current_endpoint_.reset ();
381
+ throw ;
382
+ }
383
+ }
384
+ }
385
+ }
386
+
387
+ void Client::Impl::CreateConnection () {
388
+ for (size_t i = 0 ; i < options_.send_retries ;)
389
+ {
390
+ try
391
+ {
392
+ ResetConnectionEndpoint ();
393
+ return ;
394
+ } catch (const std::system_error&) {
395
+ if (++i == options_.send_retries )
396
+ {
397
+ throw ;
398
+ }
399
+ }
400
+ }
401
+ }
402
+
339
403
const ServerInfo& Client::Impl::GetServerInfo () const {
340
404
return server_info_;
341
405
}
342
406
407
+
408
+ const std::optional<Endpoint>& Client::Impl::GetCurrentEndpoint () const {
409
+ return current_endpoint_;
410
+ }
411
+
343
412
bool Client::Impl::Handshake () {
344
413
if (!SendHello ()) {
345
414
return false ;
@@ -859,21 +928,45 @@ bool Client::Impl::ReceiveHello() {
859
928
}
860
929
861
930
void Client::Impl::RetryGuard (std::function<void ()> func) {
862
- for (unsigned int i = 0 ; ; ++i) {
863
- try {
864
- func ();
865
- return ;
866
- } catch (const std::system_error&) {
867
- bool ok = true ;
868
931
932
+ if (current_endpoint_)
933
+ {
934
+ for (unsigned int i = 0 ; ; ++i) {
869
935
try {
870
- socket_factory_->sleepFor (options_.retry_timeout );
871
- ResetConnection ();
872
- } catch (...) {
873
- ok = false ;
936
+ func ();
937
+ return ;
938
+ } catch (const std::system_error&) {
939
+ bool ok = true ;
940
+
941
+ try {
942
+ socket_factory_->sleepFor (options_.retry_timeout );
943
+ ResetConnection ();
944
+ } catch (...) {
945
+ ok = false ;
946
+ }
947
+
948
+ if (!ok && i == options_.send_retries ) {
949
+ break ;
950
+ }
874
951
}
875
-
876
- if (!ok && i == options_.send_retries ) {
952
+ }
953
+ }
954
+ // Connectiong with current_endpoint_ are broken.
955
+ // Trying to establish with the another one from the list.
956
+ size_t connection_attempts_count = GetConnectionAttempts ();
957
+ for (size_t i = 0 ; i < connection_attempts_count;)
958
+ {
959
+ try
960
+ {
961
+ socket_factory_->sleepFor (options_.retry_timeout );
962
+ current_endpoint_ = endpoints_iterator->Next ();
963
+ ResetConnection ();
964
+ func ();
965
+ return ;
966
+ } catch (const std::system_error&) {
967
+ if (++i == connection_attempts_count)
968
+ {
969
+ current_endpoint_.reset ();
877
970
throw ;
878
971
}
879
972
}
@@ -936,6 +1029,14 @@ void Client::ResetConnection() {
936
1029
impl_->ResetConnection ();
937
1030
}
938
1031
1032
+ void Client::ResetConnectionEndpoint () {
1033
+ impl_->ResetConnectionEndpoint ();
1034
+ }
1035
+
1036
+ const std::optional<Endpoint>& Client::GetCurrentEndpoint () const {
1037
+ return impl_->GetCurrentEndpoint ();
1038
+ }
1039
+
939
1040
const ServerInfo& Client::GetServerInfo () const {
940
1041
return impl_->GetServerInfo ();
941
1042
}
0 commit comments