diff options
-rw-r--r-- | src/mongo/SConscript | 37 | ||||
-rw-r--r-- | src/mongo/client/SConscript | 38 | ||||
-rw-r--r-- | src/mongo/client/connection_string.cpp | 168 | ||||
-rw-r--r-- | src/mongo/client/connection_string.h | 196 | ||||
-rw-r--r-- | src/mongo/client/connection_string_connect.cpp | 111 | ||||
-rw-r--r-- | src/mongo/client/dbclient.cpp | 199 | ||||
-rw-r--r-- | src/mongo/client/dbclientinterface.h | 156 | ||||
-rw-r--r-- | src/mongo/db/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/s/SConscript | 6 | ||||
-rw-r--r-- | src/mongo/s/client/SConscript | 2 |
11 files changed, 527 insertions, 390 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript index 64ee90cf6e6..9b834999e90 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -22,6 +22,7 @@ env.InjectThirdPartyIncludePaths(libraries=['boost', 's2', 'pcre']) env.InjectMongoIncludePaths() env.SConscript(['base/SConscript', + 'client/SConscript', 'crypto/SConscript', 'crypto/tom/SConscript', 'db/auth/SConscript', @@ -331,32 +332,6 @@ env.Library( 'index_names', ]) -env.Library('clientdriver', [ - "client/connpool.cpp", - "client/dbclient.cpp", - "client/dbclient_rs.cpp", - "client/dbclientcursor.cpp", - 'client/native_sasl_client_session.cpp', - "client/replica_set_monitor.cpp", - 'client/sasl_client_authenticate.cpp', - "client/sasl_client_authenticate_impl.cpp", - 'client/sasl_client_conversation.cpp', - 'client/sasl_client_session.cpp', - 'client/sasl_plain_client_conversation.cpp', - 'client/sasl_scramsha1_client_conversation.cpp', - "client/syncclusterconnection.cpp", - "db/dbmessage.cpp" - ], - LIBDEPS=['$BUILD_DIR/mongo/db/auth/authcommon', - '$BUILD_DIR/mongo/crypto/scramauth', - '$BUILD_DIR/mongo/util/net/command_status', - 'network' - ]) - -env.CppUnitTest("replica_set_monitor_test", - ["client/replica_set_monitor_test.cpp"], - LIBDEPS=["clientdriver"]) - env.Library('lasterror', [ "db/lasterror.cpp", ], @@ -451,7 +426,7 @@ if env['MONGO_BUILD_SASL_CLIENT']: ['client/cyrus_sasl_client_session.cpp', 'client/sasl_sspi.cpp'], LIBDEPS = [ - 'clientdriver', + '$BUILD_DIR/mongo/client/clientdriver', 'foundation', 'signal_handlers_synchronous', ], @@ -485,7 +460,7 @@ env.Library("fail_point", env.Library('mongocommon', commonFiles, LIBDEPS=['bson', 'background_job', - 'clientdriver', + '$BUILD_DIR/mongo/client/clientdriver', 'fail_point', 'foundation', 'service_context', @@ -617,7 +592,7 @@ coredbEnv.Library("coredb", [ 'server_options', '$BUILD_DIR/mongo/util/cmdline_utils/cmdline_utils', '$BUILD_DIR/mongo/logger/parse_log_component_settings', - 'clientdriver', + '$BUILD_DIR/mongo/client/clientdriver', ]) env.Library('ntservice', ['util/ntservice.cpp'], @@ -949,7 +924,7 @@ env.CppUnitTest("mongoscore_test", "coredb"]) env.CppUnitTest("dbclient_rs_test", [ "client/dbclient_rs_test.cpp" ], - LIBDEPS=['clientdriver', 'mocklib']) + LIBDEPS=['$BUILD_DIR/mongo/client/clientdriver', 'mocklib']) env.CppUnitTest("scoped_db_conn_test", [ "client/scoped_db_conn_test.cpp" ], LIBDEPS=[ @@ -1257,7 +1232,7 @@ env.Library('mocklib', [ 'dbtests/mock/mock_remote_db_server.cpp', 'dbtests/mock/mock_replica_set.cpp' ], - LIBDEPS=['clientdriver', + LIBDEPS=['$BUILD_DIR/mongo/client/clientdriver', '$BUILD_DIR/mongo/db/repl/replica_set_messages']) test = env.Install( diff --git a/src/mongo/client/SConscript b/src/mongo/client/SConscript new file mode 100644 index 00000000000..c11fa686ebe --- /dev/null +++ b/src/mongo/client/SConscript @@ -0,0 +1,38 @@ +# -*- mode: python -*- + +Import("env") + +# Contains only the core ConnectionString functionality, *not* the ability to call connect() +# and return a DBClientBase* back. For that you need to link against the 'clientdriver' library. +env.Library('connectionstring', + ["connection_string.cpp"], + LIBDEPS=[]) + + +env.Library('clientdriver', [ + "connection_string_connect.cpp", + "connpool.cpp", + "dbclient.cpp", + "dbclient_rs.cpp", + "dbclientcursor.cpp", + 'native_sasl_client_session.cpp', + "replica_set_monitor.cpp", + 'sasl_client_authenticate.cpp', + "sasl_client_authenticate_impl.cpp", + 'sasl_client_conversation.cpp', + 'sasl_client_session.cpp', + 'sasl_plain_client_conversation.cpp', + 'sasl_scramsha1_client_conversation.cpp', + "syncclusterconnection.cpp", + "$BUILD_DIR/mongo/db/dbmessage.cpp" + ], + LIBDEPS=['connectionstring', + '$BUILD_DIR/mongo/db/auth/authcommon', + '$BUILD_DIR/mongo/crypto/scramauth', + '$BUILD_DIR/mongo/util/net/command_status', + '$BUILD_DIR/mongo/network' + ]) + +env.CppUnitTest("replica_set_monitor_test", + ["replica_set_monitor_test.cpp"], + LIBDEPS=["clientdriver"])
\ No newline at end of file diff --git a/src/mongo/client/connection_string.cpp b/src/mongo/client/connection_string.cpp new file mode 100644 index 00000000000..5e8d5a817cb --- /dev/null +++ b/src/mongo/client/connection_string.cpp @@ -0,0 +1,168 @@ +/* Copyright 2009 10gen Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kNetwork + +#include "mongo/platform/basic.h" + +#include "mongo/client/connection_string.h" + +#include "mongo/util/mongoutils/str.h" + +namespace mongo { + + void ConnectionString::_fillServers( std::string s ) { + + // + // Custom-handled servers/replica sets start with '$' + // According to RFC-1123/952, this will not overlap with valid hostnames + // (also disallows $replicaSetName hosts) + // + + if( s.find( '$' ) == 0 ) _type = CUSTOM; + + { + std::string::size_type idx = s.find( '/' ); + if ( idx != std::string::npos ) { + _setName = s.substr( 0 , idx ); + s = s.substr( idx + 1 ); + if( _type != CUSTOM ) _type = SET; + } + } + + std::string::size_type idx; + while ( ( idx = s.find( ',' ) ) != std::string::npos ) { + _servers.push_back(HostAndPort(s.substr(0, idx))); + s = s.substr( idx + 1 ); + } + _servers.push_back(HostAndPort(s)); + + } + + void ConnectionString::_finishInit() { + + // Needed here as well b/c the parsing logic isn't used in all constructors + // TODO: Refactor so that the parsing logic *is* used in all constructors + if ( _type == MASTER && _servers.size() > 0 ){ + if( _servers[0].host().find( '$' ) == 0 ){ + _type = CUSTOM; + } + } + + std::stringstream ss; + if ( _type == SET ) + ss << _setName << "/"; + for ( unsigned i=0; i<_servers.size(); i++ ) { + if ( i > 0 ) + ss << ","; + ss << _servers[i].toString(); + } + _string = ss.str(); + } + + bool ConnectionString::sameLogicalEndpoint( const ConnectionString& other ) const { + if ( _type != other._type ) + return false; + + switch ( _type ) { + case INVALID: + return true; + case MASTER: + return _servers[0] == other._servers[0]; + case PAIR: + if ( _servers[0] == other._servers[0] ) + return _servers[1] == other._servers[1]; + return + ( _servers[0] == other._servers[1] ) && + ( _servers[1] == other._servers[0] ); + case SET: + return _setName == other._setName; + case SYNC: + // The servers all have to be the same in each, but not in the same order. + if ( _servers.size() != other._servers.size() ) + return false; + for ( unsigned i = 0; i < _servers.size(); i++ ) { + bool found = false; + for ( unsigned j = 0; j < other._servers.size(); j++ ) { + if ( _servers[i] == other._servers[j] ) { + found = true; + break; + } + } + if ( ! found ) + return false; + } + return true; + case CUSTOM: + return _string == other._string; + } + verify( false ); + } + + ConnectionString ConnectionString::parse( const std::string& host , std::string& errmsg ) { + + std::string::size_type i = host.find( '/' ); + if ( i != std::string::npos && i != 0) { + // replica set + return ConnectionString( SET , host.substr( i + 1 ) , host.substr( 0 , i ) ); + } + + int numCommas = str::count( host , ',' ); + + if( numCommas == 0 ) + return ConnectionString( HostAndPort( host ) ); + + if ( numCommas == 1 ) + return ConnectionString( PAIR , host ); + + if ( numCommas == 2 ) + return ConnectionString( SYNC , host ); + + errmsg = (std::string)"invalid hostname [" + host + "]"; + return ConnectionString(); // INVALID + } + + std::string ConnectionString::typeToString( ConnectionType type ) { + switch ( type ) { + case INVALID: + return "invalid"; + case MASTER: + return "master"; + case PAIR: + return "pair"; + case SET: + return "set"; + case SYNC: + return "sync"; + case CUSTOM: + return "custom"; + } + verify(0); + return ""; + } + +} // namespace mongo diff --git a/src/mongo/client/connection_string.h b/src/mongo/client/connection_string.h new file mode 100644 index 00000000000..cf5ea8a3103 --- /dev/null +++ b/src/mongo/client/connection_string.h @@ -0,0 +1,196 @@ +/* Copyright 2009 10gen Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#pragma once + +#include <boost/thread/lock_guard.hpp> +#include <boost/thread/mutex.hpp> +#include <string> +#include <vector> + +#include "mongo/util/assert_util.h" +#include "mongo/util/net/hostandport.h" + +namespace mongo { + + class DBClientBase; + + /** + * ConnectionString handles parsing different ways to connect to mongo and determining method + * samples: + * server + * server:port + * foo/server:port,server:port SET + * server,server,server SYNC + * Warning - you usually don't want "SYNC", it's used + * for some special things such as sharding config servers. + * See syncclusterconnection.h for more info. + * + * tyipcal use + * std::string errmsg, + * ConnectionString cs = ConnectionString::parse( url , errmsg ); + * if ( ! cs.isValid() ) throw "bad: " + errmsg; + * DBClientBase * conn = cs.connect( errmsg ); + */ + class ConnectionString { + public: + + enum ConnectionType { INVALID , MASTER , PAIR , SET , SYNC, CUSTOM }; + + ConnectionString() { + _type = INVALID; + } + + // Note: This should only be used for direct connections to a single server. For replica + // set and SyncClusterConnections, use ConnectionString::parse. + ConnectionString( const HostAndPort& server ) { + _type = MASTER; + _servers.push_back( server ); + _finishInit(); + } + + ConnectionString( ConnectionType type , const std::string& s , const std::string& setName = "" ) { + _type = type; + _setName = setName; + _fillServers( s ); + + switch ( _type ) { + case MASTER: + verify( _servers.size() == 1 ); + break; + case SET: + verify( _setName.size() ); + verify( _servers.size() >= 1 ); // 1 is ok since we can derive + break; + case PAIR: + verify( _servers.size() == 2 ); + break; + default: + verify( _servers.size() > 0 ); + } + + _finishInit(); + } + + ConnectionString( const std::string& s , ConnectionType favoredMultipleType ) { + _type = INVALID; + + _fillServers( s ); + if ( _type != INVALID ) { + // set already + } + else if ( _servers.size() == 1 ) { + _type = MASTER; + } + else { + _type = favoredMultipleType; + verify( _type == SET || _type == SYNC ); + } + _finishInit(); + } + + bool isValid() const { return _type != INVALID; } + + std::string toString() const { return _string; } + + DBClientBase* connect( std::string& errmsg, double socketTimeout = 0 ) const; + + std::string getSetName() const { return _setName; } + + const std::vector<HostAndPort>& getServers() const { return _servers; } + + ConnectionType type() const { return _type; } + + /** + * This returns true if this and other point to the same logical entity. + * For single nodes, thats the same address. + * For replica sets, thats just the same replica set name. + * For pair (deprecated) or sync cluster connections, that's the same hosts in any ordering. + */ + bool sameLogicalEndpoint( const ConnectionString& other ) const; + + static ConnectionString parse( const std::string& url , std::string& errmsg ); + + static std::string typeToString( ConnectionType type ); + + // + // Allow overriding the default connection behavior + // This is needed for some tests, which otherwise would fail because they are unable to contact + // the correct servers. + // + + class ConnectionHook { + public: + virtual ~ConnectionHook(){} + + // Returns an alternative connection object for a string + virtual DBClientBase* connect( const ConnectionString& c, + std::string& errmsg, + double socketTimeout ) = 0; + }; + + static void setConnectionHook( ConnectionHook* hook ){ + boost::lock_guard<boost::mutex> lk( _connectHookMutex ); + _connectHook = hook; + } + + static ConnectionHook* getConnectionHook() { + boost::lock_guard<boost::mutex> lk( _connectHookMutex ); + return _connectHook; + } + + // Allows ConnectionStrings to be stored more easily in sets/maps + bool operator<(const ConnectionString& other) const { + return _string < other._string; + } + + // + // FOR TESTING ONLY - useful to be able to directly mock a connection std::string without + // including the entire client library. + // + + static ConnectionString mock( const HostAndPort& server ) { + ConnectionString connStr; + connStr._servers.push_back( server ); + connStr._string = server.toString(); + return connStr; + } + + private: + + void _fillServers( std::string s ); + void _finishInit(); + + ConnectionType _type; + std::vector<HostAndPort> _servers; + std::string _string; + std::string _setName; + + static boost::mutex _connectHookMutex; + static ConnectionHook* _connectHook; + }; +} // namespace mongo diff --git a/src/mongo/client/connection_string_connect.cpp b/src/mongo/client/connection_string_connect.cpp new file mode 100644 index 00000000000..303f4ef9fa0 --- /dev/null +++ b/src/mongo/client/connection_string_connect.cpp @@ -0,0 +1,111 @@ +/* Copyright 2009 10gen Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kNetwork + +#include "mongo/platform/basic.h" + +#include "mongo/client/connection_string.h" + +#include <list> + +#include "mongo/client/dbclientinterface.h" +#include "mongo/client/dbclient_rs.h" +#include "mongo/client/syncclusterconnection.h" +#include "mongo/util/assert_util.h" +#include "mongo/util/log.h" + +namespace mongo { + + boost::mutex ConnectionString::_connectHookMutex; + ConnectionString::ConnectionHook* ConnectionString::_connectHook = NULL; + + DBClientBase* ConnectionString::connect( std::string& errmsg, double socketTimeout ) const { + + switch ( _type ) { + case MASTER: { + DBClientConnection * c = new DBClientConnection(true); + c->setSoTimeout( socketTimeout ); + LOG(1) << "creating new connection to:" << _servers[0]; + if ( ! c->connect( _servers[0] , errmsg ) ) { + delete c; + return 0; + } + LOG(1) << "connected connection!"; + return c; + } + + case PAIR: + case SET: { + DBClientReplicaSet * set = new DBClientReplicaSet( _setName , _servers , socketTimeout ); + if( ! set->connect() ) { + delete set; + errmsg = "connect failed to replica set "; + errmsg += toString(); + return 0; + } + return set; + } + + case SYNC: { + // TODO , don't copy + std::list<HostAndPort> l; + for ( unsigned i=0; i<_servers.size(); i++ ) + l.push_back( _servers[i] ); + SyncClusterConnection* c = new SyncClusterConnection( l, socketTimeout ); + return c; + } + + case CUSTOM: { + + // Lock in case other things are modifying this at the same time + boost::lock_guard<boost::mutex> lk( _connectHookMutex ); + + // Allow the replacement of connections with other connections - useful for testing. + + uassert( 16335, "custom connection to " + this->toString() + + " specified with no connection hook", _connectHook ); + + // Double-checked lock, since this will never be active during normal operation + DBClientBase* replacementConn = _connectHook->connect( *this, errmsg, socketTimeout ); + + log() << "replacing connection to " << this->toString() << " with " + << ( replacementConn ? replacementConn->getServerAddress() : "(empty)" ); + + return replacementConn; + } + + case INVALID: + throw UserException( 13421 , "trying to connect to invalid ConnectionString" ); + break; + } + + verify( 0 ); + return 0; + } + +} // namepspace mongo diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp index e03938a5e94..bf13114d385 100644 --- a/src/mongo/client/dbclient.cpp +++ b/src/mongo/client/dbclient.cpp @@ -37,7 +37,6 @@ #include "mongo/client/dbclient_rs.h" #include "mongo/client/dbclientcursor.h" #include "mongo/client/sasl_client_authenticate.h" -#include "mongo/client/syncclusterconnection.h" #include "mongo/config.h" #include "mongo/db/auth/internal_user_auth.h" #include "mongo/db/jsobj.h" @@ -45,6 +44,7 @@ #include "mongo/db/namespace_string.h" #include "mongo/s/stale_exception.h" // for RecvStaleConfigException #include "mongo/util/assert_util.h" +#include "mongo/util/concurrency/mutex.h" #include "mongo/util/debug_util.h" #include "mongo/util/log.h" #include "mongo/util/net/get_status_from_command_result.h" @@ -66,203 +66,6 @@ namespace mongo { const char* const saslCommandUserSourceFieldName = "userSource"; - void ConnectionString::_fillServers( string s ) { - - // - // Custom-handled servers/replica sets start with '$' - // According to RFC-1123/952, this will not overlap with valid hostnames - // (also disallows $replicaSetName hosts) - // - - if( s.find( '$' ) == 0 ) _type = CUSTOM; - - { - string::size_type idx = s.find( '/' ); - if ( idx != string::npos ) { - _setName = s.substr( 0 , idx ); - s = s.substr( idx + 1 ); - if( _type != CUSTOM ) _type = SET; - } - } - - string::size_type idx; - while ( ( idx = s.find( ',' ) ) != string::npos ) { - _servers.push_back(HostAndPort(s.substr(0, idx))); - s = s.substr( idx + 1 ); - } - _servers.push_back(HostAndPort(s)); - - } - - void ConnectionString::_finishInit() { - - // Needed here as well b/c the parsing logic isn't used in all constructors - // TODO: Refactor so that the parsing logic *is* used in all constructors - if ( _type == MASTER && _servers.size() > 0 ){ - if( _servers[0].host().find( '$' ) == 0 ){ - _type = CUSTOM; - } - } - - stringstream ss; - if ( _type == SET ) - ss << _setName << "/"; - for ( unsigned i=0; i<_servers.size(); i++ ) { - if ( i > 0 ) - ss << ","; - ss << _servers[i].toString(); - } - _string = ss.str(); - } - - mutex ConnectionString::_connectHookMutex; - ConnectionString::ConnectionHook* ConnectionString::_connectHook = NULL; - - DBClientBase* ConnectionString::connect( string& errmsg, double socketTimeout ) const { - - switch ( _type ) { - case MASTER: { - DBClientConnection * c = new DBClientConnection(true); - c->setSoTimeout( socketTimeout ); - LOG(1) << "creating new connection to:" << _servers[0] << endl; - if ( ! c->connect( _servers[0] , errmsg ) ) { - delete c; - return 0; - } - LOG(1) << "connected connection!" << endl; - return c; - } - - case PAIR: - case SET: { - DBClientReplicaSet * set = new DBClientReplicaSet( _setName , _servers , socketTimeout ); - if( ! set->connect() ) { - delete set; - errmsg = "connect failed to replica set "; - errmsg += toString(); - return 0; - } - return set; - } - - case SYNC: { - // TODO , don't copy - list<HostAndPort> l; - for ( unsigned i=0; i<_servers.size(); i++ ) - l.push_back( _servers[i] ); - SyncClusterConnection* c = new SyncClusterConnection( l, socketTimeout ); - return c; - } - - case CUSTOM: { - - // Lock in case other things are modifying this at the same time - boost::lock_guard<boost::mutex> lk( _connectHookMutex ); - - // Allow the replacement of connections with other connections - useful for testing. - - uassert( 16335, "custom connection to " + this->toString() + - " specified with no connection hook", _connectHook ); - - // Double-checked lock, since this will never be active during normal operation - DBClientBase* replacementConn = _connectHook->connect( *this, errmsg, socketTimeout ); - - log() << "replacing connection to " << this->toString() << " with " - << ( replacementConn ? replacementConn->getServerAddress() : "(empty)" ) << endl; - - return replacementConn; - } - - case INVALID: - throw UserException( 13421 , "trying to connect to invalid ConnectionString" ); - break; - } - - verify( 0 ); - return 0; - } - - bool ConnectionString::sameLogicalEndpoint( const ConnectionString& other ) const { - if ( _type != other._type ) - return false; - - switch ( _type ) { - case INVALID: - return true; - case MASTER: - return _servers[0] == other._servers[0]; - case PAIR: - if ( _servers[0] == other._servers[0] ) - return _servers[1] == other._servers[1]; - return - ( _servers[0] == other._servers[1] ) && - ( _servers[1] == other._servers[0] ); - case SET: - return _setName == other._setName; - case SYNC: - // The servers all have to be the same in each, but not in the same order. - if ( _servers.size() != other._servers.size() ) - return false; - for ( unsigned i = 0; i < _servers.size(); i++ ) { - bool found = false; - for ( unsigned j = 0; j < other._servers.size(); j++ ) { - if ( _servers[i] == other._servers[j] ) { - found = true; - break; - } - } - if ( ! found ) - return false; - } - return true; - case CUSTOM: - return _string == other._string; - } - verify( false ); - } - - ConnectionString ConnectionString::parse( const string& host , string& errmsg ) { - - string::size_type i = host.find( '/' ); - if ( i != string::npos && i != 0) { - // replica set - return ConnectionString( SET , host.substr( i + 1 ) , host.substr( 0 , i ) ); - } - - int numCommas = str::count( host , ',' ); - - if( numCommas == 0 ) - return ConnectionString( HostAndPort( host ) ); - - if ( numCommas == 1 ) - return ConnectionString( PAIR , host ); - - if ( numCommas == 2 ) - return ConnectionString( SYNC , host ); - - errmsg = (string)"invalid hostname [" + host + "]"; - return ConnectionString(); // INVALID - } - - string ConnectionString::typeToString( ConnectionType type ) { - switch ( type ) { - case INVALID: - return "invalid"; - case MASTER: - return "master"; - case PAIR: - return "pair"; - case SET: - return "set"; - case SYNC: - return "sync"; - case CUSTOM: - return "custom"; - } - verify(0); - return ""; - } - const BSONField<BSONObj> Query::ReadPrefField("$readPreference"); const BSONField<string> Query::ReadPrefModeField("mode"); const BSONField<BSONArray> Query::ReadPrefTagsField("tags"); diff --git a/src/mongo/client/dbclientinterface.h b/src/mongo/client/dbclientinterface.h index d53166107ae..05f62affef8 100644 --- a/src/mongo/client/dbclientinterface.h +++ b/src/mongo/client/dbclientinterface.h @@ -37,6 +37,7 @@ #include <boost/scoped_ptr.hpp> #include "mongo/base/string_data.h" +#include "mongo/client/connection_string.h" #include "mongo/config.h" #include "mongo/db/jsobj.h" #include "mongo/logger/log_severity.h" @@ -200,161 +201,6 @@ namespace mongo { class DBClientConnection; /** - * ConnectionString handles parsing different ways to connect to mongo and determining method - * samples: - * server - * server:port - * foo/server:port,server:port SET - * server,server,server SYNC - * Warning - you usually don't want "SYNC", it's used - * for some special things such as sharding config servers. - * See syncclusterconnection.h for more info. - * - * tyipcal use - * std::string errmsg, - * ConnectionString cs = ConnectionString::parse( url , errmsg ); - * if ( ! cs.isValid() ) throw "bad: " + errmsg; - * DBClientBase * conn = cs.connect( errmsg ); - */ - class ConnectionString { - public: - - enum ConnectionType { INVALID , MASTER , PAIR , SET , SYNC, CUSTOM }; - - ConnectionString() { - _type = INVALID; - } - - // Note: This should only be used for direct connections to a single server. For replica - // set and SyncClusterConnections, use ConnectionString::parse. - ConnectionString( const HostAndPort& server ) { - _type = MASTER; - _servers.push_back( server ); - _finishInit(); - } - - ConnectionString( ConnectionType type , const std::string& s , const std::string& setName = "" ) { - _type = type; - _setName = setName; - _fillServers( s ); - - switch ( _type ) { - case MASTER: - verify( _servers.size() == 1 ); - break; - case SET: - verify( _setName.size() ); - verify( _servers.size() >= 1 ); // 1 is ok since we can derive - break; - case PAIR: - verify( _servers.size() == 2 ); - break; - default: - verify( _servers.size() > 0 ); - } - - _finishInit(); - } - - ConnectionString( const std::string& s , ConnectionType favoredMultipleType ) { - _type = INVALID; - - _fillServers( s ); - if ( _type != INVALID ) { - // set already - } - else if ( _servers.size() == 1 ) { - _type = MASTER; - } - else { - _type = favoredMultipleType; - verify( _type == SET || _type == SYNC ); - } - _finishInit(); - } - - bool isValid() const { return _type != INVALID; } - - std::string toString() const { return _string; } - - DBClientBase* connect( std::string& errmsg, double socketTimeout = 0 ) const; - - std::string getSetName() const { return _setName; } - - const std::vector<HostAndPort>& getServers() const { return _servers; } - - ConnectionType type() const { return _type; } - - /** - * This returns true if this and other point to the same logical entity. - * For single nodes, thats the same address. - * For replica sets, thats just the same replica set name. - * For pair (deprecated) or sync cluster connections, that's the same hosts in any ordering. - */ - bool sameLogicalEndpoint( const ConnectionString& other ) const; - - static ConnectionString parse( const std::string& url , std::string& errmsg ); - - static std::string typeToString( ConnectionType type ); - - // - // Allow overriding the default connection behavior - // This is needed for some tests, which otherwise would fail because they are unable to contact - // the correct servers. - // - - class ConnectionHook { - public: - virtual ~ConnectionHook(){} - - // Returns an alternative connection object for a string - virtual DBClientBase* connect( const ConnectionString& c, - std::string& errmsg, - double socketTimeout ) = 0; - }; - - static void setConnectionHook( ConnectionHook* hook ){ - boost::lock_guard<boost::mutex> lk( _connectHookMutex ); - _connectHook = hook; - } - - static ConnectionHook* getConnectionHook() { - boost::lock_guard<boost::mutex> lk( _connectHookMutex ); - return _connectHook; - } - - // Allows ConnectionStrings to be stored more easily in sets/maps - bool operator<(const ConnectionString& other) const { - return _string < other._string; - } - - // - // FOR TESTING ONLY - useful to be able to directly mock a connection std::string without - // including the entire client library. - // - - static ConnectionString mock( const HostAndPort& server ) { - ConnectionString connStr; - connStr._servers.push_back( server ); - connStr._string = server.toString(); - return connStr; - } - - private: - - void _fillServers( std::string s ); - void _finishInit(); - - ConnectionType _type; - std::vector<HostAndPort> _servers; - std::string _string; - std::string _setName; - - static boost::mutex _connectHookMutex; - static ConnectionHook* _connectHook; - }; - - /** * controls how much a clients cares about writes * default is NORMAL */ diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index c0bc6f93a08..722b707e3f2 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -74,7 +74,7 @@ env.CppUnitTest( ], LIBDEPS=[ "common", - "$BUILD_DIR/mongo/clientdriver", + "$BUILD_DIR/mongo/client/clientdriver", ], ) env.CppUnitTest('record_id_test', 'record_id_test.cpp', LIBDEPS=[]) diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index fcef1a96ef7..ef65b51d788 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -24,7 +24,7 @@ env.Library( LIBDEPS=[ '$BUILD_DIR/mongo/base/base', '$BUILD_DIR/mongo/bson', - '$BUILD_DIR/mongo/clientdriver', + '$BUILD_DIR/mongo/client/clientdriver', '$BUILD_DIR/mongo/coredb', '$BUILD_DIR/mongo/db/common', '$BUILD_DIR/mongo/db/query/getmore_request', diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index 43cc7f41696..51f2f8f83f6 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -73,7 +73,7 @@ env.Library('metadata', 'base', '$BUILD_DIR/mongo/bson', '$BUILD_DIR/mongo/base/base', - '$BUILD_DIR/mongo/clientdriver', + '$BUILD_DIR/mongo/client/clientdriver', '$BUILD_DIR/mongo/range_arithmetic', '$BUILD_DIR/mongo/s/catalog/catalog_types' ]) @@ -152,7 +152,7 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/bson', - '$BUILD_DIR/mongo/clientdriver', + '$BUILD_DIR/mongo/client/clientdriver', 'batch_write_types', '$BUILD_DIR/mongo/synchronization' ], @@ -197,7 +197,7 @@ env.CppUnitTest( 'cluster_write_op_conversion', '$BUILD_DIR/mongo/db/common', '$BUILD_DIR/mongo/server_options', # DbMessage needs server options - "$BUILD_DIR/mongo/clientdriver", + "$BUILD_DIR/mongo/client/clientdriver", ] ) diff --git a/src/mongo/s/client/SConscript b/src/mongo/s/client/SConscript index edd1c282ef9..f4226615280 100644 --- a/src/mongo/s/client/SConscript +++ b/src/mongo/s/client/SConscript @@ -10,7 +10,7 @@ env.Library( 'shard_connection.cpp', ], LIBDEPS=[ - '$BUILD_DIR/mongo/clientdriver', + '$BUILD_DIR/mongo/client/clientdriver', ] ) |