summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/SConscript37
-rw-r--r--src/mongo/client/SConscript38
-rw-r--r--src/mongo/client/connection_string.cpp168
-rw-r--r--src/mongo/client/connection_string.h196
-rw-r--r--src/mongo/client/connection_string_connect.cpp111
-rw-r--r--src/mongo/client/dbclient.cpp199
-rw-r--r--src/mongo/client/dbclientinterface.h156
-rw-r--r--src/mongo/db/SConscript2
-rw-r--r--src/mongo/db/repl/SConscript2
-rw-r--r--src/mongo/s/SConscript6
-rw-r--r--src/mongo/s/client/SConscript2
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',
]
)