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