Skip to content

Commit 988a1d0

Browse files
committed
Bug#32781963: Don't test all servers on fail to get connection.
1 parent f3d2a71 commit 988a1d0

File tree

4 files changed

+98
-9
lines changed

4 files changed

+98
-9
lines changed

cdk/core/session.cc

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,28 @@ struct Session_builder
4949
using TLS = cdk::connection::TLS;
5050
using TCPIP = cdk::connection::TCPIP;
5151
using Socket_base = foundation::connection::Socket_base;
52+
using ep_filter_t = std::function<bool(size_t, option_t)>;
53+
54+
struct ReportStatus
55+
{
56+
//False if not able to connect, true if all is good.
57+
option_t m_status = false;
58+
Session_builder::ep_filter_t m_filter;
59+
size_t m_id;
60+
61+
ReportStatus(Session_builder::ep_filter_t filter, size_t id)
62+
: m_filter(filter)
63+
, m_id(id)
64+
{}
65+
66+
67+
~ReportStatus()
68+
{
69+
if(m_filter)
70+
m_filter(m_id, m_status);
71+
}
72+
73+
};
5274

5375
unique_ptr<cdk::api::Connection> m_conn;
5476
mysqlx::Session *m_sess = NULL;
@@ -57,9 +79,12 @@ struct Session_builder
5779
scoped_ptr<Error> m_error;
5880
unsigned m_attempts = 0;
5981
size_t m_id = 0;
82+
ep_filter_t m_filter;
6083

61-
Session_builder(bool throw_errors = false)
84+
85+
Session_builder(bool throw_errors = false, ep_filter_t filter = nullptr)
6286
: m_throw_errors(throw_errors)
87+
, m_filter(filter)
6388
{}
6489

6590
/*
@@ -155,6 +180,7 @@ bool Session_builder::connect(Conn &connection)
155180
}
156181

157182

183+
158184
bool
159185
Session_builder::operator() (
160186
size_t id,
@@ -165,6 +191,8 @@ Session_builder::operator() (
165191
using foundation::connection::TCPIP;
166192
using foundation::connection::Socket_base;
167193

194+
ReportStatus report_status(m_filter, id);
195+
168196
unique_ptr<TCPIP> connection(new TCPIP(ds.host(), ds.port(),
169197
options));
170198

@@ -220,6 +248,7 @@ Session_builder::operator() (
220248

221249
m_database = options.database();
222250
m_id = id;
251+
report_status.m_status = true;
223252
return true;
224253
}
225254

@@ -234,6 +263,8 @@ Session_builder::operator() (
234263
using foundation::connection::Unix_socket;
235264
using foundation::connection::Socket_base;
236265

266+
ReportStatus report_status(m_filter, id);
267+
237268
unique_ptr<Unix_socket> connection(new Unix_socket(ds.path(), options));
238269

239270
if (!connect(*connection))
@@ -244,6 +275,7 @@ Session_builder::operator() (
244275

245276
m_database = options.database();
246277
m_id = id;
278+
report_status.m_status = true;
247279
return true;
248280
}
249281

@@ -393,14 +425,29 @@ struct ds::Multi_source::Access
393425
};
394426

395427

428+
/*
429+
Create session to one of the data sources in the multi-source `ds`.
430+
The order in which data sources are tried is determined by `Multi_source`
431+
class (see `Multi_source::visit()` method). For each data source with
432+
identifier `id`, first a call to `ep_filter(id,UNKNOWN)` is made to determine
433+
if that data source should be filtered. If this is not the case and session
434+
could be successfully created, `ep_filter(id,YES)` is called. Otherwise
435+
`ep_filter(id,NO)` is called and next data source is tried.
436+
*/
396437

