diff options
-rw-r--r-- | src/mongo/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/client/dbclient_rs_test.cpp | 67 | ||||
-rw-r--r-- | src/mongo/client/replica_set_monitor_test.cpp | 1 | ||||
-rw-r--r-- | src/mongo/dbtests/mock/mock_replica_set.cpp | 74 | ||||
-rw-r--r-- | src/mongo/dbtests/mock/mock_replica_set.h | 10 | ||||
-rw-r--r-- | src/mongo/dbtests/mock_replica_set_test.cpp | 49 | ||||
-rw-r--r-- | src/mongo/dbtests/replica_set_monitor_test.cpp | 74 | ||||
-rw-r--r-- | src/mongo/dbtests/repltests.cpp | 22 |
8 files changed, 195 insertions, 105 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript index 1b9481ad3e1..431ae487e5f 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -1097,7 +1097,8 @@ env.Library('mocklib', [ 'dbtests/mock/mock_remote_db_server.cpp', 'dbtests/mock/mock_replica_set.cpp' ], - LIBDEPS=['clientdriver']) + LIBDEPS=['clientdriver', + '$BUILD_DIR/mongo/db/repl/replica_set_messages']) test = env.Install( '#/', diff --git a/src/mongo/client/dbclient_rs_test.cpp b/src/mongo/client/dbclient_rs_test.cpp index cd9ccc55948..6082d899a31 100644 --- a/src/mongo/client/dbclient_rs_test.cpp +++ b/src/mongo/client/dbclient_rs_test.cpp @@ -433,14 +433,21 @@ namespace { mongo::MockConnRegistry::get()->getConnStrHook()); { - mongo::MockReplicaSet::ReplConfigMap config = _replSet->getReplConfig(); + mongo::repl::ReplicaSetConfig oldConfig = _replSet->getReplConfig(); + mongo::BSONObjBuilder newConfigBuilder; + newConfigBuilder.append("_id", oldConfig.getReplSetName()); + newConfigBuilder.append("version", oldConfig.getConfigVersion()); + + mongo::BSONArrayBuilder membersBuilder(newConfigBuilder.subarrayStart("members")); { const string host(_replSet->getPrimary()); - map<string, string>& tag = config[host].tags; - tag.clear(); - tag["dc"] = "ny"; - tag["p"] = "1"; + const mongo::repl::MemberConfig* member = + oldConfig.findMemberByHostAndPort(HostAndPort(host)); + membersBuilder.append(BSON("_id" << member->getId() << + "host" << host << + "tags" << BSON("dc" << "ny" << + "p" << "1"))); _replSet->getNode(host)->insert(IdentityNS, BSON(HostField(host))); } @@ -449,46 +456,58 @@ namespace { { const string host(*secIter); - map<string, string>& tag = config[host].tags; - tag.clear(); - tag["dc"] = "sf"; - tag["s"] = "1"; - tag["group"] = "1"; + const mongo::repl::MemberConfig* member = + oldConfig.findMemberByHostAndPort(HostAndPort(host)); + membersBuilder.append(BSON("_id" << member->getId() << + "host" << host << + "tags" << BSON("dc" << "sf" << + "s" << "1" << + "group" << "1"))); _replSet->getNode(host)->insert(IdentityNS, BSON(HostField(host))); } { ++secIter; const string host(*secIter); - map<string, string>& tag = config[host].tags; - tag.clear(); - tag["dc"] = "ma"; - tag["s"] = "2"; - tag["group"] = "1"; + const mongo::repl::MemberConfig* member = + oldConfig.findMemberByHostAndPort(HostAndPort(host)); + membersBuilder.append(BSON("_id" << member->getId() << + "host" << host << + "tags" << BSON("dc" << "ma" << + "s" << "2" << + "group" << "1"))); _replSet->getNode(host)->insert(IdentityNS, BSON(HostField(host))); } { ++secIter; const string host(*secIter); - map<string, string>& tag = config[host].tags; - tag.clear(); - tag["dc"] = "eu"; - tag["s"] = "3"; + const mongo::repl::MemberConfig* member = + oldConfig.findMemberByHostAndPort(HostAndPort(host)); + membersBuilder.append(BSON("_id" << member->getId() << + "host" << host << + "tags" << BSON("dc" << "eu" << + "s" << "3"))); _replSet->getNode(host)->insert(IdentityNS, BSON(HostField(host))); } { ++secIter; const string host(*secIter); - map<string, string>& tag = config[host].tags; - tag.clear(); - tag["dc"] = "jp"; - tag["s"] = "4"; + const mongo::repl::MemberConfig* member = + oldConfig.findMemberByHostAndPort(HostAndPort(host)); + membersBuilder.append(BSON("_id" << member->getId() << + "host" << host << + "tags" << BSON("dc" << "jp" << + "s" << "4"))); _replSet->getNode(host)->insert(IdentityNS, BSON(HostField(host))); } - _replSet->setConfig(config); + membersBuilder.done(); + mongo::repl::ReplicaSetConfig newConfig; + fassert(28569, newConfig.initialize(newConfigBuilder.done())); + fassert(28568, newConfig.validate()); + _replSet->setConfig(newConfig); } } diff --git a/src/mongo/client/replica_set_monitor_test.cpp b/src/mongo/client/replica_set_monitor_test.cpp index 559b4f3d443..9316baefad9 100644 --- a/src/mongo/client/replica_set_monitor_test.cpp +++ b/src/mongo/client/replica_set_monitor_test.cpp @@ -32,7 +32,6 @@ #include "mongo/client/replica_set_monitor.h" #include "mongo/client/replica_set_monitor_internal.h" #include "mongo/dbtests/mock/mock_conn_registry.h" -#include "mongo/dbtests/mock/mock_replica_set.h" #include "mongo/unittest/unittest.h" using namespace mongo; diff --git a/src/mongo/dbtests/mock/mock_replica_set.cpp b/src/mongo/dbtests/mock/mock_replica_set.cpp index d1bc8c1edbe..851d69e8a7e 100644 --- a/src/mongo/dbtests/mock/mock_replica_set.cpp +++ b/src/mongo/dbtests/mock/mock_replica_set.cpp @@ -39,8 +39,11 @@ using namespace mongo::repl; namespace mongo { MockReplicaSet::MockReplicaSet(const string& setName, size_t nodes): _setName(setName) { - ReplConfigMap replConfig; + BSONObjBuilder configBuilder; + configBuilder.append("_id", setName); + configBuilder.append("version", 1); + BSONArrayBuilder membersBuilder(configBuilder.subarrayStart("members")); for (size_t n = 0; n < nodes; n++) { std::stringstream str; str << "$" << setName << n << ":27017"; @@ -55,11 +58,13 @@ namespace mongo { MockConnRegistry::get()->addServer(mockServer); - ReplSetConfig::MemberCfg config; - config.h = HostAndPort(hostName); - replConfig.insert(std::make_pair(hostName, config)); + membersBuilder.append(BSON("_id" << static_cast<int>(n) << "host" << hostName)); } + membersBuilder.done(); + ReplicaSetConfig replConfig; + fassert(28566, replConfig.initialize(configBuilder.obj())); + fassert(28573, replConfig.validate()); setConfig(replConfig); } @@ -109,11 +114,10 @@ namespace mongo { } void MockReplicaSet::setPrimary(const string& hostAndPort) { - ReplConfigMap::const_iterator iter = _replConfig.find(hostAndPort); - fassert(16578, iter != _replConfig.end()); + const MemberConfig* config = _replConfig.findMemberByHostAndPort(HostAndPort(hostAndPort)); + fassert(16578, config); - const ReplSetConfig::MemberCfg& config = iter->second; - fassert(16579, !config.hidden && config.priority > 0 && !config.arbiterOnly); + fassert(16579, !config->isHidden() && config->getPriority() > 0 && !config->isArbiter()); _primaryHost = hostAndPort; @@ -124,10 +128,10 @@ namespace mongo { vector<string> MockReplicaSet::getSecondaries() const { vector<string> secondaries; - for (ReplConfigMap::const_iterator iter = _replConfig.begin(); - iter != _replConfig.end(); ++iter) { - if (iter->first != _primaryHost) { - secondaries.push_back(iter->first); + for (ReplicaSetConfig::MemberIterator member = _replConfig.membersBegin(); + member != _replConfig.membersEnd(); ++member) { + if (member->getHostAndPort() != HostAndPort(_primaryHost)) { + secondaries.push_back(member->getHostAndPort().toString()); } } @@ -138,11 +142,11 @@ namespace mongo { return mapFindWithDefault(_nodeMap, hostAndPort, static_cast<MockRemoteDBServer*>(NULL)); } - MockReplicaSet::ReplConfigMap MockReplicaSet::getReplConfig() const { + repl::ReplicaSetConfig MockReplicaSet::getReplConfig() const { return _replConfig; } - void MockReplicaSet::setConfig(const MockReplicaSet::ReplConfigMap& newConfig) { + void MockReplicaSet::setConfig(const repl::ReplicaSetConfig& newConfig) { _replConfig = newConfig; mockIsMasterCmd(); mockReplSetGetStatusCmd(); @@ -166,7 +170,6 @@ namespace mongo { } void MockReplicaSet::mockIsMasterCmd() { - // Copied from ReplSetImpl::_fillIsMaster for (ReplNodeMap::iterator nodeIter = _nodeMap.begin(); nodeIter != _nodeMap.end(); ++nodeIter) { const string& hostAndPort = nodeIter->first; @@ -174,8 +177,9 @@ namespace mongo { BSONObjBuilder builder; builder.append("setName", _setName); - ReplConfigMap::const_iterator configIter = _replConfig.find(hostAndPort); - if (configIter == _replConfig.end()) { + const MemberConfig* member = _replConfig.findMemberByHostAndPort( + HostAndPort(hostAndPort)); + if (!member) { builder.append("ismaster", false); builder.append("secondary", false); @@ -203,34 +207,38 @@ namespace mongo { builder.append("primary", getPrimary()); - const ReplSetConfig::MemberCfg& replConfig = configIter->second; - if (replConfig.arbiterOnly) { + if (member->isArbiter()) { builder.append("arbiterOnly", true); } - if (replConfig.priority == 0 && !replConfig.arbiterOnly) { + if (member->getPriority() == 0 && !member->isArbiter()) { builder.append("passive", true); } - if (replConfig.slaveDelay) { - builder.append("slaveDelay", replConfig.slaveDelay); + if (member->getSlaveDelay().total_seconds()) { + builder.append("slaveDelay", member->getSlaveDelay().total_seconds()); } - if (replConfig.hidden) { + if (member->isHidden()) { builder.append("hidden", true); } - if (!replConfig.buildIndexes) { + if (!member->shouldBuildIndexes()) { builder.append("buildIndexes", false); } - if(!replConfig.tags.empty()) { + const ReplicaSetTagConfig tagConfig = _replConfig.getTagConfig(); + if (member->hasTags(tagConfig)) { BSONObjBuilder tagBuilder; - for(map<string, string>::const_iterator tagIter = replConfig.tags.begin(); - tagIter != replConfig.tags.end(); tagIter++) { - tagBuilder.append(tagIter->first, tagIter->second); + for (MemberConfig::TagIterator tag = member->tagsBegin(); + tag != member->tagsEnd(); ++tag) { + std::string tagKey = tagConfig.getTagKey(*tag); + if (tagKey[0] == '$') { + // Filter out internal tags + continue; + } + tagBuilder.append(tagKey, tagConfig.getTagValue(*tag)); } - builder.append("tags", tagBuilder.done()); } } @@ -243,7 +251,7 @@ namespace mongo { } int MockReplicaSet::getState(const std::string& hostAndPort) const { - if (_replConfig.count(hostAndPort) < 1) { + if (!_replConfig.findMemberByHostAndPort(HostAndPort(hostAndPort))) { return static_cast<int>(MemberState::RS_REMOVED); } else if (hostAndPort == getPrimary()) { @@ -275,9 +283,9 @@ namespace mongo { hostsField.push_back(selfStatBuilder.obj()); } - for (ReplConfigMap::const_iterator replConfIter = _replConfig.begin(); - replConfIter != _replConfig.end(); ++replConfIter) { - MockRemoteDBServer* hostNode = getNode(replConfIter->first); + for (ReplicaSetConfig::MemberIterator member = _replConfig.membersBegin(); + member != _replConfig.membersEnd(); ++member) { + MockRemoteDBServer* hostNode = getNode(member->getHostAndPort().toString()); if (hostNode == node) { continue; diff --git a/src/mongo/dbtests/mock/mock_replica_set.h b/src/mongo/dbtests/mock/mock_replica_set.h index 92f238cd1b7..9c394c97648 100644 --- a/src/mongo/dbtests/mock/mock_replica_set.h +++ b/src/mongo/dbtests/mock/mock_replica_set.h @@ -28,7 +28,8 @@ #pragma once #include "mongo/dbtests/mock/mock_remote_db_server.h" -#include "mongo/db/repl/rs_config.h" +#include "mongo/db/repl/member_config.h" +#include "mongo/db/repl/replica_set_config.h" #include <string> #include <map> @@ -49,7 +50,6 @@ namespace mongo { */ class MockReplicaSet { public: - typedef std::map<std::string, repl::ReplSetConfig::MemberCfg> ReplConfigMap; /** * Creates a mock replica set and automatically mocks the isMaster @@ -69,7 +69,7 @@ namespace mongo { std::string getSetName() const; std::string getConnectionString() const; std::vector<HostAndPort> getHosts() const; - ReplConfigMap getReplConfig() const; + repl::ReplicaSetConfig getReplConfig() const; std::string getPrimary() const; std::vector<std::string> getSecondaries() const; @@ -81,7 +81,7 @@ namespace mongo { * Note: does not automatically select a new primary. Can be done manually by * calling setPrimary. */ - void setConfig(const ReplConfigMap& newConfig); + void setConfig(const repl::ReplicaSetConfig& newConfig); void setPrimary(const std::string& hostAndPort); @@ -134,7 +134,7 @@ namespace mongo { const std::string _setName; ReplNodeMap _nodeMap; - ReplConfigMap _replConfig; + repl::ReplicaSetConfig _replConfig; std::string _primaryHost; }; diff --git a/src/mongo/dbtests/mock_replica_set_test.cpp b/src/mongo/dbtests/mock_replica_set_test.cpp index 40aa16f600b..6cda455fd3d 100644 --- a/src/mongo/dbtests/mock_replica_set_test.cpp +++ b/src/mongo/dbtests/mock_replica_set_test.cpp @@ -32,12 +32,16 @@ #include <set> #include <string> +using mongo::BSONArrayBuilder; using mongo::BSONElement; using mongo::BSONObj; +using mongo::BSONObjBuilder; using mongo::BSONObjIterator; using mongo::ConnectionString; +using mongo::HostAndPort; using mongo::MockRemoteDBServer; using mongo::MockReplicaSet; +using mongo::repl::ReplicaSetConfig; using std::set; using std::string; @@ -255,13 +259,45 @@ namespace mongo_test { ASSERT(expectedMembers == memberList); } +namespace { + /** + * Takes a ReplicaSetConfig and a node to remove and returns a new config with equivalent + * members minus the one specified to be removed. NOTE: Does not copy over properties of the + * members other than their id and host. + */ + ReplicaSetConfig _getConfigWithMemberRemoved( + const ReplicaSetConfig& oldConfig, const HostAndPort& toRemove) { + BSONObjBuilder newConfigBuilder; + newConfigBuilder.append("_id", oldConfig.getReplSetName()); + newConfigBuilder.append("version", oldConfig.getConfigVersion()); + + BSONArrayBuilder membersBuilder(newConfigBuilder.subarrayStart("members")); + for (ReplicaSetConfig::MemberIterator member = oldConfig.membersBegin(); + member != oldConfig.membersEnd(); ++member) { + if (member->getHostAndPort() == toRemove) { + continue; + } + + membersBuilder.append(BSON("_id" << member->getId() << + "host" << member->getHostAndPort().toString())); + } + + membersBuilder.done(); + ReplicaSetConfig newConfig; + ASSERT_OK(newConfig.initialize(newConfigBuilder.obj())); + ASSERT_OK(newConfig.validate()); + return newConfig; + } +} // namespace + TEST(MockReplicaSetTest, IsMasterReconfigNodeRemoved) { MockReplicaSet replSet("n", 3); - MockReplicaSet::ReplConfigMap config = replSet.getReplConfig(); + ReplicaSetConfig oldConfig = replSet.getReplConfig(); const string hostToRemove("$n1:27017"); - config.erase(hostToRemove); - replSet.setConfig(config); + ReplicaSetConfig newConfig = _getConfigWithMemberRemoved(oldConfig, + HostAndPort(hostToRemove)); + replSet.setConfig(newConfig); { // Check isMaster for node still in set @@ -309,10 +345,11 @@ namespace mongo_test { TEST(MockReplicaSetTest, replSetGetStatusReconfigNodeRemoved) { MockReplicaSet replSet("n", 3); - MockReplicaSet::ReplConfigMap config = replSet.getReplConfig(); + ReplicaSetConfig oldConfig = replSet.getReplConfig(); const string hostToRemove("$n1:27017"); - config.erase(hostToRemove); - replSet.setConfig(config); + ReplicaSetConfig newConfig = _getConfigWithMemberRemoved(oldConfig, + HostAndPort(hostToRemove)); + replSet.setConfig(newConfig); { // Check replSetGetStatus for node still in set diff --git a/src/mongo/dbtests/replica_set_monitor_test.cpp b/src/mongo/dbtests/replica_set_monitor_test.cpp index e1692732e33..f77a46856bf 100644 --- a/src/mongo/dbtests/replica_set_monitor_test.cpp +++ b/src/mongo/dbtests/replica_set_monitor_test.cpp @@ -54,6 +54,7 @@ using mongo::HostAndPort; using mongo::MockReplicaSet; using mongo::ReadPreference; using mongo::ReadPreferenceSetting; +using mongo::repl::ReplicaSetConfig; using mongo::ReplicaSetMonitor; using mongo::ReplicaSetMonitorPtr; using mongo::ScopedDbConnection; @@ -1429,6 +1430,37 @@ namespace mongo_test { monitor->startOrContinueRefresh().refreshAll(); } +namespace { + /** + * Takes a ReplicaSetConfig and a node to remove and returns a new config with equivalent + * members minus the one specified to be removed. NOTE: Does not copy over properties of the + * members other than their id and host. + */ + ReplicaSetConfig _getConfigWithMemberRemoved( + const ReplicaSetConfig& oldConfig, const HostAndPort& toRemove) { + BSONObjBuilder newConfigBuilder; + newConfigBuilder.append("_id", oldConfig.getReplSetName()); + newConfigBuilder.append("version", oldConfig.getConfigVersion()); + + BSONArrayBuilder membersBuilder(newConfigBuilder.subarrayStart("members")); + for (ReplicaSetConfig::MemberIterator member = oldConfig.membersBegin(); + member != oldConfig.membersEnd(); ++member) { + if (member->getHostAndPort() == toRemove) { + continue; + } + + membersBuilder.append(BSON("_id" << member->getId() << + "host" << member->getHostAndPort().toString())); + } + + membersBuilder.done(); + ReplicaSetConfig newConfig; + ASSERT_OK(newConfig.initialize(newConfigBuilder.obj())); + ASSERT_OK(newConfig.validate()); + return newConfig; + } +} // namespace + // Stress test case for a node that is previously a primary being removed from the set. // This test goes through configurations with different positions for the primary node // in the host list returned from the isMaster command. The test here is to make sure @@ -1445,11 +1477,10 @@ namespace mongo_test { seedList.insert(HostAndPort(replSet.getPrimary())); ReplicaSetMonitor::createIfNeeded(replSetName, seedList); - const MockReplicaSet::ReplConfigMap origConfig = replSet.getReplConfig(); + const ReplicaSetConfig& origConfig = replSet.getReplConfig(); mongo::ReplicaSetMonitorPtr replMonitor = ReplicaSetMonitor::get(replSetName); for (size_t idxToRemove = 0; idxToRemove < NODE_COUNT; idxToRemove++) { - MockReplicaSet::ReplConfigMap newConfig = origConfig; replSet.setConfig(origConfig); // Make sure the monitor sees the change @@ -1470,9 +1501,10 @@ namespace mongo_test { // Make sure the monitor sees the new primary replMonitor->startOrContinueRefresh().refreshAll(); - newConfig.erase(hostToRemove); + mongo::repl::ReplicaSetConfig newConfig = _getConfigWithMemberRemoved( + origConfig, HostAndPort(hostToRemove)); replSet.setConfig(newConfig); - replSet.setPrimary(newConfig.begin()->first); + replSet.setPrimary(newConfig.getMemberAt(0).getHostAndPort().toString()); // Force refresh -> should not crash replMonitor->startOrContinueRefresh().refreshAll(); } @@ -1494,25 +1526,39 @@ namespace mongo_test { ConnectionString::setConnectionHook( mongo::MockConnRegistry::get()->getConnStrHook()); - mongo::MockReplicaSet::ReplConfigMap config = _replSet->getReplConfig(); + mongo::repl::ReplicaSetConfig oldConfig = _replSet->getReplConfig(); + + mongo::BSONObjBuilder newConfigBuilder; + newConfigBuilder.append("_id", oldConfig.getReplSetName()); + newConfigBuilder.append("version", oldConfig.getConfigVersion()); + + mongo::BSONArrayBuilder membersBuilder(newConfigBuilder.subarrayStart("members")); { const string host(_replSet->getPrimary()); - map<string, string>& tag = config[host].tags; - tag.clear(); - tag["dc"] = "ny"; - tag["num"] = "1"; + const mongo::repl::MemberConfig* member = + oldConfig.findMemberByHostAndPort(HostAndPort(host)); + membersBuilder.append(BSON("_id" << member->getId() << + "host" << host << + "tags" << BSON("dc" << "ny" << + "num" << "1"))); } { const string host(_replSet->getSecondaries().front()); - map<string, string>& tag = config[host].tags; - tag.clear(); - tag["dc"] = "ny"; - tag["num"] = "2"; + const mongo::repl::MemberConfig* member = + oldConfig.findMemberByHostAndPort(HostAndPort(host)); + membersBuilder.append(BSON("_id" << member->getId() << + "host" << host << + "tags" << BSON("dc" << "ny" << + "num" << "2"))); } - _replSet->setConfig(config); + membersBuilder.done(); + mongo::repl::ReplicaSetConfig newConfig; + fassert(28572, newConfig.initialize(newConfigBuilder.done())); + fassert(28571, newConfig.validate()); + _replSet->setConfig(newConfig); } diff --git a/src/mongo/dbtests/repltests.cpp b/src/mongo/dbtests/repltests.cpp index 826729595a7..25e677ee3bd 100644 --- a/src/mongo/dbtests/repltests.cpp +++ b/src/mongo/dbtests/repltests.cpp @@ -42,7 +42,7 @@ #include "mongo/db/repl/oplog.h" #include "mongo/db/repl/repl_coordinator_global.h" #include "mongo/db/repl/repl_coordinator_mock.h" -#include "mongo/db/repl/rs.h" +#include "mongo/db/repl/sync.h" #include "mongo/db/ops/update.h" #include "mongo/db/catalog/collection.h" #include "mongo/db/operation_context_impl.h" @@ -1389,25 +1389,6 @@ namespace ReplTests { } }; - /** Check ReplSetConfig::MemberCfg equality */ - class ReplSetMemberCfgEquality : public Base { - public: - void run() { - ReplSetConfig::MemberCfg m1, m2; - verify(m1 == m2); - m1.tags["x"] = "foo"; - verify(m1 != m2); - m2.tags["y"] = "bar"; - verify(m1 != m2); - m1.tags["y"] = "bar"; - verify(m1 != m2); - m2.tags["x"] = "foo"; - verify(m1 == m2); - m1.tags.clear(); - verify(m1 != m2); - } - }; - class SyncTest : public Sync { public: bool returnEmpty; @@ -1517,7 +1498,6 @@ namespace ReplTests { add< DeleteOpIsIdBased >(); add< DatabaseIgnorerBasic >(); add< DatabaseIgnorerUpdate >(); - add< ReplSetMemberCfgEquality >(); add< ShouldRetry >(); } }; |