MongoDB  1.8.5
connpool.h
Go to the documentation of this file.
00001 
00003 /*    Copyright 2009 10gen Inc.
00004  *
00005  *    Licensed under the Apache License, Version 2.0 (the "License");
00006  *    you may not use this file except in compliance with the License.
00007  *    You may obtain a copy of the License at
00008  *
00009  *    http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  *    Unless required by applicable law or agreed to in writing, software
00012  *    distributed under the License is distributed on an "AS IS" BASIS,
00013  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  *    See the License for the specific language governing permissions and
00015  *    limitations under the License.
00016  */
00017 
00018 #pragma once
00019 
00020 #include <stack>
00021 #include "dbclient.h"
00022 #include "redef_macros.h"
00023 
00024 namespace mongo {
00025 
00026     class Shard;
00027 
00032     class PoolForHost {
00033     public:
00034         PoolForHost()
00035             : _created(0) {}
00036 
00037         PoolForHost( const PoolForHost& other ) {
00038             assert(other._pool.size() == 0);
00039             _created = other._created;
00040             assert( _created == 0 );
00041         }
00042 
00043         ~PoolForHost();
00044 
00045         int numAvailable() const { return (int)_pool.size(); }
00046 
00047         void createdOne( DBClientBase * base);
00048         long long numCreated() const { return _created; }
00049 
00050         ConnectionString::ConnectionType type() const { assert(_created); return _type; }
00051 
00055         DBClientBase * get();
00056 
00057         void done( DBClientBase * c );
00058 
00059         void flush();
00060 
00061         static void setMaxPerHost( unsigned max ) { _maxPerHost = max; }
00062         static unsigned getMaxPerHost() { return _maxPerHost; }
00063     private:
00064 
00065         struct StoredConnection {
00066             StoredConnection( DBClientBase * c );
00067 
00068             bool ok( time_t now );
00069 
00070             DBClientBase* conn;
00071             time_t when;
00072         };
00073 
00074         std::stack<StoredConnection> _pool;
00075         long long _created;
00076         ConnectionString::ConnectionType _type;
00077 
00078         static unsigned _maxPerHost;
00079     };
00080 
00081     class DBConnectionHook {
00082     public:
00083         virtual ~DBConnectionHook() {}
00084         virtual void onCreate( DBClientBase * conn ) {}
00085         virtual void onHandedOut( DBClientBase * conn ) {}
00086     };
00087 
00103     class DBConnectionPool {
00104         
00105     public:
00106 
00108         struct serverNameCompare {
00109             bool operator()( const string& a , const string& b ) const;
00110         };
00111 
00112     private:
00113 
00114         mongo::mutex _mutex;
00115         typedef map<string,PoolForHost,serverNameCompare> PoolMap; // servername -> pool
00116         PoolMap _pools;
00117         list<DBConnectionHook*> _hooks;
00118         string _name;
00119 
00120         DBClientBase* _get( const string& ident );
00121 
00122         DBClientBase* _finishCreate( const string& ident , DBClientBase* conn );
00123 
00124     public:
00125         DBConnectionPool() : _mutex("DBConnectionPool") , _name( "dbconnectionpool" ) { }
00126         ~DBConnectionPool();
00127 
00129         void setName( const string& name ) { _name = name; }
00130 
00131         void onCreate( DBClientBase * conn );
00132         void onHandedOut( DBClientBase * conn );
00133 
00134         void flush();
00135 
00136         DBClientBase *get(const string& host);
00137         DBClientBase *get(const ConnectionString& host);
00138 
00139         void release(const string& host, DBClientBase *c) {
00140             if ( c->isFailed() ) {
00141                 delete c;
00142                 return;
00143             }
00144             scoped_lock L(_mutex);
00145             _pools[host].done(c);
00146         }
00147         void addHook( DBConnectionHook * hook );
00148         void appendInfo( BSONObjBuilder& b );
00149     };
00150 
00151     extern DBConnectionPool pool;
00152 
00153     class AScopedConnection : boost::noncopyable {
00154     public:
00155         AScopedConnection() { _numConnections++; }
00156         virtual ~AScopedConnection() { _numConnections--; }
00157         virtual DBClientBase* get() = 0;
00158         virtual void done() = 0;
00159         virtual string getHost() const = 0;
00160 
00164         static int getNumConnections() { return _numConnections; }
00165 
00166     private:
00167         static AtomicUInt _numConnections;
00168     };
00169 
00174     class ScopedDbConnection : public AScopedConnection {
00175     public:
00179         explicit ScopedDbConnection(const string& host) : _host(host), _conn( pool.get(host) ) {}
00180 
00181         ScopedDbConnection() : _host( "" ) , _conn(0) {}
00182 
00183         /* @param conn - bind to an existing connection */
00184         ScopedDbConnection(const string& host, DBClientBase* conn ) : _host( host ) , _conn( conn ) {}
00185 
00187         explicit ScopedDbConnection(const ConnectionString& url ) : _host(url.toString()), _conn( pool.get(url) ) {}
00188 
00190         explicit ScopedDbConnection(const Shard& shard );
00191         explicit ScopedDbConnection(const Shard* shard );
00192 
00193         ~ScopedDbConnection();
00194 
00196         DBClientBase* operator->() {
00197             uassert( 11004 ,  "connection was returned to the pool already" , _conn );
00198             return _conn;
00199         }
00200 
00202         DBClientBase& conn() {
00203             uassert( 11005 ,  "connection was returned to the pool already" , _conn );
00204             return *_conn;
00205         }
00206 
00208         DBClientBase* get() {
00209             uassert( 13102 ,  "connection was returned to the pool already" , _conn );
00210             return _conn;
00211         }
00212 
00213         string getHost() const { return _host; }
00214 
00218         void kill() {
00219             delete _conn;
00220             _conn = 0;
00221         }
00222 
00229         void done() {
00230             if ( ! _conn )
00231                 return;
00232 
00233             /* we could do this, but instead of assume one is using autoreconnect mode on the connection
00234             if ( _conn->isFailed() )
00235                 kill();
00236             else
00237             */
00238             pool.release(_host, _conn);
00239             _conn = 0;
00240         }
00241 
00242         ScopedDbConnection * steal();
00243 
00244     private:
00245         const string _host;
00246         DBClientBase *_conn;
00247 
00248     };
00249 
00250 } // namespace mongo
00251 
00252 #include "undef_macros.h"