1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 #pragma once 32 33 #include <map> 34 35 #include "mongo/base/disallow_copying.h" 36 #include "mongo/client/dbclientinterface.h" 37 #include "mongo/platform/unordered_map.h" 38 #include "mongo/stdx/list.h" 39 #include "mongo/stdx/mutex.h" 40 #include "mongo/util/net/hostandport.h" 41 #include "mongo/util/time_support.h" 42 43 namespace mongo { 44 namespace executor { 45 class NetworkConnectionHook; 46 } 47 48 /** 49 * Represents a pool of connections to a MongoDB server. The pool is synchronized internally 50 * and its methods can be called from multiple threads, however once a connection is obtained 51 * it should only be used from one thread in accordance with the rules of DBClientBase. 52 */ 53 class ConnectionPool { 54 MONGO_DISALLOW_COPYING(ConnectionPool); 55 56 public: 57 /** 58 * Information about a connection in the pool. 59 */ 60 struct ConnectionInfo { ConnectionInfoConnectionInfo61 ConnectionInfo(DBClientConnection* theConn, Date_t date) 62 : conn(theConn), creationDate(date) {} 63 64 // A connection in the pool. 65 DBClientConnection* const conn; 66 67 // The date at which the connection was created. 68 const Date_t creationDate; 69 }; 70 71 typedef stdx::list<ConnectionInfo> ConnectionList; 72 typedef unordered_map<HostAndPort, ConnectionList> HostConnectionMap; 73 typedef std::map<HostAndPort, Date_t> HostLastUsedMap; 74 75 /** 76 * RAII class for connections from the pool. To use the connection pool, instantiate one of 77 * these with a pointer to the pool, the identity of the target node and the timeout for 78 * network operations, use it like a pointer to a connection, and then call done() on 79 * successful completion. Failure to call done() will lead to the connection being reaped 80 * when the holder goes out of scope. 81 */ 82 class ConnectionPtr { 83 MONGO_DISALLOW_COPYING(ConnectionPtr); 84 85 public: 86 /** 87 * Constructs a ConnectionPtr referring to a connection to "target" drawn from "pool", 88 * with the network timeout set to "timeout". 89 * 90 * Throws DBExceptions if the connection cannot be established. 91 */ 92 ConnectionPtr(ConnectionPool* pool, 93 const HostAndPort& target, 94 Date_t now, 95 Milliseconds timeout); 96 97 /** 98 * Destructor reaps the connection if it wasn't already returned to the pool by calling 99 * done(). 100 */ 101 ~ConnectionPtr(); 102 103 // We need to provide user defined move operations as we need to set the pool 104 // pointer to nullptr on the moved-from object. 105 ConnectionPtr(ConnectionPtr&&); 106 107 ConnectionPtr& operator=(ConnectionPtr&&); 108 109 /** 110 * Obtains the underlying connection which can be used for making calls to the server. 111 */ get()112 DBClientConnection* get() const { 113 return _connInfo->conn; 114 } 115 116 /** 117 * Releases the connection back to the pool from which it was drawn. 118 */ 119 void done(Date_t now); 120 121 private: 122 ConnectionPool* _pool; 123 ConnectionList::iterator _connInfo; 124 }; 125 126 /** 127 * Instantiates a new connection pool with the specified tags to be applied to the 128 * messaging ports that it opens. 129 * 130 * @param messagingPortTags tags to be applied to the messaging ports for each of the 131 * connections. If no tags are required, use 0. 132 */ 133 ConnectionPool(int messagingPortTags, std::unique_ptr<executor::NetworkConnectionHook> hook); 134 ConnectionPool(int messagingPortTags); 135 ~ConnectionPool(); 136 137 /** 138 * Acquires a connection to "target" with the given "timeout", or throws a DBException. 139 * Intended for use by ConnectionPtr. 140 */ 141 ConnectionList::iterator acquireConnection(const HostAndPort& target, 142 Date_t now, 143 Milliseconds timeout); 144 145 /** 146 * Releases a connection back into the pool. 147 * Intended for use by ConnectionPtr. 148 * Call this for connections that can safely be reused. 149 */ 150 void releaseConnection(ConnectionList::iterator iter, Date_t now); 151 152 /** 153 * Destroys a connection previously acquired from the pool. 154 * Intended for use by ConnectionPtr. 155 * Call this for connections that cannot be reused. 156 */ 157 void destroyConnection(ConnectionList::iterator); 158 159 /** 160 * Closes all connections currently in use, to ensure that the network threads 161 * terminate promptly during shutdown. 162 */ 163 void closeAllInUseConnections(); 164 165 /** 166 * Reaps all connections in the pool that are too old as of "now". 167 */ 168 void cleanUpOlderThan(Date_t now); 169 170 private: 171 /** 172 * Returns true if the given connection is young enough to keep in the pool. 173 */ 174 bool _shouldKeepConnection(Date_t now, const ConnectionInfo& connInfo) const; 175 176 /** 177 * Apply cleanup policy to any host(s) not active in the last kCleanupInterval milliseconds. 178 */ 179 void _cleanUpStaleHosts_inlock(Date_t now); 180 181 /** 182 * Reaps connections in "hostConns" that are too old or have been in the pool too long as of 183 * "now". Expects _mutex to be held. 184 */ 185 void _cleanUpOlderThan_inlock(Date_t now, ConnectionList* hostConns); 186 187 /** 188 * Destroys the connection associated with "iter" and removes "iter" fron connList. 189 */ 190 static void _destroyConnection_inlock(ConnectionList* connList, ConnectionList::iterator iter); 191 192 193 // Flags to apply to the opened connections 194 const int _messagingPortTags; 195 196 // Mutex guarding members of the connection pool 197 stdx::mutex _mutex; 198 199 // Map from HostAndPort to idle connections. 200 HostConnectionMap _connections; 201 202 // List of non-idle connections. 203 ConnectionList _inUseConnections; 204 205 // Map of HostAndPorts to when they were last used. 206 HostLastUsedMap _lastUsedHosts; 207 208 // Time representing when the connections were last cleaned. 209 Date_t _lastCleanUpTime; 210 211 // The connection hook for this pool. May be nullptr if there is no hook. 212 const std::unique_ptr<executor::NetworkConnectionHook> _hook; 213 }; 214 215 } // namespace mongo 216