@@ -235,9 +235,10 @@ class asio_connection
235
235
// /
236
236
// / During the cleanup phase, connections are removed starting with the oldest. This
237
237
// / ensures that if a high intensity workload is followed by a low intensity workload,
238
- // / the connection pool will correctly adapt to the current workload. Specifically,
239
- // / the following code will eventually result in a maximum of one pooled connection
240
- // / regardless of the initial number of pooled connections:
238
+ // / the connection pool will correctly adapt to the low intensity workload.
239
+ // /
240
+ // / Specifically, the following code will eventually result in a maximum of one pooled
241
+ // / connection regardless of the initial number of pooled connections:
241
242
// / <code>
242
243
// / while(1)
243
244
// / {
@@ -246,18 +247,11 @@ class asio_connection
246
247
// / pool.release(conn);
247
248
// / }
248
249
// / </code>
249
- // /
250
- // / Additionally, when two cleanup phases have occurred with no calls to `release()`
251
- // / between them, the internal self-reference is cleared. If there are no active
252
- // / `http_client`s keeping the pool alive, this will cause the pool to expire upon
253
- // / cleanup handler termination. Whenever a new call to `release()` arrives, the self
254
- // / reference is re-applied to keep the pool alive.
255
250
// / </remarks>
256
251
class asio_connection_pool : public std ::enable_shared_from_this<asio_connection_pool>
257
252
{
258
253
public:
259
- asio_connection_pool ()
260
- : m_pool_epoch_timer(crossplat::threadpool::shared_instance().service())
254
+ asio_connection_pool () : m_pool_epoch_timer(crossplat::threadpool::shared_instance().service())
261
255
{}
262
256
263
257
std::shared_ptr<asio_connection> acquire ()
@@ -281,29 +275,29 @@ class asio_connection_pool : public std::enable_shared_from_this<asio_connection
281
275
return ;
282
276
283
277
std::lock_guard<std::mutex> lock (m_lock);
284
- if (m_self_reference == nullptr )
278
+ if (!is_timer_running )
285
279
{
286
- auto sptr = this ->shared_from_this ();
287
- m_self_reference = sptr;
288
- start_epoch_interval (sptr);
280
+ start_epoch_interval (shared_from_this ());
281
+ is_timer_running = true ;
289
282
}
290
283
291
284
m_epoch++;
292
- m_connections.emplace_back (m_epoch, connection);
285
+ m_connections.emplace_back (m_epoch, std::move ( connection) );
293
286
}
294
287
295
288
private:
296
289
// Note: must be called under m_lock
297
- static void start_epoch_interval (const std::shared_ptr<asio_connection_pool>& pool) {
290
+ static void start_epoch_interval (const std::shared_ptr<asio_connection_pool>& pool)
291
+ {
298
292
_ASSERTE (pool.get () != nullptr );
299
- _ASSERTE (pool->m_self_reference != nullptr );
300
293
301
294
auto & self = *pool;
302
295
std::weak_ptr<asio_connection_pool> weak_pool = pool;
303
296
304
297
self.m_prev_epoch = self.m_epoch ;
305
298
pool->m_pool_epoch_timer .expires_from_now (boost::posix_time::seconds (30 ));
306
- pool->m_pool_epoch_timer .async_wait ([weak_pool](const boost::system::error_code& ec) {
299
+ pool->m_pool_epoch_timer .async_wait ([weak_pool](const boost::system::error_code& ec)
300
+ {
307
301
if (ec)
308
302
return ;
309
303
@@ -313,11 +307,11 @@ class asio_connection_pool : public std::enable_shared_from_this<asio_connection
313
307
auto & self = *pool;
314
308
315
309
std::lock_guard<std::mutex> lock (self.m_lock );
316
- _ASSERTE (self.m_self_reference != nullptr );
317
310
if (self.m_prev_epoch == self.m_epoch )
318
311
{
319
312
self.m_connections .clear ();
320
- self.m_self_reference = nullptr ;
313
+ self.is_timer_running = false ;
314
+ return ;
321
315
}
322
316
else
323
317
{
@@ -335,109 +329,23 @@ class asio_connection_pool : public std::enable_shared_from_this<asio_connection
335
329
}
336
330
337
331
std::mutex m_lock;
338
- boost::asio::deadline_timer m_pool_epoch_timer;
339
332
std::deque<std::pair<uint64_t , std::shared_ptr<asio_connection>>> m_connections;
333
+
340
334
uint64_t m_epoch = 0 ;
341
335
uint64_t m_prev_epoch = 0 ;
342
-
343
- std::shared_ptr<asio_connection_pool> m_self_reference;
344
- };
345
-
346
- class asio_shared_connection_pool : public std ::enable_shared_from_this<asio_shared_connection_pool>
347
- {
348
- public:
349
- std::shared_ptr<asio_connection_pool> obtain (const std::string &pool_key)
350
- {
351
- std::shared_ptr<asio_connection_pool> ret;
352
-
353
- std::lock_guard<std::mutex> lock (m_lock);
354
- auto it = m_pools.find (pool_key);
355
- if (it != m_pools.end ())
356
- {
357
- ret = it->second .lock ();
358
- if (ret == nullptr )
359
- {
360
- // Previous pool expired
361
- ret = std::make_shared<asio_connection_pool>();
362
- it->second = ret;
363
- }
364
- }
365
- else
366
- {
367
- if (m_pools.empty ())
368
- {
369
- // If transitioning from empty to having a single element, restart the timer.
370
- start_timer (shared_from_this ());
371
- }
372
- ret = std::make_shared<asio_connection_pool>();
373
- m_pools.emplace (pool_key, ret);
374
- }
375
-
376
- assert (ret != nullptr );
377
- return ret;
378
- }
379
-
380
- static std::shared_ptr<asio_shared_connection_pool>& shared_instance ()
381
- {
382
- static std::shared_ptr<asio_shared_connection_pool> s_instance = std::make_shared<asio_shared_connection_pool>();
383
-
384
- return s_instance;
385
- }
386
-
387
- asio_shared_connection_pool () : m_timer(crossplat::threadpool::shared_instance().service()) {}
388
-
389
- private:
390
- static void start_timer (const std::shared_ptr<asio_shared_connection_pool>& self)
391
- {
392
- self->m_timer .expires_from_now (boost::posix_time::seconds (60 ));
393
- std::weak_ptr<asio_shared_connection_pool> weak_this = self;
394
- self->m_timer .async_wait ([weak_this](const boost::system::error_code& ec)
395
- {
396
- if (ec)
397
- return ;
398
- auto strong_this = weak_this.lock ();
399
- if (!strong_this)
400
- return ;
401
-
402
- std::lock_guard<std::mutex> lock (strong_this->m_lock );
403
- auto b = strong_this->m_pools .begin ();
404
- auto e = strong_this->m_pools .end ();
405
- for (; b != e;)
406
- {
407
- if (b->second .expired ())
408
- b = strong_this->m_pools .erase (b);
409
- else
410
- ++b;
411
- }
412
- if (!strong_this->m_pools .empty ())
413
- start_timer (strong_this);
414
- });
415
- }
416
-
417
- boost::asio::deadline_timer m_timer;
418
- std::mutex m_lock;
419
- std::unordered_map<std::string, std::weak_ptr<asio_connection_pool>> m_pools;
336
+ bool is_timer_running = false ;
337
+ boost::asio::deadline_timer m_pool_epoch_timer;
420
338
};
421
339
422
340
class asio_client final : public _http_client_communicator
423
341
{
424
342
public:
425
- asio_client (http::uri address, http_client_config client_config)
426
- : _http_client_communicator(std::move(address), std::move(client_config))
427
- , m_resolver(crossplat::threadpool::shared_instance().service())
428
- {
429
- m_start_with_ssl = base_uri ().scheme () == " https" && !this ->client_config ().proxy ().is_specified ();
430
-
431
- if (this ->client_config ().get_ssl_context_callback ())
432
- {
433
- // We will use a private connection pool because there is no better approaches to compare callback functors.
434
- m_pool = std::make_shared<asio_connection_pool>();
435
- }
436
- else
437
- {
438
- m_pool = asio_shared_connection_pool::shared_instance ()->obtain (get_pool_key ());
439
- }
440
- }
343
+ asio_client (http::uri&& address, http_client_config&& client_config)
344
+ : _http_client_communicator(std::move(address), std::move(client_config))
345
+ , m_resolver(crossplat::threadpool::shared_instance().service())
346
+ , m_pool(std::make_shared<asio_connection_pool>())
347
+ , m_start_with_ssl(base_uri().scheme() == " https" && !this ->client_config ().proxy().is_specified())
348
+ {}
441
349
442
350
void send_request (const std::shared_ptr<request_context> &request_ctx) override ;
443
351
@@ -464,35 +372,11 @@ class asio_client final : public _http_client_communicator
464
372
465
373
virtual pplx::task<http_response> propagate (http_request request) override ;
466
374
467
- private:
468
- std::string get_pool_key () const
469
- {
470
- auto pool_key = base_uri ().to_string ();
471
-
472
- auto &credentials = _http_client_communicator::client_config ().credentials ();
473
- if (credentials.is_set ())
474
- {
475
- pool_key.append (credentials.username ());
476
- }
477
-
478
- auto &proxy = _http_client_communicator::client_config ().proxy ();
479
- if (proxy.is_specified ())
480
- {
481
- pool_key.append (proxy.address ().to_string ());
482
- if (proxy.credentials ().is_set ())
483
- {
484
- pool_key.append (proxy.credentials ().username ());
485
- }
486
- }
487
-
488
- return pool_key;
489
- }
490
-
491
- std::shared_ptr<asio_connection_pool> m_pool;
492
375
public:
493
376
tcp::resolver m_resolver;
494
377
private:
495
- bool m_start_with_ssl;
378
+ const std::shared_ptr<asio_connection_pool> m_pool;
379
+ const bool m_start_with_ssl;
496
380
};
497
381
498
382
class asio_context : public request_context , public std ::enable_shared_from_this<asio_context>
@@ -1612,9 +1496,9 @@ class asio_context : public request_context, public std::enable_shared_from_this
1612
1496
};
1613
1497
1614
1498
1615
- std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage (uri base_uri, const http_client_config& client_config)
1499
+ std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage (uri&& base_uri, http_client_config& & client_config)
1616
1500
{
1617
- return std::make_shared<asio_client>(base_uri, client_config);
1501
+ return std::make_shared<asio_client>(std::move ( base_uri), std::move ( client_config) );
1618
1502
}
1619
1503
1620
1504
void asio_client::send_request (const std::shared_ptr<request_context> &request_ctx)
0 commit comments