Skip to content

Commit 254ebcd

Browse files
author
Valtteri Heikkila
committed
Refactored linux_connection close() to its destructor and added more comments in http_linux.cpp
1 parent 81dfb17 commit 254ebcd

File tree

1 file changed

+37
-27
lines changed

1 file changed

+37
-27
lines changed

Release/src/http/client/http_linux.cpp

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,16 @@ namespace web { namespace http
6464
m_keep_alive(true)
6565
{}
6666

67+
~linux_connection()
68+
{
69+
close();
70+
}
71+
6772
void close()
6873
{
74+
// Ensures closed connections owned by request_context will not be put to pool when they are released.
6975
m_keep_alive = false;
76+
7077
boost::system::error_code error;
7178
m_socket.shutdown(tcp::socket::shutdown_both, error);
7279
m_socket.close(error);
@@ -124,12 +131,10 @@ namespace web { namespace http
124131
~linux_connection_pool()
125132
{
126133
std::lock_guard<std::mutex> lock(m_connections_mutex);
127-
// Close all connections. This happens when linux_client is destroyed because
128-
// it only has shared_ptr reference to pool. Connections use weak_ptr instead.
134+
// Cancel the pool timer for all connections.
129135
for (auto& connection : m_connections)
130136
{
131137
connection->cancel_pool_timer();
132-
connection->close();
133138
}
134139
}
135140

@@ -138,27 +143,20 @@ namespace web { namespace http
138143
if (connection->keep_alive() && (m_timeout_secs > 0))
139144
{
140145
connection->cancel();
141-
// Remove idle connections from pool after timeout.
146+
// This will destroy and remove the connection from pool after the set timeout.
147+
// We use 'this' because async calls to timer handler only occur while the pool exists.
142148
connection->start_pool_timer(m_timeout_secs, boost::bind(&linux_connection_pool::handle_pool_timer, this, boost::asio::placeholders::error, connection));
143149

144-
{
145-
std::lock_guard<std::mutex> lock(m_connections_mutex);
146-
m_connections.insert(connection);
147-
}
148-
}
149-
else
150-
{
151-
// Connection is not returned to pool => will be destroyed.
152-
connection->close();
150+
put_to_pool(connection);
153151
}
152+
// Otherwise connection is not put to the pool and it will go out of scope.
154153
}
155154

156155
std::shared_ptr<linux_connection> obtain()
157156
{
158157
if (is_pool_empty())
159158
{
160-
// No connections in pool => create new connection instance.
161-
// shared_from_this() is only to create a weak_ptr to pool.
159+
// No connections in pool => create a new connection instance.
162160
return std::make_shared<linux_connection>(m_io_service);
163161
}
164162
else
@@ -176,11 +174,15 @@ namespace web { namespace http
176174
m_connections.erase(connection);
177175
}
178176

179-
void handle_pool_timer(const boost::system::error_code& ec, std::shared_ptr<linux_connection> connection)
177+
// Using weak_ptr here ensures bind() to this handler will not prevent the connection object from going out of scope.
178+
void handle_pool_timer(const boost::system::error_code& ec, std::weak_ptr<linux_connection> connection)
180179
{
181180
if (!ec)
182181
{
183-
remove(connection);
182+
if (auto connection_shared = connection.lock())
183+
{
184+
remove(connection_shared);
185+
}
184186
}
185187
}
186188

@@ -199,6 +201,12 @@ namespace web { namespace http
199201
return connection;
200202
}
201203

204+
void put_to_pool(std::shared_ptr<linux_connection> connection)
205+
{
206+
std::lock_guard<std::mutex> lock(m_connections_mutex);
207+
m_connections.insert(connection);
208+
}
209+
202210
boost::asio::io_service& m_io_service;
203211
const int m_timeout_secs;
204212
std::unordered_set<std::shared_ptr<linux_connection> > m_connections;
@@ -425,9 +433,9 @@ namespace web { namespace http
425433
{
426434
ctx->m_cancellationRegistration = request_ctx->m_request._cancellation_token().register_callback([ctx]()
427435
{
428-
// Cancel operations and all async handlers.
436+
// Cancel operations and all asio async handlers.
429437
ctx->m_connection->cancel();
430-
// Shut down transmissions and close socket. Also prevents connection being pooled.
438+
// Shut down transmissions, close the socket and prevent connection from being pooled.
431439
ctx->m_connection->close();
432440
});
433441
}
@@ -508,8 +516,8 @@ namespace web { namespace http
508516
{
509517
ctx->m_timeout_timer.cancel();
510518

511-
ctx->m_connection->close();
512-
ctx->m_connection = m_pool.obtain();
519+
// Replace the connection. This causes old connection object to go out of scope.
520+
ctx->m_connection = m_pool.obtain();
513521

514522
auto endpoint = *endpoints;
515523
if (ctx->m_ssl_stream)
@@ -761,16 +769,18 @@ namespace web { namespace http
761769
|| (boost::asio::error::connection_aborted == ec));
762770
if (socket_was_closed && ctx->m_connection->is_reused() && ctx->m_connection->socket().is_open())
763771
{
764-
// Connection was closed while connection was in pool.
765-
// Ensure connection is closed in a robust way.
772+
// Failed to write to socket because connection was already closed while it was in the pool.
773+
// close() here ensures socket is closed in a robust way and prevents the connection from being put to the pool again.
766774
ctx->m_connection->close();
767775

768-
// Replace context and destroy the old one. The request,
769-
// completion event and cancellation registration are copied to
770-
// the new context. This will also obtain a new connection.
776+
// Create a new context and copy the requst object, completion event and
777+
// cancellation registration to maintain the old state.
778+
// This also obtains a new connection from pool.
771779
auto new_ctx = details::linux_client_request_context::create_request_context(ctx->m_http_client, ctx->m_request);
772780
new_ctx->m_request_completion = ctx->m_request_completion;
773781
new_ctx->m_cancellationRegistration = ctx->m_cancellationRegistration;
782+
783+
// Replace context with the new one. This causes the old context and connection to go out of scope.
774784
ctx = std::static_pointer_cast<linux_client_request_context>(new_ctx);
775785

776786
// Resend the request using the new context.
@@ -1103,7 +1113,7 @@ namespace web { namespace http
11031113
linux_client_request_context::~linux_client_request_context()
11041114
{
11051115
m_timeout_timer.cancel();
1106-
// Give connection back to the pool where it can be reused.
1116+
// Release connection back to the pool. If connection was not closed, it will be put to the pool for reuse.
11071117
std::static_pointer_cast<linux_client>(m_http_client)->m_pool.release(m_connection);
11081118
}
11091119

0 commit comments

Comments
 (0)