@@ -87,18 +87,22 @@ class ConnectionPoolImpl
87
87
Connection::ptr_t & GetConnection () noexcept { return connection; }
88
88
int GetTtl () const noexcept { return ttl; }
89
89
time_t GetCreated () const noexcept { return created;}
90
- timestamp_t GetLastUsed () const noexcept { return last_used; }
90
+ timestamp_t GetLastUsed () const noexcept {
91
+ LOCK_ALWAYS_;
92
+ return last_used;
93
+ }
94
+ void SetLastUsed (timestamp_t ts) {
95
+ LOCK_ALWAYS_;
96
+ last_used = ts;
97
+ }
91
98
92
99
private:
93
100
const Key key;
94
101
Connection::ptr_t connection;
95
102
const int ttl = 60 ;
96
103
const time_t created;
97
- #ifdef RESTC_CPP_THREADED_CTX
98
- atomic<timestamp_t > last_used = chrono::steady_clock::now();
99
- #else
104
+ mutable std::mutex mutex_;
100
105
timestamp_t last_used = chrono::steady_clock::now();
101
- #endif
102
106
};
103
107
104
108
// Owns the connection
@@ -145,10 +149,6 @@ class ConnectionPoolImpl
145
149
ConnectionPoolImpl (RestClient& owner)
146
150
: owner_{owner}, properties_{owner.GetConnectionProperties ()}
147
151
, cache_cleanup_timer_{owner.GetIoService ()}
148
- #ifdef RESTC_CPP_THREADED_CTX
149
- , strand_{owner_.GetIoService ()}
150
- #endif
151
-
152
152
{
153
153
on_release_ = [this ](const Entry::ptr_t & entry) { OnRelease (entry); };
154
154
}
@@ -175,32 +175,27 @@ class ConnectionPoolImpl
175
175
}
176
176
177
177
// Get ctx for internal, syncronized operations;
178
- #ifdef RESTC_CPP_THREADED_CTX
179
- auto GetCtx () const {
180
- return strand_;
181
- }
182
- #else
183
178
auto & GetCtx () const {
184
179
return owner_.GetIoService ();
185
180
}
186
- #endif
187
181
188
- std::future<std::size_t > GetIdleConnections () const override {
189
- auto my_promise = make_shared<promise<size_t >>() ;
190
- GetCtx ().dispatch ([my_promise, this ]() {
191
- my_promise->set_value (idle_.size ());
192
- });
193
- return my_promise->get_future ();
182
+ size_t GetIdleConnections () const override {
183
+ LOCK_ALWAYS_;
184
+ return idle_.size ();
194
185
}
195
186
196
187
void Close () override {
188
+ RESTC_CPP_LOG_TRACE_ (" ConnectionPoolImpl::Close: enter" );
197
189
if (!closed_) {
198
- closed_ = true ;
199
- GetCtx ().dispatch ([this ]{
190
+ call_once (close_once_, [this ] {
191
+ RESTC_CPP_LOG_TRACE_ (" ConnectionPoolImpl::Close: closing *once*." );
192
+ LOCK_ALWAYS_;
193
+ closed_ = true ;
200
194
cache_cleanup_timer_.cancel ();
201
195
idle_.clear ();
202
196
});
203
197
}
198
+ RESTC_CPP_LOG_TRACE_ (" ConnectionPoolImpl::Close: leave" );
204
199
}
205
200
206
201
void StartTimer () {
@@ -209,16 +204,17 @@ class ConnectionPoolImpl
209
204
210
205
private:
211
206
void ScheduleNextCacheCleanup () {
212
- GetCtx ().dispatch ([this ]{
213
- cache_cleanup_timer_.expires_from_now (
214
- boost::posix_time::seconds (properties_->cacheCleanupIntervalSeconds ));
215
- cache_cleanup_timer_.async_wait (std::bind (&ConnectionPoolImpl::OnCacheCleanup,
216
- shared_from_this (), std::placeholders::_1));
217
- });
207
+ LOCK_ALWAYS_;
208
+ cache_cleanup_timer_.expires_from_now (
209
+ boost::posix_time::seconds (properties_->cacheCleanupIntervalSeconds ));
210
+ cache_cleanup_timer_.async_wait (std::bind (&ConnectionPoolImpl::OnCacheCleanup,
211
+ shared_from_this (), std::placeholders::_1));
218
212
}
219
213
220
214
void OnCacheCleanup (const boost::system::error_code& error) {
215
+ RESTC_CPP_LOG_TRACE_ (" OnCacheCleanup: enter" );
221
216
if (closed_) {
217
+ RESTC_CPP_LOG_TRACE_ (" OnCacheCleanup: closed" );
222
218
return ;
223
219
}
224
220
@@ -227,10 +223,11 @@ class ConnectionPoolImpl
227
223
return ;
228
224
}
229
225
230
- RESTC_CPP_LOG_TRACE_ (" Cleaning cache..." );
226
+ RESTC_CPP_LOG_TRACE_ (" OnCacheCleanup: Cleaning cache..." );
231
227
232
228
const auto now = std::chrono::steady_clock::now ();
233
229
{
230
+ LOCK_ALWAYS_;
234
231
for (auto it = idle_.begin (); !closed_ && it != idle_.end ();) {
235
232
236
233
auto current = it;
@@ -250,21 +247,27 @@ class ConnectionPoolImpl
250
247
}
251
248
}
252
249
250
+ RESTC_CPP_LOG_TRACE_ (" OnCacheCleanup: schedule next" );
253
251
ScheduleNextCacheCleanup ();
252
+ RESTC_CPP_LOG_TRACE_ (" OnCacheCleanup: leave" );
254
253
}
255
254
256
- void OnRelease (const Entry::ptr_t & entry) {
257
- GetCtx ().dispatch ([this , entry]{
255
+ void OnRelease (const Entry::ptr_t entry) {
256
+ {
257
+ LOCK_ALWAYS_;
258
258
in_use_.erase (entry->GetKey ());
259
- if (closed_ || !entry->GetConnection ()->GetSocket ().IsOpen ()) {
260
- RESTC_CPP_LOG_TRACE_ (" Discarding " << *entry << " after use" );
261
- return ;
262
- }
259
+ }
260
+ if (closed_ || !entry->GetConnection ()->GetSocket ().IsOpen ()) {
261
+ RESTC_CPP_LOG_TRACE_ (" Discarding " << *entry << " after use" );
262
+ return ;
263
+ }
263
264
264
- RESTC_CPP_LOG_TRACE_ (" Recycling " << *entry << " after use" );
265
- entry->GetLastUsed () = chrono::steady_clock::now ();
265
+ RESTC_CPP_LOG_TRACE_ (" Recycling " << *entry << " after use" );
266
+ entry->SetLastUsed (chrono::steady_clock::now ());
267
+ {
268
+ LOCK_ALWAYS_;
266
269
idle_.insert ({entry->GetKey (), entry});
267
- });
270
+ }
268
271
}
269
272
270
273
// Check the constraints to see if we can create a new connection
@@ -277,39 +280,42 @@ class ConnectionPoolImpl
277
280
promise<bool > pr;
278
281
auto result = pr.get_future ();
279
282
280
- GetCtx ().dispatch ([this , &ep, connectionType, &pr]() {
281
- {
282
- const auto key = Key{ep, connectionType};
283
- const size_t ep_cnt = idle_.count (key) + in_use_.count (key);
284
- if (ep_cnt >= properties_->cacheMaxConnectionsPerEndpoint ) {
285
- RESTC_CPP_LOG_DEBUG_ (" No more available slots for " << key);
286
- pr.set_value (false );
287
- return ;
288
- }
289
- }
283
+ size_t cnt = 0 ;
284
+ const auto key = Key{ep, connectionType};
285
+ {
286
+ LOCK_ALWAYS_;
287
+ cnt = idle_.count (key) + in_use_.count (key);
288
+ }
290
289
291
- {
292
- const size_t all_cnt = idle_.size () + in_use_.size ();
293
- if (all_cnt >= properties_->cacheMaxConnections ) {
294
-
295
- // See if we can release an idle connection.
296
- if (!PurgeOldestIdleEntry ()) {
297
- RESTC_CPP_LOG_DEBUG_ (" No more available slots (max="
298
- << properties_->cacheMaxConnections
299
- << " , used=" << all_cnt << ' )' );
300
- pr.set_value (false );
301
- return ;
302
- }
303
- }
304
- }
290
+ if (cnt >= properties_->cacheMaxConnectionsPerEndpoint ) {
291
+ RESTC_CPP_LOG_DEBUG_ (" No more available slots for " << key);
292
+ pr.set_value (false );
293
+ return false ;
294
+ }
305
295
306
- pr.set_value (true );
307
- });
308
296
309
- return result.get ();
297
+ {
298
+ LOCK_ALWAYS_;
299
+ cnt = idle_.size () + in_use_.size ();
300
+ }
301
+ if (cnt >= properties_->cacheMaxConnections ) {
302
+
303
+ // See if we can release an idle connection.
304
+ if (!PurgeOldestIdleEntry ()) {
305
+ RESTC_CPP_LOG_DEBUG_ (" No more available slots (max="
306
+ << properties_->cacheMaxConnections
307
+ << " , used=" << cnt << ' )' );
308
+ pr.set_value (false );
309
+ return false ;
310
+ }
311
+ }
312
+
313
+ return true ;
310
314
}
311
315
312
316
bool PurgeOldestIdleEntry () {
317
+ RESTC_CPP_LOG_TRACE_ (" PurgeOldestIdleEntry: enter" );
318
+ LOCK_ALWAYS_;
313
319
auto oldest = idle_.begin ();
314
320
for (auto it = idle_.begin (); it != idle_.end (); ++it) {
315
321
if (it->second ->GetLastUsed () < oldest->second ->GetLastUsed ()) {
@@ -320,9 +326,11 @@ class ConnectionPoolImpl
320
326
if (oldest != idle_.end ()) {
321
327
RESTC_CPP_LOG_TRACE_ (" LRU-Purging " << *oldest->second );
322
328
idle_.erase (oldest);
329
+ RESTC_CPP_LOG_TRACE_ (" PurgeOldestIdleEntry: success" );
323
330
return true ;
324
331
}
325
332
333
+ RESTC_CPP_LOG_TRACE_ (" PurgeOldestIdleEntry: failed" );
326
334
return false ;
327
335
}
328
336
@@ -336,21 +344,17 @@ class ConnectionPoolImpl
336
344
promise<Connection::ptr_t > pr;
337
345
auto result = pr.get_future ();
338
346
339
- GetCtx ().dispatch ([this , &ep, connectionType, &pr]{
340
- const auto key = Key{ep, connectionType};
341
- auto it = idle_.find (key);
342
- if (it != idle_.end ()) {
343
- auto wrapper = make_unique<ConnectionWrapper>(it->second , on_release_);
344
- in_use_.insert (*it);
345
- idle_.erase (it);
346
- pr.set_value (move (wrapper));
347
- return ;
348
- }
349
-
350
- pr.set_value ({});
351
- });
347
+ LOCK_ALWAYS_;
348
+ const auto key = Key{ep, connectionType};
349
+ auto it = idle_.find (key);
350
+ if (it != idle_.end ()) {
351
+ auto wrapper = make_unique<ConnectionWrapper>(it->second , on_release_);
352
+ in_use_.insert (*it);
353
+ idle_.erase (it);
354
+ return wrapper;
355
+ }
352
356
353
- return result. get () ;
357
+ return {} ;
354
358
}
355
359
356
360
Connection::ptr_t CreateNew (const boost::asio::ip::tcp::endpoint& ep,
@@ -377,31 +381,28 @@ class ConnectionPoolImpl
377
381
promise<Connection::ptr_t > pr;
378
382
auto result = pr.get_future ();
379
383
380
- GetCtx ().dispatch ([this , entry=move (entry), &pr]{
384
+ {
385
+ LOCK_ALWAYS_;
381
386
in_use_.insert ({entry->GetKey (), entry});
382
- pr.set_value (make_unique<ConnectionWrapper>(entry, on_release_));
383
- });
384
-
385
- return result.get ();
387
+ }
388
+ return make_unique<ConnectionWrapper>(entry, on_release_);
386
389
}
387
390
388
391
#ifdef RESTC_CPP_THREADED_CTX
389
- std::atomic_bool closed_ = false ;
392
+ std::atomic_bool closed_{ false } ;
390
393
#else
391
394
bool closed_ = false ;
392
395
#endif
396
+ std::once_flag close_once_;
393
397
RestClient& owner_;
394
398
multimap<Key, Entry::ptr_t > idle_;
395
399
multimap<Key, std::weak_ptr<Entry>> in_use_;
396
- std::queue<Entry> pending_;
400
+ // std::queue<Entry> pending_;
397
401
const Request::Properties::ptr_t properties_;
398
402
ConnectionWrapper::release_callback_t on_release_;
399
403
boost::asio::deadline_timer cache_cleanup_timer_;
400
404
401
- #ifdef RESTC_CPP_THREADED_CTX
402
405
mutable std::mutex mutex_;
403
- boost::asio::io_context::strand strand_;
404
- #endif
405
406
}; // ConnectionPoolImpl
406
407
407
408
0 commit comments