Skip to content
This repository was archived by the owner on Mar 1, 2026. It is now read-only.

Commit c89512b

Browse files
committed
Bug#34781248 pooled connection not used if io.threads larger than 1
When connection pooling is used and a connection to a destination is picked from the pool, it is ignored if the connection is belongs to another io-thread. - By default, as many io-threads are starts as there are CPU-threads. - Each new connection is assigned another io-thread (round-robin) E.g. a 24 core machine, with 2-threads per core, leads to 48 io-threads. If a server-connection is taken from the pool for the current client-connection then it must match the right: - destination AND - io-thread With 3 possible destinations and 48 io-threads, the connection pool has to contain 3 * 48 connections to have a good chance that there is 1 matching connection for this client-connection. The higher the io-thread count, the lower the cache-hit rate. Change ------ - ignore the io-thread when taking connections from the pool - move pooled-connections to the current client connection's io-thread when taken from the pool. Change-Id: I586e7b5b1904a3a0020d6c8784928d549a1675e4
1 parent ff6d2f7 commit c89512b

3 files changed

Lines changed: 29 additions & 9 deletions

File tree

‎router/src/connection_pool/include/mysqlrouter/connection_base.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class ConnectionBase {
7070
[[nodiscard]] virtual std::string endpoint() const = 0;
7171

7272
[[nodiscard]] virtual stdx::expected<void, std::error_code> cancel() = 0;
73+
74+
[[nodiscard]] virtual stdx::expected<void, std::error_code> set_io_context(
75+
net::io_context &new_ctx) = 0;
7376
};
7477

7578
#endif

‎router/src/routing/src/basic_protocol_splicer.h‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,25 @@ class BasicConnection : public ConnectionBase {
127127

128128
net::io_context &io_ctx() override { return sock_.get_executor().context(); }
129129

130+
stdx::expected<void, std::error_code> set_io_context(
131+
net::io_context &new_ctx) override {
132+
// nothing to do.
133+
if (sock_.get_executor() == new_ctx.get_executor()) return {};
134+
135+
return sock_.release().and_then(
136+
[this, &new_ctx](
137+
auto native_handle) -> stdx::expected<void, std::error_code> {
138+
socket_type new_sock(new_ctx);
139+
140+
auto assign_res = new_sock.assign(ep_.protocol(), native_handle);
141+
if (!assign_res) return assign_res;
142+
143+
std::swap(sock_, new_sock);
144+
145+
return {};
146+
});
147+
}
148+
130149
void async_recv(recv_buffer_type &buf,
131150
std::function<void(std::error_code ec, size_t transferred)>
132151
completion) override {

‎router/src/routing/src/classic_connect.cc‎

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,6 @@ ConnectProcessor::from_pool() {
224224
return Result::Again;
225225
}
226226

227-
auto &io_ctx =
228-
connection()->socket_splicer()->client_conn().connection()->io_ctx();
229-
230227
auto &pools = ConnectionPoolComponent::get_instance();
231228

232229
if (auto pool = pools.get(ConnectionPoolComponent::default_pool_name())) {
@@ -243,19 +240,16 @@ ConnectProcessor::from_pool() {
243240

244241
auto pool_res = pool->pop_if(
245242
[client_caps, ep = mysqlrouter::to_string(server_endpoint_),
246-
my_executor = io_ctx.get_executor(),
247243
requires_tls = connection()->requires_tls()](const auto &pooled_conn) {
248244
auto pooled_caps = pooled_conn.shared_capabilities();
249245

250246
pooled_caps.reset(classic_protocol::capabilities::pos::ssl)
251247
.reset(classic_protocol::capabilities::pos::compress)
252248
.reset(classic_protocol::capabilities::pos::compress_zstd);
253249

254-
return pooled_conn.endpoint() == ep && //
255-
client_caps == pooled_caps && //
256-
pooled_conn.connection()->io_ctx().get_executor() ==
257-
my_executor &&
258-
(requires_tls == (bool)pooled_conn.ssl());
250+
return (pooled_conn.endpoint() == ep && //
251+
client_caps == pooled_caps && //
252+
(requires_tls == (bool)pooled_conn.ssl()));
259253
});
260254

261255
if (pool_res) {
@@ -269,12 +263,16 @@ ConnectProcessor::from_pool() {
269263
trace(Tracer::Event().stage(
270264
"connect::from_pool: " +
271265
destination_id_from_endpoint(*endpoints_it_)));
266+
272267
// if the socket would be closed, recv() would return 0 for "eof".
273268
//
274269
// socket is still alive. good.
275270
socket_splicer->server_conn() =
276271
make_connection_from_pooled(std::move(*pool_res));
277272

273+
(void)socket_splicer->server_conn().connection()->set_io_context(
274+
socket_splicer->client_conn().connection()->io_ctx());
275+
278276
stage(Stage::Connected);
279277
return Result::Again;
280278
}

0 commit comments

Comments
 (0)