1 /* connpool.cpp
2 */
3
4
5 /**
6 * Copyright (C) 2018-present MongoDB, Inc.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the Server Side Public License, version 1,
10 * as published by MongoDB, Inc.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * Server Side Public License for more details.
16 *
17 * You should have received a copy of the Server Side Public License
18 * along with this program. If not, see
19 * <http://www.mongodb.com/licensing/server-side-public-license>.
20 *
21 * As a special exception, the copyright holders give permission to link the
22 * code of portions of this program with the OpenSSL library under certain
23 * conditions as described in each individual source file and distribute
24 * linked combinations including the program with the OpenSSL library. You
25 * must comply with the Server Side Public License in all respects for
26 * all of the code used other than as permitted herein. If you modify file(s)
27 * with this exception, you may extend this exception to your version of the
28 * file(s), but you are not obligated to do so. If you do not wish to do so,
29 * delete this exception statement from your version. If you delete this
30 * exception statement from all source files in the program, then also delete
31 * it in the license file.
32 */
33
34 // _ todo: reconnect?
35
36 #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kNetwork
37
38 #include "mongo/platform/basic.h"
39
40 #include "mongo/client/connpool.h"
41
42 #include <limits>
43 #include <string>
44
45 #include "mongo/client/connection_string.h"
46 #include "mongo/client/global_conn_pool.h"
47 #include "mongo/client/replica_set_monitor.h"
48 #include "mongo/executor/connection_pool_stats.h"
49 #include "mongo/stdx/chrono.h"
50 #include "mongo/util/exit.h"
51 #include "mongo/util/log.h"
52 #include "mongo/util/net/socket_exception.h"
53
54 #if !defined(__has_feature)
55 #define __has_feature(x) 0
56 #endif
57
58 #if __has_feature(address_sanitizer)
59 #include <sanitizer/lsan_interface.h>
60 #endif
61
62 namespace mongo {
63
64 namespace {
65 const int kDefaultIdleTimeout = std::numeric_limits<int>::max();
66 const int kDefaultMaxInUse = std::numeric_limits<int>::max();
67 } // namespace
68
69 using std::endl;
70 using std::list;
71 using std::map;
72 using std::set;
73 using std::string;
74 using std::vector;
75
76 // ------ PoolForHost ------
77
PoolForHost()78 PoolForHost::PoolForHost()
79 : _created(0),
80 _minValidCreationTimeMicroSec(0),
81 _type(ConnectionString::INVALID),
82 _maxPoolSize(kPoolSizeUnlimited),
83 _maxInUse(kDefaultMaxInUse),
84 _checkedOut(0),
85 _badConns(0),
86 _parentDestroyed(false),
87 _inShutdown(false) {}
88
~PoolForHost()89 PoolForHost::~PoolForHost() {
90 clear();
91 }
92
clear()93 void PoolForHost::clear() {
94 if (!_parentDestroyed) {
95 logNoCache() << "Dropping all pooled connections to " << _hostName << "(with timeout of "
96 << _socketTimeoutSecs << " seconds)";
97 }
98
99 _pool = decltype(_pool){};
100 }
101
done(DBConnectionPool * pool,DBClientBase * c_raw)102 void PoolForHost::done(DBConnectionPool* pool, DBClientBase* c_raw) {
103 std::unique_ptr<DBClientBase> c{c_raw};
104 const bool isFailed = c->isFailed();
105
106 --_checkedOut;
107
108 // Remember that this host had a broken connection for later
109 if (isFailed) {
110 reportBadConnectionAt(c->getSockCreationMicroSec());
111 }
112
113 // Another (later) connection was reported as broken to this host
114 bool isBroken = c->getSockCreationMicroSec() < _minValidCreationTimeMicroSec;
115 if (isFailed || isBroken) {
116 _badConns++;
117 logNoCache() << "Ending connection to host " << _hostName << "(with timeout of "
118 << _socketTimeoutSecs << " seconds)"
119 << " due to bad connection status; " << openConnections()
120 << " connections to that host remain open";
121 pool->onDestroy(c.get());
122 } else if (_maxPoolSize >= 0 && static_cast<int>(_pool.size()) >= _maxPoolSize) {
123 // We have a pool size that we need to enforce
124 logNoCache() << "Ending idle connection to host " << _hostName << "(with timeout of "
125 << _socketTimeoutSecs << " seconds)"
126 << " because the pool meets constraints; " << openConnections()
127 << " connections to that host remain open";
128 pool->onDestroy(c.get());
129 } else {
130 // The connection is probably fine, save for later
131 _pool.push(std::move(c));
132 }
133 }
134
reportBadConnectionAt(uint64_t microSec)135 void PoolForHost::reportBadConnectionAt(uint64_t microSec) {
136 if (microSec != DBClientBase::INVALID_SOCK_CREATION_TIME &&
137 microSec > _minValidCreationTimeMicroSec) {
138 _minValidCreationTimeMicroSec = microSec;
139 logNoCache() << "Detected bad connection created at " << _minValidCreationTimeMicroSec
140 << " microSec, clearing pool for " << _hostName << " of " << openConnections()
141 << " connections" << endl;
142 clear();
143 }
144 }
145
isBadSocketCreationTime(uint64_t microSec)146 bool PoolForHost::isBadSocketCreationTime(uint64_t microSec) {
147 return microSec != DBClientBase::INVALID_SOCK_CREATION_TIME &&
148 microSec <= _minValidCreationTimeMicroSec;
149 }
150
get(DBConnectionPool * pool,double socketTimeout)151 DBClientBase* PoolForHost::get(DBConnectionPool* pool, double socketTimeout) {
152 while (!_pool.empty()) {
153 auto sc = std::move(_pool.top());
154 _pool.pop();
155
156 if (!sc.ok()) {
157 _badConns++;
158 pool->onDestroy(sc.conn.get());
159 continue;
160 }
161
162 verify(sc.conn->getSoTimeout() == socketTimeout);
163
164 ++_checkedOut;
165 return sc.conn.release();
166 }
167
168 return nullptr;
169 }
170
flush()171 void PoolForHost::flush() {
172 clear();
173 }
174
getStaleConnections(Date_t idleThreshold,vector<DBClientBase * > & stale)175 void PoolForHost::getStaleConnections(Date_t idleThreshold, vector<DBClientBase*>& stale) {
176 vector<StoredConnection> all;
177 while (!_pool.empty()) {
178 StoredConnection c = std::move(_pool.top());
179 _pool.pop();
180
181 if (c.ok() && !c.addedBefore(idleThreshold)) {
182 all.push_back(std::move(c));
183 } else {
184 _badConns++;
185 stale.emplace_back(c.conn.release());
186 }
187 }
188
189 for (auto& conn : all) {
190 _pool.push(std::move(conn));
191 }
192 }
193
194
StoredConnection(std::unique_ptr<DBClientBase> c)195 PoolForHost::StoredConnection::StoredConnection(std::unique_ptr<DBClientBase> c)
196 : conn(std::move(c)), added(Date_t::now()) {}
197
ok()198 bool PoolForHost::StoredConnection::ok() {
199 // Poke the connection to see if we're still ok
200 return conn->isStillConnected();
201 }
202
addedBefore(Date_t time)203 bool PoolForHost::StoredConnection::addedBefore(Date_t time) {
204 return added < time;
205 }
206
createdOne(DBClientBase * base)207 void PoolForHost::createdOne(DBClientBase* base) {
208 if (_created == 0)
209 _type = base->type();
210 ++_created;
211 // _checkedOut is used to indicate the number of in-use connections so
212 // though we didn't actually check this connection out, we bump it here.
213 ++_checkedOut;
214 }
215
initializeHostName(const std::string & hostName)216 void PoolForHost::initializeHostName(const std::string& hostName) {
217 if (_hostName.empty()) {
218 _hostName = hostName;
219 }
220 }
221
waitForFreeConnection(int timeout,stdx::unique_lock<stdx::mutex> & lk)222 void PoolForHost::waitForFreeConnection(int timeout, stdx::unique_lock<stdx::mutex>& lk) {
223 auto condition = [&] { return (numInUse() < _maxInUse || _inShutdown.load()); };
224
225 if (timeout > 0) {
226 stdx::chrono::seconds timeoutSeconds{timeout};
227
228 // If we timed out waiting without getting a new connection, throw.
229 uassert(ErrorCodes::ExceededTimeLimit,
230 str::stream() << "too many connections to " << _hostName << ":" << timeout,
231 !_cv.wait_for(lk, timeoutSeconds, condition));
232 } else {
233 _cv.wait(lk, condition);
234 }
235 }
236
notifyWaiters()237 void PoolForHost::notifyWaiters() {
238 _cv.notify_one();
239 }
240
shutdown()241 void PoolForHost::shutdown() {
242 _inShutdown.store(true);
243 _cv.notify_all();
244 }
245
246 // ------ DBConnectionPool::Detail ------
247
248 class DBConnectionPool::Detail {
249 public:
250 template <typename Connect>
get(DBConnectionPool * _this,const std::string & host,double timeout,Connect connect)251 static DBClientBase* get(DBConnectionPool* _this,
252 const std::string& host,
253 double timeout,
254 Connect connect) {
255 while (!(_this->_inShutdown.load())) {
256 // Get a connection from the pool, if there is one.
257 std::unique_ptr<DBClientBase> c(_this->_get(host, timeout));
258 if (c) {
259 // This call may throw.
260 _this->onHandedOut(c.get());
261 return c.release();
262 }
263
264 // If there are no pooled connections for this host, create a new connection. If
265 // there are too many connections in this pool to make a new one, block until a
266 // connection is released.
267 {
268 stdx::unique_lock<stdx::mutex> lk(_this->_mutex);
269 PoolForHost& p = _this->_pools[PoolKey(host, timeout)];
270
271 if (p.openConnections() >= _this->_maxInUse) {
272 log() << "Too many in-use connections; waiting until there are fewer than "
273 << _this->_maxInUse;
274 p.waitForFreeConnection(timeout, lk);
275 } else {
276 // Drop the lock here, so we can connect without holding it.
277 // _finishCreate will take the lock again.
278 lk.unlock();
279
280 // Create a new connection and return. All Connect functions
281 // should throw if they cannot create a connection.
282 auto c = connect();
283 invariant(c);
284 return _this->_finishCreate(host, timeout, c);
285 }
286 }
287 }
288
289 // If we get here, we are in shutdown, and it does not matter what we return.
290 invariant(_this->_inShutdown.load());
291 uassert(ErrorCodes::ShutdownInProgress, "connection pool is in shutdown", false);
292 MONGO_UNREACHABLE;
293 }
294 };
295
296 // ------ DBConnectionPool ------
297
298 const int PoolForHost::kPoolSizeUnlimited(-1);
299
DBConnectionPool()300 DBConnectionPool::DBConnectionPool()
301 : _name("dbconnectionpool"),
302 _maxPoolSize(PoolForHost::kPoolSizeUnlimited),
303 _maxInUse(kDefaultMaxInUse),
304 _idleTimeout(kDefaultIdleTimeout),
305 _inShutdown(false),
306 _hooks(new list<DBConnectionHook*>())
307
308 {}
309
shutdown()310 void DBConnectionPool::shutdown() {
311 if (!_inShutdown.swap(true)) {
312 stdx::lock_guard<stdx::mutex> L(_mutex);
313 for (auto i = _pools.begin(); i != _pools.end(); i++) {
314 PoolForHost& p = i->second;
315 p.shutdown();
316 }
317 }
318 }
319
_get(const string & ident,double socketTimeout)320 DBClientBase* DBConnectionPool::_get(const string& ident, double socketTimeout) {
321 uassert(ErrorCodes::ShutdownInProgress,
322 "Can't use connection pool during shutdown",
323 !globalInShutdownDeprecated());
324 stdx::lock_guard<stdx::mutex> L(_mutex);
325 PoolForHost& p = _pools[PoolKey(ident, socketTimeout)];
326 p.setMaxPoolSize(_maxPoolSize);
327 p.setSocketTimeout(socketTimeout);
328 p.initializeHostName(ident);
329 return p.get(this, socketTimeout);
330 }
331
openConnections(const string & ident,double socketTimeout)332 int DBConnectionPool::openConnections(const string& ident, double socketTimeout) {
333 stdx::lock_guard<stdx::mutex> L(_mutex);
334 PoolForHost& p = _pools[PoolKey(ident, socketTimeout)];
335 return p.openConnections();
336 }
337
_finishCreate(const string & ident,double socketTimeout,DBClientBase * conn)338 DBClientBase* DBConnectionPool::_finishCreate(const string& ident,
339 double socketTimeout,
340 DBClientBase* conn) {
341 {
342 stdx::lock_guard<stdx::mutex> L(_mutex);
343 PoolForHost& p = _pools[PoolKey(ident, socketTimeout)];
344 p.setMaxPoolSize(_maxPoolSize);
345 p.initializeHostName(ident);
346 p.createdOne(conn);
347 }
348
349 try {
350 onCreate(conn);
351 onHandedOut(conn);
352 } catch (std::exception&) {
353 delete conn;
354 throw;
355 }
356
357 log() << "Successfully connected to " << ident << " (" << openConnections(ident, socketTimeout)
358 << " connections now open to " << ident << " with a " << socketTimeout
359 << " second timeout)";
360
361 return conn;
362 }
363
get(const ConnectionString & url,double socketTimeout)364 DBClientBase* DBConnectionPool::get(const ConnectionString& url, double socketTimeout) {
365 auto connect = [&]() {
366 string errmsg;
367 auto c = url.connect(StringData(), errmsg, socketTimeout).release();
368 uassert(13328, _name + ": connect failed " + url.toString() + " : " + errmsg, c);
369 return c;
370 };
371
372 return Detail::get(this, url.toString(), socketTimeout, connect);
373 }
374
get(const string & host,double socketTimeout)375 DBClientBase* DBConnectionPool::get(const string& host, double socketTimeout) {
376 auto connect = [&] {
377 const ConnectionString cs(uassertStatusOK(ConnectionString::parse(host)));
378
379 string errmsg;
380 auto c = cs.connect(StringData(), errmsg, socketTimeout).release();
381 if (!c) {
382 throw SocketException(SocketException::CONNECT_ERROR,
383 host,
384 11002,
385 str::stream() << _name << " error: " << errmsg);
386 }
387
388 return c;
389 };
390
391 return Detail::get(this, host, socketTimeout, connect);
392 }
393
get(const MongoURI & uri,double socketTimeout)394 DBClientBase* DBConnectionPool::get(const MongoURI& uri, double socketTimeout) {
395 auto connect = [&] {
396 string errmsg;
397 std::unique_ptr<DBClientBase> c(uri.connect(StringData(), errmsg, socketTimeout));
398 uassert(40356, _name + ": connect failed " + uri.toString() + " : " + errmsg, c);
399 return c.release();
400 };
401
402 return Detail::get(this, uri.toString(), socketTimeout, connect);
403 }
404
getNumAvailableConns(const string & host,double socketTimeout) const405 int DBConnectionPool::getNumAvailableConns(const string& host, double socketTimeout) const {
406 stdx::lock_guard<stdx::mutex> L(_mutex);
407 auto it = _pools.find(PoolKey(host, socketTimeout));
408 return (it == _pools.end()) ? 0 : it->second.numAvailable();
409 }
410
getNumBadConns(const string & host,double socketTimeout) const411 int DBConnectionPool::getNumBadConns(const string& host, double socketTimeout) const {
412 stdx::lock_guard<stdx::mutex> L(_mutex);
413 auto it = _pools.find(PoolKey(host, socketTimeout));
414 return (it == _pools.end()) ? 0 : it->second.getNumBadConns();
415 }
416
onRelease(DBClientBase * conn)417 void DBConnectionPool::onRelease(DBClientBase* conn) {
418 if (_hooks->empty()) {
419 return;
420 }
421
422 for (list<DBConnectionHook*>::iterator i = _hooks->begin(); i != _hooks->end(); i++) {
423 (*i)->onRelease(conn);
424 }
425 }
426
release(const string & host,DBClientBase * c)427 void DBConnectionPool::release(const string& host, DBClientBase* c) {
428 onRelease(c);
429
430 stdx::unique_lock<stdx::mutex> lk(_mutex);
431 PoolForHost& p = _pools[PoolKey(host, c->getSoTimeout())];
432 p.done(this, c);
433
434 lk.unlock();
435 p.notifyWaiters();
436 }
437
decrementEgress(const string & host,DBClientBase * c)438 void DBConnectionPool::decrementEgress(const string& host, DBClientBase* c) {
439 stdx::lock_guard<stdx::mutex> L(_mutex);
440 PoolForHost& p = _pools[PoolKey(host, c->getSoTimeout())];
441 --p._checkedOut;
442 }
443
~DBConnectionPool()444 DBConnectionPool::~DBConnectionPool() {
445 // Do not log in destruction, because global connection pools get
446 // destroyed after the logging framework.
447 stdx::lock_guard<stdx::mutex> L(_mutex);
448 for (PoolMap::iterator i = _pools.begin(); i != _pools.end(); i++) {
449 PoolForHost& p = i->second;
450 p._parentDestroyed = true;
451 }
452
453 #if __has_feature(address_sanitizer)
454 __lsan_ignore_object(_hooks);
455 #endif
456 }
457
flush()458 void DBConnectionPool::flush() {
459 stdx::lock_guard<stdx::mutex> L(_mutex);
460 for (PoolMap::iterator i = _pools.begin(); i != _pools.end(); i++) {
461 PoolForHost& p = i->second;
462 p.flush();
463 }
464 }
465
clear()466 void DBConnectionPool::clear() {
467 stdx::lock_guard<stdx::mutex> L(_mutex);
468 LOG(2) << "Removing connections on all pools owned by " << _name << endl;
469 for (PoolMap::iterator iter = _pools.begin(); iter != _pools.end(); ++iter) {
470 iter->second.clear();
471 }
472 }
473
removeHost(const string & host)474 void DBConnectionPool::removeHost(const string& host) {
475 stdx::lock_guard<stdx::mutex> L(_mutex);
476 LOG(2) << "Removing connections from all pools for host: " << host << endl;
477 for (PoolMap::iterator i = _pools.begin(); i != _pools.end(); ++i) {
478 const string& poolHost = i->first.ident;
479 if (!serverNameCompare()(host, poolHost) && !serverNameCompare()(poolHost, host)) {
480 // hosts are the same
481 i->second.clear();
482 }
483 }
484 }
485
addHook(DBConnectionHook * hook)486 void DBConnectionPool::addHook(DBConnectionHook* hook) {
487 _hooks->push_back(hook);
488 }
489
onCreate(DBClientBase * conn)490 void DBConnectionPool::onCreate(DBClientBase* conn) {
491 if (_hooks->size() == 0)
492 return;
493
494 for (list<DBConnectionHook*>::iterator i = _hooks->begin(); i != _hooks->end(); i++) {
495 (*i)->onCreate(conn);
496 }
497 }
498
onHandedOut(DBClientBase * conn)499 void DBConnectionPool::onHandedOut(DBClientBase* conn) {
500 if (_hooks->size() == 0)
501 return;
502
503 for (list<DBConnectionHook*>::iterator i = _hooks->begin(); i != _hooks->end(); i++) {
504 (*i)->onHandedOut(conn);
505 }
506 }
507
onDestroy(DBClientBase * conn)508 void DBConnectionPool::onDestroy(DBClientBase* conn) {
509 if (_hooks->size() == 0)
510 return;
511
512 for (list<DBConnectionHook*>::iterator i = _hooks->begin(); i != _hooks->end(); i++) {
513 (*i)->onDestroy(conn);
514 }
515 }
516
appendConnectionStats(executor::ConnectionPoolStats * stats) const517 void DBConnectionPool::appendConnectionStats(executor::ConnectionPoolStats* stats) const {
518 {
519 stdx::lock_guard<stdx::mutex> lk(_mutex);
520 for (PoolMap::const_iterator i = _pools.begin(); i != _pools.end(); ++i) {
521 if (i->second.numCreated() == 0)
522 continue;
523
524 // Mongos may use either a replica set uri or a list of addresses as
525 // the identifier here, so we always take the first server parsed out
526 // as our label for connPoolStats. Note that these stats will collide
527 // with any existing stats for the chosen host.
528 auto uri = ConnectionString::parse(i->first.ident);
529 invariant(uri.isOK());
530 HostAndPort host = uri.getValue().getServers().front();
531
532 executor::ConnectionStatsPer hostStats{static_cast<size_t>(i->second.numInUse()),
533 static_cast<size_t>(i->second.numAvailable()),
534 static_cast<size_t>(i->second.numCreated()),
535 0};
536 stats->updateStatsForHost("global", host, hostStats);
537 }
538 }
539 }
540
operator ()(const string & a,const string & b) const541 bool DBConnectionPool::serverNameCompare::operator()(const string& a, const string& b) const {
542 const char* ap = a.c_str();
543 const char* bp = b.c_str();
544
545 while (true) {
546 if (*ap == '\0' || *ap == '/') {
547 if (*bp == '\0' || *bp == '/')
548 return false; // equal strings
549 else
550 return true; // a is shorter
551 }
552
553 if (*bp == '\0' || *bp == '/')
554 return false; // b is shorter
555
556 if (*ap < *bp)
557 return true;
558 else if (*ap > *bp)
559 return false;
560
561 ++ap;
562 ++bp;
563 }
564 verify(false);
565 }
566
operator ()(const PoolKey & a,const PoolKey & b) const567 bool DBConnectionPool::poolKeyCompare::operator()(const PoolKey& a, const PoolKey& b) const {
568 if (DBConnectionPool::serverNameCompare()(a.ident, b.ident))
569 return true;
570
571 if (DBConnectionPool::serverNameCompare()(b.ident, a.ident))
572 return false;
573
574 return a.timeout < b.timeout;
575 }
576
isConnectionGood(const string & hostName,DBClientBase * conn)577 bool DBConnectionPool::isConnectionGood(const string& hostName, DBClientBase* conn) {
578 if (conn == NULL) {
579 return false;
580 }
581
582 if (conn->isFailed()) {
583 return false;
584 }
585
586 {
587 stdx::lock_guard<stdx::mutex> sl(_mutex);
588 PoolForHost& pool = _pools[PoolKey(hostName, conn->getSoTimeout())];
589 if (pool.isBadSocketCreationTime(conn->getSockCreationMicroSec())) {
590 return false;
591 }
592 }
593
594 return true;
595 }
596
taskDoWork()597 void DBConnectionPool::taskDoWork() {
598 vector<DBClientBase*> toDelete;
599 auto idleThreshold = Date_t::now() - _idleTimeout;
600 {
601 // we need to get the connections inside the lock
602 // but we can actually delete them outside
603 stdx::lock_guard<stdx::mutex> lk(_mutex);
604 for (PoolMap::iterator i = _pools.begin(); i != _pools.end(); ++i) {
605 i->second.getStaleConnections(idleThreshold, toDelete);
606 }
607 }
608
609 for (size_t i = 0; i < toDelete.size(); i++) {
610 try {
611 onDestroy(toDelete[i]);
612 delete toDelete[i];
613 } catch (...) {
614 // we don't care if there was a socket error
615 }
616 }
617 }
618
619 // ------ ScopedDbConnection ------
620
ScopedDbConnection(const std::string & host,double socketTimeout)621 ScopedDbConnection::ScopedDbConnection(const std::string& host, double socketTimeout)
622 : _host(host),
623 _conn(globalConnPool.get(host, socketTimeout)),
624 _socketTimeoutSecs(socketTimeout) {
625 _setSocketTimeout();
626 }
627
ScopedDbConnection(const ConnectionString & host,double socketTimeout)628 ScopedDbConnection::ScopedDbConnection(const ConnectionString& host, double socketTimeout)
629 : _host(host.toString()),
630 _conn(globalConnPool.get(host, socketTimeout)),
631 _socketTimeoutSecs(socketTimeout) {
632 _setSocketTimeout();
633 }
634
ScopedDbConnection(const MongoURI & uri,double socketTimeout)635 ScopedDbConnection::ScopedDbConnection(const MongoURI& uri, double socketTimeout)
636 : _host(uri.toString()),
637 _conn(globalConnPool.get(uri, socketTimeout)),
638 _socketTimeoutSecs(socketTimeout) {
639 _setSocketTimeout();
640 }
641
done()642 void ScopedDbConnection::done() {
643 if (!_conn) {
644 return;
645 }
646
647 globalConnPool.release(_host, _conn);
648 _conn = NULL;
649 }
650
kill()651 void ScopedDbConnection::kill() {
652 globalConnPool.decrementEgress(_host, _conn);
653 delete _conn;
654 _conn = NULL;
655 }
656
_setSocketTimeout()657 void ScopedDbConnection::_setSocketTimeout() {
658 if (!_conn)
659 return;
660
661 if (_conn->type() == ConnectionString::MASTER)
662 static_cast<DBClientConnection*>(_conn)->setSoTimeout(_socketTimeoutSecs);
663 }
664
~ScopedDbConnection()665 ScopedDbConnection::~ScopedDbConnection() {
666 if (_conn) {
667 if (_conn->isFailed()) {
668 if (_conn->getSockCreationMicroSec() == DBClientBase::INVALID_SOCK_CREATION_TIME) {
669 kill();
670 } else {
671 // The pool takes care of deleting the failed connection - this
672 // will also trigger disposal of older connections in the pool
673 done();
674 }
675 } else {
676 /* see done() comments above for why we log this line */
677 logNoCache() << "scoped connection to " << _conn->getServerAddress()
678 << " not being returned to the pool" << endl;
679 kill();
680 }
681 }
682 }
683
clearPool()684 void ScopedDbConnection::clearPool() {
685 globalConnPool.clear();
686 }
687
688 AtomicInt32 AScopedConnection::_numConnections;
689
690 } // namespace mongo
691