397-
Session::Session(ds::Multi_source &ds, ds::Multi_source::ep_filter_t ep_filter)
438+
Session::Session(ds::Multi_source &ds, ep_filter_t ep_filter)
398439
: m_session(NULL)
399440
, m_connection(NULL)
400441
{
401-
Session_builder sb;
442+
Session_builder sb(false, ep_filter);
443+
444+
auto filter = [&ep_filter](size_t id) -> bool {
445+
if(ep_filter)
446+
return ep_filter(id, option_t());
447+
return false;
448+
};
402449

403-
ds::Multi_source::Access::visit(ds, sb, ep_filter);
450+
ds::Multi_source::Access::visit(ds, sb, filter);
404451

405452
if (!sb.m_sess)
406453
{

cdk/include/mysql/cdk/session.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,14 @@ class Session
6464

6565
typedef api::Session::Diagnostics Diagnostics;
6666

67+
using ep_filter_t = std::function<bool(size_t,option_t)>;
68+
6769
/// Create session to a data store represented by `ds` object.
6870

6971
Session(ds::TCPIP &ds,
7072
const ds::TCPIP::Options &options = ds::TCPIP::Options());
7173

72-
Session(ds::Multi_source&, ds::Multi_source::ep_filter_t = nullptr);
74+
Session(ds::Multi_source&, ep_filter_t = nullptr);
7375

7476
#ifndef _WIN32
7577
Session(ds::Unix_socket &ds,

common/session.cc

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -979,12 +979,29 @@ Session_pool::get_session(Session_cleanup *cleanup)
979979
avoiding the block-listed endpoints.
980980
*/
981981

982+
/*
983+
Keep the original block list so that, if non blocked servers fail to get a
984+
session, previously blocked ones are tried.
985+
*/
986+
Block_list original_block(m_block_list);
987+
982988
if (m_pool.size() < m_max)
983989
{
984990
try
985991
{
986-
auto block_list_filter = [this](size_t id) {
987-
return m_block_list.is_block_listed(id);
992+
auto block_list_filter = [this](size_t id, cdk::option_t opt) -> bool {
993+
switch(opt.state())
994+
{
995+
case cdk::option_t::UNKNOWN:
996+
return m_block_list.is_block_listed(id);
997+
case cdk::option_t::YES:
998+
m_block_list.remove(id);
999+
break;
1000+
case cdk::option_t::NO:
1001+
m_block_list.add(id);
1002+
break;
1003+
}
1004+
return true;
9881005
};
9891006

9901007
auto ret = m_pool.emplace(
@@ -1013,14 +1030,32 @@ Session_pool::get_session(Session_cleanup *cleanup)
10131030

10141031
/*
10151032
If a session is still not found, and there is space in the pool,
1016-
try creating a new session this time ignoring the block-list.
1033+
try creating a new session this time using the block-listed ones.
10171034
*/
10181035

10191036
if (m_pool.size() < m_max)
10201037
{
1038+
1039+
1040+
auto block_list_filter = [this, &original_block](size_t id, cdk::option_t opt) -> bool {
1041+
switch(opt.state())
1042+
{
1043+
case cdk::option_t::UNKNOWN:
1044+
//Filter out sessions that were not block-listed
1045+
return !original_block.is_block_listed(id);
1046+
case cdk::option_t::YES:
1047+
m_block_list.remove(id);
1048+
break;
1049+
case cdk::option_t::NO:
1050+
m_block_list.add(id);
1051+
break;
1052+
}
1053+
return true;
1054+
};
1055+
10211056
// If an exception is thrown, don't intercept it, let it propagate
10221057
auto ret = m_pool.emplace(
1023-
cdk::shared_ptr<cdk::Session>(new cdk::Session(m_ds)),
1058+
cdk::shared_ptr<cdk::Session>(new cdk::Session(m_ds, block_list_filter)),
10241059
Sess_data{ time_point::max(), cleanup }
10251060
);
10261061
return ret.first->first;

common/session.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ class Session_pool
235235
m_list[id] = system_clock::now() + m_timeout;
236236
}
237237

238+
void remove(size_t id)
239+
{
240+
m_list.erase(id);
241+
}
242+
238243
bool is_block_listed(size_t id)
239244
{
240245
if (m_list.find(id) == m_list.end())

0 commit comments

Comments
 (0)