summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2015-06-10 15:00:59 -0400
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2015-06-11 13:32:10 -0400
commit7c028e4f68c73d4e598b4836051678d307fa8adb (patch)
tree527229dc646ead5b45d4473ef0ff08429fd8231a
parent1b4c02b090b9c2fc56beca3295cdd7d5db48cf89 (diff)
downloadmongo-7c028e4f68c73d4e598b4836051678d307fa8adb.tar.gz
SERVER-18464 Implement ReplicaSetMonitorManager to replace statics
The ReplicaSetMonitorManager will be responsible for the lifetime of replica set monitors and will replaces the global static variables, which we currently use to track the replica set monitors. This change brings us closer to having a separate instance of the replica set monitors for MongoS.
-rw-r--r--src/mongo/client/SConscript88
-rw-r--r--src/mongo/client/connection_string.cpp13
-rw-r--r--src/mongo/client/connection_string.h16
-rw-r--r--src/mongo/client/connpool.cpp20
-rw-r--r--src/mongo/client/connpool.h1
-rw-r--r--src/mongo/client/global_conn_pool.cpp41
-rw-r--r--src/mongo/client/global_conn_pool.h40
-rw-r--r--src/mongo/client/replica_set_monitor.cpp95
-rw-r--r--src/mongo/client/replica_set_monitor.h5
-rw-r--r--src/mongo/client/replica_set_monitor_internal.h2
-rw-r--r--src/mongo/client/replica_set_monitor_manager.cpp112
-rw-r--r--src/mongo/client/replica_set_monitor_manager.h90
12 files changed, 382 insertions, 141 deletions
diff --git a/src/mongo/client/SConscript b/src/mongo/client/SConscript
index 3b41aaeb36b..8b6aefc8d34 100644
--- a/src/mongo/client/SConscript
+++ b/src/mongo/client/SConscript
@@ -1,6 +1,6 @@
# -*- mode: python -*-
-Import("env")
+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.
@@ -45,36 +45,42 @@ env.CppUnitTest(
],
LIBDEPS=[
'read_preference',
- ],
+ ]
)
-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=['connection_string',
- '$BUILD_DIR/mongo/bson/util/bson_extract',
- '$BUILD_DIR/mongo/crypto/scramauth',
- '$BUILD_DIR/mongo/db/auth/authcommon',
- '$BUILD_DIR/mongo/rpc/command_status',
- '$BUILD_DIR/mongo/rpc/rpc',
- '$BUILD_DIR/mongo/util/net/network',
- 'cyrus_sasl_client_session',
- 'read_preference',
- ])
+env.Library(
+ target='clientdriver',
+ source=[
+ 'connection_string_connect.cpp',
+ 'connpool.cpp',
+ 'dbclient.cpp',
+ 'dbclient_rs.cpp',
+ 'dbclientcursor.cpp',
+ 'global_conn_pool.cpp',
+ 'native_sasl_client_session.cpp',
+ 'replica_set_monitor.cpp',
+ 'replica_set_monitor_manager.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=[
+ 'connection_string',
+ '$BUILD_DIR/mongo/bson/util/bson_extract',
+ '$BUILD_DIR/mongo/crypto/scramauth',
+ '$BUILD_DIR/mongo/db/auth/authcommon',
+ '$BUILD_DIR/mongo/rpc/command_status',
+ '$BUILD_DIR/mongo/rpc/rpc',
+ '$BUILD_DIR/mongo/util/net/network',
+ 'cyrus_sasl_client_session',
+ 'read_preference',
+ ]
+)
env.Library(
target='connection_pool',
@@ -157,14 +163,14 @@ env.CppUnitTest(
]
)
-env.CppUnitTest("dbclient_rs_test",
- ["dbclient_rs_test.cpp"],
+env.CppUnitTest('dbclient_rs_test',
+ ['dbclient_rs_test.cpp'],
LIBDEPS=['clientdriver', '$BUILD_DIR/mongo/dbtests/mocklib'])
if env['MONGO_BUILD_SASL_CLIENT']:
saslLibs = ['sasl2']
if env.TargetOSIs('windows'):
- saslLibs.extend(["secur32"])
+ saslLibs.extend(['secur32'])
env.Library(
target='cyrus_sasl_client_session',
@@ -188,23 +194,23 @@ else:
)
env.CppUnitTest(
- target="scoped_db_conn_test",
+ target='scoped_db_conn_test',
source=[
- "scoped_db_conn_test.cpp",
+ 'scoped_db_conn_test.cpp',
],
LIBDEPS=[
- "$BUILD_DIR/mongo/db/coredb",
- "$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init",
- "$BUILD_DIR/mongo/util/net/message_server_port",
- "$BUILD_DIR/mongo/s/coreshard",
- "$BUILD_DIR/mongo/s/mongoscore",
- "$BUILD_DIR/mongo/util/ntservice_mock",
+ '$BUILD_DIR/mongo/db/coredb',
+ '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/util/net/message_server_port',
+ '$BUILD_DIR/mongo/s/coreshard',
+ '$BUILD_DIR/mongo/s/mongoscore',
+ '$BUILD_DIR/mongo/util/ntservice_mock',
],
NO_CRUTCH=True,
)
env.Library(
- target="parallel",
+ target='parallel',
source=[
'parallel.cpp',
],
diff --git a/src/mongo/client/connection_string.cpp b/src/mongo/client/connection_string.cpp
index 08c601b1e9f..ec10f39f1a6 100644
--- a/src/mongo/client/connection_string.cpp
+++ b/src/mongo/client/connection_string.cpp
@@ -42,6 +42,14 @@ namespace mongo {
_finishInit();
}
+ ConnectionString::ConnectionString(StringData setName, std::vector<HostAndPort> servers)
+ : _type(SET),
+ _servers(std::move(servers)),
+ _setName(setName.toString()) {
+
+ _finishInit();
+ }
+
ConnectionString::ConnectionString(ConnectionType type,
const std::string& s,
const std::string& setName) {
@@ -81,6 +89,11 @@ namespace mongo {
_finishInit();
}
+ ConnectionString ConnectionString::forReplicaSet(StringData setName,
+ std::vector<HostAndPort> servers) {
+ return ConnectionString(setName, std::move(servers));
+ }
+
void ConnectionString::_fillServers( std::string s ) {
//
diff --git a/src/mongo/client/connection_string.h b/src/mongo/client/connection_string.h
index 86798668546..3c5fe14a863 100644
--- a/src/mongo/client/connection_string.h
+++ b/src/mongo/client/connection_string.h
@@ -33,6 +33,7 @@
#include <string>
#include <vector>
+#include "mongo/base/string_data.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/net/hostandport.h"
@@ -64,6 +65,15 @@ namespace mongo {
ConnectionString() = default;
+ /**
+ * Constructs a connection string representing a replica set.
+ */
+ static ConnectionString forReplicaSet(StringData setName,
+ std::vector<HostAndPort> servers);
+
+ /**
+ * Creates a MASTER connection string with the specified server.
+ */
explicit ConnectionString(const HostAndPort& server);
ConnectionString(ConnectionType type, const std::string& s, const std::string& setName);
@@ -127,6 +137,12 @@ namespace mongo {
}
private:
+ /**
+ * Creates a SET connection string with the specified set name and servers.
+ */
+ ConnectionString(StringData setName, std::vector<HostAndPort> servers);
+
+
void _fillServers( std::string s );
void _finishInit();
diff --git a/src/mongo/client/connpool.cpp b/src/mongo/client/connpool.cpp
index 2357f930742..457f4c0de5a 100644
--- a/src/mongo/client/connpool.cpp
+++ b/src/mongo/client/connpool.cpp
@@ -35,6 +35,7 @@
#include "mongo/platform/basic.h"
#include "mongo/client/connpool.h"
+#include "mongo/client/global_conn_pool.h"
#include "mongo/client/replica_set_monitor.h"
#include "mongo/client/syncclusterconnection.h"
#include "mongo/util/exit.h"
@@ -175,8 +176,6 @@ namespace mongo {
// ------ DBConnectionPool ------
- DBConnectionPool pool;
-
const int PoolForHost::kPoolSizeUnlimited(-1);
DBConnectionPool::DBConnectionPool()
@@ -371,21 +370,8 @@ namespace mongo {
bb.done();
// Always report all replica sets being tracked
- set<string> replicaSets = ReplicaSetMonitor::getAllTrackedSets();
-
- BSONObjBuilder setBuilder( b.subobjStart( "replicaSets" ) );
- for ( set<string>::iterator i=replicaSets.begin(); i!=replicaSets.end(); ++i ) {
- string rs = *i;
- ReplicaSetMonitorPtr m = ReplicaSetMonitor::get( rs );
- if ( ! m ) {
- warning() << "no monitor for set: " << rs << endl;
- continue;
- }
-
- BSONObjBuilder temp( setBuilder.subobjStart( rs ) );
- m->appendInfo( temp );
- temp.done();
- }
+ BSONObjBuilder setBuilder(b.subobjStart("replicaSets"));
+ globalRSMonitorManager.report(&setBuilder);
setBuilder.done();
{
diff --git a/src/mongo/client/connpool.h b/src/mongo/client/connpool.h
index 534a03871cf..5c9735af4a9 100644
--- a/src/mongo/client/connpool.h
+++ b/src/mongo/client/connpool.h
@@ -375,7 +375,6 @@ namespace mongo {
const std::string _host;
DBClientBase *_conn;
const double _socketTimeout;
-
};
} // namespace mongo
diff --git a/src/mongo/client/global_conn_pool.cpp b/src/mongo/client/global_conn_pool.cpp
new file mode 100644
index 00000000000..86451da40ed
--- /dev/null
+++ b/src/mongo/client/global_conn_pool.cpp
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2015 MongoDB 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.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/client/global_conn_pool.h"
+
+#include "mongo/client/connpool.h"
+
+namespace mongo {
+
+ DBConnectionPool pool;
+
+ ReplicaSetMonitorManager globalRSMonitorManager;
+
+} // namespace mongo
diff --git a/src/mongo/client/global_conn_pool.h b/src/mongo/client/global_conn_pool.h
new file mode 100644
index 00000000000..68e72311758
--- /dev/null
+++ b/src/mongo/client/global_conn_pool.h
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2015 MongoDB 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 "mongo/client/replica_set_monitor_manager.h"
+
+namespace mongo {
+
+ /**
+ * Maintains the replica set monitors associated with the global connection pool.
+ */
+ extern ReplicaSetMonitorManager globalRSMonitorManager;
+
+} // namespace mongo
diff --git a/src/mongo/client/replica_set_monitor.cpp b/src/mongo/client/replica_set_monitor.cpp
index 98cfde7af7b..4d02a045f1f 100644
--- a/src/mongo/client/replica_set_monitor.cpp
+++ b/src/mongo/client/replica_set_monitor.cpp
@@ -38,6 +38,7 @@
#include "mongo/db/server_options.h"
#include "mongo/client/connpool.h"
+#include "mongo/client/global_conn_pool.h"
#include "mongo/client/replica_set_monitor_internal.h"
#include "mongo/util/background.h"
#include "mongo/util/concurrency/mutex.h" // for StaticObserver
@@ -53,6 +54,7 @@ namespace mongo {
using std::numeric_limits;
using std::set;
using std::string;
+ using std::vector;
namespace {
@@ -70,30 +72,8 @@ namespace {
const double socketTimeoutSecs = 5;
- /* Replica Set Monitor shared state:
- * If a program (such as one built with the C++ driver) exits (by either calling exit()
- * or by returning from main()), static objects will be destroyed in the reverse order
- * of their creation (within each translation unit (source code file)). This makes it
- * vital that the order be explicitly controlled within the source file so that destroyed
- * objects never reference objects that have been destroyed earlier.
- *
- * The order chosen below is intended to allow safe destruction in reverse order from
- * construction order:
- * setsLock -- mutex protecting sets, destroyed last
- * sets -- list (map) of ReplicaSetMonitors
- * replicaSetMonitorWatcher -- background job to check Replica Set members
- * staticObserver -- sentinel to detect process termination
- *
- * Related to:
- * SERVER-8891 -- Simple client fail with segmentation fault in mongoclient library
- *
- * Mutex locking order:
- * Don't lock setsLock while holding any SetState::mutex. It is however safe to grab a
- * SetState::mutex without holder setsLock, but then you can't grab setsLock until you
- * release the SetState::mutex.
- */
- mongo::mutex setsLock;
- StringMap<ReplicaSetMonitorPtr> sets;
+ // TODO: Move to ReplicaSetMonitorManager
+ ReplicaSetMonitor::ConfigChangeHook configChangeHook;
// global background job responsible for checking every X amount of time
class ReplicaSetMonitorWatcher : public BackgroundJob {
@@ -179,17 +159,13 @@ namespace {
void checkAllSets() {
// make a copy so we can quickly unlock setsLock
- StringMap<ReplicaSetMonitorPtr> setsCopy;
- {
- boost::lock_guard<boost::mutex> lk( setsLock );
- setsCopy = sets;
- }
-
- for (StringMap<ReplicaSetMonitorPtr>::const_iterator it = setsCopy.begin();
- it != setsCopy.end(); ++it) {
+ for (const string& setName : globalRSMonitorManager.getAllSetNames()) {
+ LOG(1) << "checking replica set: " << setName;
- LOG(1) << "checking replica set: " << it->first;
- ReplicaSetMonitorPtr m = it->second;
+ shared_ptr<ReplicaSetMonitor> m = globalRSMonitorManager.getMonitor(setName);
+ if (!m) {
+ continue;
+ }
m->startOrContinueRefresh().refreshAll();
@@ -355,47 +331,19 @@ namespace {
}
void ReplicaSetMonitor::createIfNeeded(const string& name, const set<HostAndPort>& servers) {
- LOG(3) << "ReplicaSetMonitor::createIfNeeded " << name;
- boost::lock_guard<boost::mutex> lk(setsLock);
- ReplicaSetMonitorPtr& m = sets[name];
- if (!m) {
- m = std::make_shared<ReplicaSetMonitor>(name, servers);
- }
+ globalRSMonitorManager.getOrCreateMonitor(
+ ConnectionString::forReplicaSet(name,
+ vector<HostAndPort>(servers.begin(), servers.end())));
replicaSetMonitorWatcher.safeGo();
}
shared_ptr<ReplicaSetMonitor> ReplicaSetMonitor::get(const std::string& name) {
- LOG(2) << "ReplicaSetMonitor::get " << name;
-
- boost::lock_guard<boost::mutex> lk( setsLock );
- StringMap<ReplicaSetMonitorPtr>::const_iterator i = sets.find( name );
- if ( i != sets.end() ) {
- return i->second;
- }
-
- return ReplicaSetMonitorPtr();
- }
-
- set<string> ReplicaSetMonitor::getAllTrackedSets() {
- set<string> activeSets;
- boost::lock_guard<boost::mutex> lk( setsLock );
- for (StringMap<ReplicaSetMonitorPtr>::const_iterator it = sets.begin();
- it != sets.end(); ++it)
- {
- activeSets.insert(it->first);
- }
- return activeSets;
+ return globalRSMonitorManager.getMonitor(name);
}
void ReplicaSetMonitor::remove(const string& name) {
- LOG(2) << "Removing ReplicaSetMonitor for " << name << " from replica set table";
-
- boost::lock_guard<boost::mutex> lk(setsLock);
- StringMap<ReplicaSetMonitorPtr>::const_iterator setIt = sets.find(name);
- if (setIt != sets.end()) {
- sets.erase(setIt);
- }
+ globalRSMonitorManager.removeMonitor(name);
// Kill all pooled ReplicaSetConnections for this set. They will not function correctly
// after we kill the ReplicaSetMonitor.
@@ -403,8 +351,8 @@ namespace {
}
void ReplicaSetMonitor::setConfigChangeHook(ConfigChangeHook hook) {
- massert(13610, "ConfigChangeHook already specified", !SetState::configChangeHook);
- SetState::configChangeHook = hook;
+ massert(13610, "ConfigChangeHook already specified", !configChangeHook);
+ configChangeHook = hook;
}
// TODO move to correct order with non-statics before pushing
@@ -447,8 +395,7 @@ namespace {
replicaSetMonitorWatcher.cancel();
replicaSetMonitorWatcher.stop();
replicaSetMonitorWatcher.wait();
- boost::lock_guard<boost::mutex> lock(setsLock);
- sets = StringMap<ReplicaSetMonitorPtr>();
+ globalRSMonitorManager.removeAllMonitors();
}
Refresher::Refresher(const SetStatePtr& setState)
@@ -690,10 +637,10 @@ namespace {
// and we want to record our changes
log() << "changing hosts to " << _set->getServerAddress() << " from " << oldAddr;
- if (SetState::configChangeHook) {
+ if (configChangeHook) {
// call from a separate thread to avoid blocking and holding lock while potentially
// going over the network
- boost::thread bg(SetState::configChangeHook, _set->name, _set->getServerAddress());
+ boost::thread bg(configChangeHook, _set->name, _set->getServerAddress());
bg.detach();
}
}
@@ -879,8 +826,6 @@ namespace {
}
}
- ReplicaSetMonitor::ConfigChangeHook SetState::configChangeHook;
-
SetState::SetState(StringData name, const std::set<HostAndPort>& seedNodes)
: name(name.toString())
, consecutiveFailedScans(0)
diff --git a/src/mongo/client/replica_set_monitor.h b/src/mongo/client/replica_set_monitor.h
index 599cc187dc9..b582923ce88 100644
--- a/src/mongo/client/replica_set_monitor.h
+++ b/src/mongo/client/replica_set_monitor.h
@@ -147,11 +147,6 @@ namespace mongo {
static std::shared_ptr<ReplicaSetMonitor> get(const std::string& name);
/**
- * Returns all the currently tracked replica set names.
- */
- static std::set<std::string> getAllTrackedSets();
-
- /**
* Removes the ReplicaSetMonitor for the given set name from _sets, which will delete it.
* If clearSeedCache is true, then the cached seed std::string for this Replica Set will be
* removed from _seedServers.
diff --git a/src/mongo/client/replica_set_monitor_internal.h b/src/mongo/client/replica_set_monitor_internal.h
index ba19ad1eb82..f840c2a1f65 100644
--- a/src/mongo/client/replica_set_monitor_internal.h
+++ b/src/mongo/client/replica_set_monitor_internal.h
@@ -162,8 +162,6 @@ namespace mongo {
*/
void checkInvariants() const;
- static ConfigChangeHook configChangeHook;
-
boost::mutex mutex; // must hold this to access any other member or method (except name).
// If Refresher::getNextStep returns WAIT, you should wait on the condition_variable,
diff --git a/src/mongo/client/replica_set_monitor_manager.cpp b/src/mongo/client/replica_set_monitor_manager.cpp
new file mode 100644
index 00000000000..ac1f6b8e6e7
--- /dev/null
+++ b/src/mongo/client/replica_set_monitor_manager.cpp
@@ -0,0 +1,112 @@
+/**
+ * Copyright (C) 2015 MongoDB 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.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/client/replica_set_monitor_manager.h"
+
+#include <boost/thread/lock_guard.hpp>
+
+#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/client/connection_string.h"
+#include "mongo/client/replica_set_monitor.h"
+#include "mongo/util/map_util.h"
+
+namespace mongo {
+
+ using std::shared_ptr;
+ using std::set;
+ using std::string;
+ using std::vector;
+
+ ReplicaSetMonitorManager::ReplicaSetMonitorManager() = default;
+
+ ReplicaSetMonitorManager::~ReplicaSetMonitorManager() = default;
+
+ shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorManager::getMonitor(StringData setName) {
+ boost::lock_guard<boost::mutex> lk(_mutex);
+
+ return mapFindWithDefault(_monitors, setName, shared_ptr<ReplicaSetMonitor>());
+ }
+
+ shared_ptr<ReplicaSetMonitor>
+ ReplicaSetMonitorManager::getOrCreateMonitor(const ConnectionString& connStr) {
+ invariant(connStr.type() == ConnectionString::SET);
+
+ boost::lock_guard<boost::mutex> lk(_mutex);
+
+ shared_ptr<ReplicaSetMonitor>& monitor = _monitors[connStr.getSetName()];
+ if (!monitor) {
+ const std::set<HostAndPort> servers(connStr.getServers().begin(),
+ connStr.getServers().end());
+
+ monitor = std::make_shared<ReplicaSetMonitor>(connStr.getSetName(), servers);
+ }
+
+ return monitor;
+ }
+
+ vector<string> ReplicaSetMonitorManager::getAllSetNames() {
+ vector<string> allNames;
+
+ boost::lock_guard<boost::mutex> lk(_mutex);
+
+ for (const auto& entry : _monitors) {
+ allNames.push_back(entry.first);
+ }
+
+ return allNames;
+ }
+
+ void ReplicaSetMonitorManager::removeMonitor(StringData setName) {
+ boost::lock_guard<boost::mutex> lk(_mutex);
+
+ ReplicaSetMonitorsMap::const_iterator it = _monitors.find(setName);
+ if (it != _monitors.end()) {
+ _monitors.erase(it);
+ }
+ }
+
+ void ReplicaSetMonitorManager::removeAllMonitors() {
+ boost::lock_guard<boost::mutex> lk(_mutex);
+
+ // Reset the StringMap, which will release all registered monitors
+ _monitors = ReplicaSetMonitorsMap();
+ }
+
+ void ReplicaSetMonitorManager::report(BSONObjBuilder* builder) {
+ boost::lock_guard<boost::mutex> lk(_mutex);
+
+ for (const auto& monitorPair : _monitors) {
+ BSONObjBuilder monitorInfo(builder->subobjStart(monitorPair.first));
+ monitorPair.second->appendInfo(monitorInfo);
+ monitorInfo.done();
+ }
+ }
+
+} // namespace mongo
diff --git a/src/mongo/client/replica_set_monitor_manager.h b/src/mongo/client/replica_set_monitor_manager.h
new file mode 100644
index 00000000000..fefaa065ad4
--- /dev/null
+++ b/src/mongo/client/replica_set_monitor_manager.h
@@ -0,0 +1,90 @@
+/**
+ * Copyright (C) 2015 MongoDB 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 <string>
+#include <vector>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/stdx/mutex.h"
+#include "mongo/util/string_map.h"
+
+namespace mongo {
+
+ class BSONObjBuilder;
+ class ConnectionString;
+ class ReplicaSetMonitor;
+
+ /**
+ * Manages the lifetime of a set of replica set monitors.
+ */
+ class ReplicaSetMonitorManager {
+ MONGO_DISALLOW_COPYING(ReplicaSetMonitorManager);
+ public:
+ ReplicaSetMonitorManager();
+ ~ReplicaSetMonitorManager();
+
+ /**
+ * Create or retrieve a monitor for a particular replica set. The getter method returns
+ * nullptr if there is no monitor registered for the particular replica set.
+ */
+ std::shared_ptr<ReplicaSetMonitor> getMonitor(StringData setName);
+ std::shared_ptr<ReplicaSetMonitor> getOrCreateMonitor(const ConnectionString& connStr);
+
+ /**
+ * Retrieves the names of all sets tracked by this manager.
+ */
+ std::vector<std::string> getAllSetNames();
+
+ /**
+ * Removes the specified replica set monitor from being tracked, if it exists. Otherwise
+ * does nothing. Once all shared_ptr references to that monitor are released, the monitor
+ * will be destroyed and will no longer be tracked.
+ */
+ void removeMonitor(StringData setName);
+
+ /**
+ * Removes and destroys all replica set monitors.
+ */
+ void removeAllMonitors();
+
+ /**
+ * Reports information about the replica sets tracked by us, for diagnostic purposes.
+ */
+ void report(BSONObjBuilder* builder);
+
+ private:
+ using ReplicaSetMonitorsMap = StringMap<std::shared_ptr<ReplicaSetMonitor>>;
+
+ // Protects access to the replica set monitors
+ stdx::mutex _mutex;
+ ReplicaSetMonitorsMap _monitors;
+ };
+
+} // namespace mongo