diff options
-rw-r--r-- | src/mongo/db/repl/repl_coordinator.h | 5 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_external_state_mock.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_external_state_mock.h | 6 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_hybrid.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_hybrid.h | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_impl.cpp | 29 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_impl.h | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_impl_test.cpp | 75 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_legacy.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_legacy.h | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_mock.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_mock.h | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_test_fixture.h | 5 | ||||
-rw-r--r-- | src/mongo/db/write_concern.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/write_concern.h | 3 |
15 files changed, 145 insertions, 25 deletions
diff --git a/src/mongo/db/repl/repl_coordinator.h b/src/mongo/db/repl/repl_coordinator.h index 77e57f4f66d..b4d91704039 100644 --- a/src/mongo/db/repl/repl_coordinator.h +++ b/src/mongo/db/repl/repl_coordinator.h @@ -442,10 +442,9 @@ namespace repl { virtual bool buildsIndexes() = 0; /** - * Returns a vector containing BSONObjs describing each member that has applied operation - * at OpTime 'op'. + * Returns a vector of members that have applied the operation with OpTime 'op'. */ - virtual std::vector<BSONObj> getHostsWrittenTo(const OpTime& op) = 0; + virtual std::vector<HostAndPort> getHostsWrittenTo(const OpTime& op) = 0; /** * Returns a BSONObj containing a representation of the current default write concern. diff --git a/src/mongo/db/repl/repl_coordinator_external_state_mock.cpp b/src/mongo/db/repl/repl_coordinator_external_state_mock.cpp index 7a1d6486d7f..370960e7b65 100644 --- a/src/mongo/db/repl/repl_coordinator_external_state_mock.cpp +++ b/src/mongo/db/repl/repl_coordinator_external_state_mock.cpp @@ -68,7 +68,12 @@ namespace repl { HostAndPort ReplicationCoordinatorExternalStateMock::getClientHostAndPort( const OperationContext* txn) { - return HostAndPort(); + return _clientHostAndPort; + } + + void ReplicationCoordinatorExternalStateMock::setClientHostAndPort( + const HostAndPort& clientHostAndPort) { + _clientHostAndPort = clientHostAndPort; } StatusWith<BSONObj> ReplicationCoordinatorExternalStateMock::loadLocalConfigDocument( diff --git a/src/mongo/db/repl/repl_coordinator_external_state_mock.h b/src/mongo/db/repl/repl_coordinator_external_state_mock.h index 950a870efc3..5519745d917 100644 --- a/src/mongo/db/repl/repl_coordinator_external_state_mock.h +++ b/src/mongo/db/repl/repl_coordinator_external_state_mock.h @@ -67,10 +67,16 @@ namespace repl { */ void setLocalConfigDocument(const StatusWith<BSONObj>& localConfigDocument); + /** + * Sets the return value for subsequent calls to getClientHostAndPort(). + */ + void setClientHostAndPort(const HostAndPort& clientHostAndPort); + private: StatusWith<BSONObj> _localRsConfigDocument; std::vector<HostAndPort> _selfHosts; bool _connectionsClosed; + HostAndPort _clientHostAndPort; }; } // namespace repl diff --git a/src/mongo/db/repl/repl_coordinator_hybrid.cpp b/src/mongo/db/repl/repl_coordinator_hybrid.cpp index 2c5cddbf9dc..f8c9f1241d1 100644 --- a/src/mongo/db/repl/repl_coordinator_hybrid.cpp +++ b/src/mongo/db/repl/repl_coordinator_hybrid.cpp @@ -376,10 +376,9 @@ namespace repl { return legacyResponse; } - vector<BSONObj> HybridReplicationCoordinator::getHostsWrittenTo(const OpTime& op) { - vector<BSONObj> legacyResponse = _legacy.getHostsWrittenTo(op); - vector<BSONObj> implResponse = _impl.getHostsWrittenTo(op); - return legacyResponse; + vector<HostAndPort> HybridReplicationCoordinator::getHostsWrittenTo(const OpTime& op) { + vector<HostAndPort> implResponse = _impl.getHostsWrittenTo(op); + return implResponse; } Status HybridReplicationCoordinator::checkIfWriteConcernCanBeSatisfied( diff --git a/src/mongo/db/repl/repl_coordinator_hybrid.h b/src/mongo/db/repl/repl_coordinator_hybrid.h index cede8b8c9fb..6fddbc99ba8 100644 --- a/src/mongo/db/repl/repl_coordinator_hybrid.h +++ b/src/mongo/db/repl/repl_coordinator_hybrid.h @@ -153,7 +153,7 @@ namespace repl { virtual bool buildsIndexes(); - virtual std::vector<BSONObj> getHostsWrittenTo(const OpTime& op); + virtual std::vector<HostAndPort> getHostsWrittenTo(const OpTime& op); virtual BSONObj getGetLastErrorDefault(); diff --git a/src/mongo/db/repl/repl_coordinator_impl.cpp b/src/mongo/db/repl/repl_coordinator_impl.cpp index 8d12a1d5c2c..bc0ff5fedd5 100644 --- a/src/mongo/db/repl/repl_coordinator_impl.cpp +++ b/src/mongo/db/repl/repl_coordinator_impl.cpp @@ -1215,9 +1215,32 @@ namespace { return self.shouldBuildIndexes(); } - std::vector<BSONObj> ReplicationCoordinatorImpl::getHostsWrittenTo(const OpTime& op) { - // TODO - return std::vector<BSONObj>(); + std::vector<HostAndPort> ReplicationCoordinatorImpl::getHostsWrittenTo(const OpTime& op) { + std::vector<HostAndPort> hosts; + boost::lock_guard<boost::mutex> lk(_mutex); + for (SlaveInfoMap::const_iterator it = _slaveInfoMap.begin(); + it != _slaveInfoMap.end(); ++it) { + const SlaveInfo& slaveInfo = it->second; + if (slaveInfo.opTime < op) { + continue; + } + if (_getReplicationMode_inlock() == modeReplSet) { + const MemberConfig* memberConfig = _rsConfig.findMemberByID(slaveInfo.memberID); + if (!memberConfig) { + // Node might have been removed in a reconfig + continue; + } + hosts.push_back(memberConfig->getHostAndPort()); + } + else { + if (it->first == _getMyRID_inlock()) { + // Master-slave doesn't know the HostAndPort for itself at this point. + continue; + } + hosts.push_back(slaveInfo.hostAndPort); + } + } + return hosts; } Status ReplicationCoordinatorImpl::checkIfWriteConcernCanBeSatisfied( diff --git a/src/mongo/db/repl/repl_coordinator_impl.h b/src/mongo/db/repl/repl_coordinator_impl.h index 7ecb7022f62..50a25d13f84 100644 --- a/src/mongo/db/repl/repl_coordinator_impl.h +++ b/src/mongo/db/repl/repl_coordinator_impl.h @@ -187,7 +187,7 @@ namespace repl { virtual bool buildsIndexes(); - virtual std::vector<BSONObj> getHostsWrittenTo(const OpTime& op); + virtual std::vector<HostAndPort> getHostsWrittenTo(const OpTime& op); virtual BSONObj getGetLastErrorDefault(); diff --git a/src/mongo/db/repl/repl_coordinator_impl_test.cpp b/src/mongo/db/repl/repl_coordinator_impl_test.cpp index 63a0661213c..2c63a066766 100644 --- a/src/mongo/db/repl/repl_coordinator_impl_test.cpp +++ b/src/mongo/db/repl/repl_coordinator_impl_test.cpp @@ -1054,7 +1054,80 @@ namespace { ASSERT_OK(getReplCoord()->setMaintenanceMode(&txn, false)); } - // TODO(spencer): Unit test replSetFreeze + TEST_F(ReplCoordTest, GetHostsWrittenToReplSet) { + HostAndPort myHost("node1:12345"); + HostAndPort client1Host("node2:12345"); + HostAndPort client2Host("node3:12345") ; + assertStartSuccess( + BSON("_id" << "mySet" << + "version" << 2 << + "members" << BSON_ARRAY(BSON("_id" << 0 << "host" << myHost.toString()) << + BSON("_id" << 1 << "host" << client1Host.toString()) << + BSON("_id" << 2 << "host" << client2Host.toString()))), + HostAndPort("node1", 12345)); + OperationContextNoop txn; + + OID myRID = getReplCoord()->getMyRID(); + OID client1 = OID::gen(); + OID client2 = OID::gen(); + OpTime time1(1, 1); + OpTime time2(1, 2); + + HandshakeArgs handshake1; + ASSERT_OK(handshake1.initialize(BSON("handshake" << client1 << "member" << 1))); + ASSERT_OK(getReplCoord()->processHandshake(&txn, handshake1)); + HandshakeArgs handshake2; + ASSERT_OK(handshake2.initialize(BSON("handshake" << client2 << "member" << 2))); + ASSERT_OK(getReplCoord()->processHandshake(&txn, handshake2)); + + ASSERT_OK(getReplCoord()->setLastOptime(&txn, myRID, time2)); + ASSERT_OK(getReplCoord()->setLastOptime(&txn, client1, time1)); + + std::vector<HostAndPort> caughtUpHosts = getReplCoord()->getHostsWrittenTo(time2); + ASSERT_EQUALS(1U, caughtUpHosts.size()); + ASSERT_EQUALS(myHost, caughtUpHosts[0]); + + ASSERT_OK(getReplCoord()->setLastOptime(&txn, client2, time2)); + caughtUpHosts = getReplCoord()->getHostsWrittenTo(time2); + ASSERT_EQUALS(2U, caughtUpHosts.size()); + if (myHost == caughtUpHosts[0]) { + ASSERT_EQUALS(client2Host, caughtUpHosts[1]); + } + else { + ASSERT_EQUALS(client2Host, caughtUpHosts[0]); + ASSERT_EQUALS(myHost, caughtUpHosts[1]); + } + } + + TEST_F(ReplCoordTest, GetHostsWrittenToMasterSlave) { + ReplSettings settings; + settings.master = true; + init(settings); + HostAndPort clientHost("node2:12345"); + OperationContextNoop txn; + + OID myRID = getReplCoord()->getMyRID(); + OID client = OID::gen(); + OpTime time1(1, 1); + OpTime time2(1, 2); + + getExternalState()->setClientHostAndPort(clientHost); + HandshakeArgs handshake; + ASSERT_OK(handshake.initialize(BSON("handshake" << client))); + ASSERT_OK(getReplCoord()->processHandshake(&txn, handshake)); + + ASSERT_OK(getReplCoord()->setLastOptime(&txn, myRID, time2)); + ASSERT_OK(getReplCoord()->setLastOptime(&txn, client, time1)); + + std::vector<HostAndPort> caughtUpHosts = getReplCoord()->getHostsWrittenTo(time2); + ASSERT_EQUALS(0U, caughtUpHosts.size()); // self doesn't get included in master-slave + + ASSERT_OK(getReplCoord()->setLastOptime(&txn, client, time2)); + caughtUpHosts = getReplCoord()->getHostsWrittenTo(time2); + ASSERT_EQUALS(1U, caughtUpHosts.size()); + ASSERT_EQUALS(clientHost, caughtUpHosts[0]); + } + // TODO(schwerin): Unit test election id updating } // namespace diff --git a/src/mongo/db/repl/repl_coordinator_legacy.cpp b/src/mongo/db/repl/repl_coordinator_legacy.cpp index b4557f608b5..060f78d8d5f 100644 --- a/src/mongo/db/repl/repl_coordinator_legacy.cpp +++ b/src/mongo/db/repl/repl_coordinator_legacy.cpp @@ -953,8 +953,13 @@ namespace { return theReplSet->buildIndexes(); } - vector<BSONObj> LegacyReplicationCoordinator::getHostsWrittenTo(const OpTime& op) { - return repl::getHostsWrittenTo(op); + vector<HostAndPort> LegacyReplicationCoordinator::getHostsWrittenTo(const OpTime& op) { + vector<BSONObj> configs = repl::getHostsWrittenTo(op); + vector<HostAndPort> hosts; + for (size_t i = 0; i < configs.size(); ++i) { + hosts.push_back(HostAndPort(configs[i]["host"].String())); + } + return hosts; } Status LegacyReplicationCoordinator::checkIfWriteConcernCanBeSatisfied( diff --git a/src/mongo/db/repl/repl_coordinator_legacy.h b/src/mongo/db/repl/repl_coordinator_legacy.h index 415a8cfe175..581e7fd7432 100644 --- a/src/mongo/db/repl/repl_coordinator_legacy.h +++ b/src/mongo/db/repl/repl_coordinator_legacy.h @@ -149,7 +149,7 @@ namespace repl { virtual bool buildsIndexes(); - virtual std::vector<BSONObj> getHostsWrittenTo(const OpTime& op); + virtual std::vector<HostAndPort> getHostsWrittenTo(const OpTime& op); virtual BSONObj getGetLastErrorDefault(); diff --git a/src/mongo/db/repl/repl_coordinator_mock.cpp b/src/mongo/db/repl/repl_coordinator_mock.cpp index 6c4e5828595..bafad53ca68 100644 --- a/src/mongo/db/repl/repl_coordinator_mock.cpp +++ b/src/mongo/db/repl/repl_coordinator_mock.cpp @@ -230,9 +230,8 @@ namespace repl { return false; } - std::vector<BSONObj> ReplicationCoordinatorMock::getHostsWrittenTo(const OpTime& op) { - // TODO - return std::vector<BSONObj>(); + std::vector<HostAndPort> ReplicationCoordinatorMock::getHostsWrittenTo(const OpTime& op) { + return std::vector<HostAndPort>(); } Status ReplicationCoordinatorMock::checkIfWriteConcernCanBeSatisfied( diff --git a/src/mongo/db/repl/repl_coordinator_mock.h b/src/mongo/db/repl/repl_coordinator_mock.h index 53f045c4443..aa3bfec4bd9 100644 --- a/src/mongo/db/repl/repl_coordinator_mock.h +++ b/src/mongo/db/repl/repl_coordinator_mock.h @@ -150,7 +150,7 @@ namespace repl { virtual bool buildsIndexes(); - virtual std::vector<BSONObj> getHostsWrittenTo(const OpTime& op); + virtual std::vector<HostAndPort> getHostsWrittenTo(const OpTime& op); virtual BSONObj getGetLastErrorDefault(); diff --git a/src/mongo/db/repl/repl_coordinator_test_fixture.h b/src/mongo/db/repl/repl_coordinator_test_fixture.h index d636b5a61eb..5529572c7a6 100644 --- a/src/mongo/db/repl/repl_coordinator_test_fixture.h +++ b/src/mongo/db/repl/repl_coordinator_test_fixture.h @@ -82,6 +82,11 @@ namespace repl { TopologyCoordinatorImpl& getTopoCoord() { return *_topo;} /** + * Gets the external state used by the replication coordinator under test. + */ + ReplicationCoordinatorExternalStateMock* getExternalState() { return _externalState; } + + /** * Initializes the objects under test; this behavior is optional, in case you need to call * any methods on the network or coordinator objects before calling start. */ diff --git a/src/mongo/db/write_concern.cpp b/src/mongo/db/write_concern.cpp index 3aaefead488..90fe69b947b 100644 --- a/src/mongo/db/write_concern.cpp +++ b/src/mongo/db/write_concern.cpp @@ -105,10 +105,15 @@ namespace mongo { if ( wTimedOut ) result->appendBool( "wtimeout", true ); - if ( writtenTo.size() ) - result->append( "writtenTo", writtenTo ); - else + if (writtenTo.size()) { + BSONArrayBuilder hosts(result->subarrayStart("writtenTo")); + for (size_t i = 0; i < writtenTo.size(); ++i) { + hosts.append(writtenTo[i].toString()); + } + } + else { result->appendNull( "writtenTo" ); + } if ( err.empty() ) result->appendNull( "err" ); diff --git a/src/mongo/db/write_concern.h b/src/mongo/db/write_concern.h index 6e4a1c30087..98d7893a2e1 100644 --- a/src/mongo/db/write_concern.h +++ b/src/mongo/db/write_concern.h @@ -29,6 +29,7 @@ #pragma once #include "mongo/db/write_concern_options.h" +#include "mongo/util/net/hostandport.h" namespace mongo { @@ -59,7 +60,7 @@ namespace mongo { bool wTimedOut; int wTime; - std::vector<BSONObj> writtenTo; + std::vector<HostAndPort> writtenTo; std::string err; // this is the old err field, should deprecate }; |