diff options
author | Benety Goh <benety@mongodb.com> | 2015-10-16 15:40:39 -0400 |
---|---|---|
committer | Benety Goh <benety@mongodb.com> | 2015-10-22 15:27:17 -0400 |
commit | fd6d4f03054ccc1f6df634d7a9d5060186070e98 (patch) | |
tree | c2441c3ecdfc3c1822ba5d535f9dc3138a6da1d8 /src | |
parent | 38f16626e9f161672ebad8ad4a18e23b7e57de87 (diff) | |
download | mongo-fd6d4f03054ccc1f6df634d7a9d5060186070e98.tar.gz |
SERVER-20977 added test for processing metadata in heartbeat
Diffstat (limited to 'src')
6 files changed, 94 insertions, 10 deletions
diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index 683777454e6..82617ff73c4 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -3308,6 +3308,15 @@ CallbackHandle ReplicationCoordinatorImpl::_wrapAndScheduleWork(ScheduleFn sched return cbh.getValue(); } +EventHandle ReplicationCoordinatorImpl::_makeEvent() { + auto eventResult = this->_replExecutor.makeEvent(); + if (eventResult.getStatus() == ErrorCodes::ShutdownInProgress) { + return EventHandle(); + } + fassert(28825, eventResult.getStatus()); + return eventResult.getValue(); +} + void ReplicationCoordinatorImpl::_scheduleElectionWinNotification() { auto electionWinNotificationCallback = [this](const CallbackArgs& cbData) { if (cbData.status == ErrorCodes::CallbackCanceled) { diff --git a/src/mongo/db/repl/replication_coordinator_impl.h b/src/mongo/db/repl/replication_coordinator_impl.h index e4f9a50e5c1..80757b7ba8e 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.h +++ b/src/mongo/db/repl/replication_coordinator_impl.h @@ -386,6 +386,8 @@ private: using CallbackHandle = executor::TaskExecutor::CallbackHandle; + using EventHandle = executor::TaskExecutor::EventHandle; + using ScheduleFn = stdx::function<StatusWith<executor::TaskExecutor::CallbackHandle>( const executor::TaskExecutor::CallbackFn& work)>; @@ -1143,6 +1145,13 @@ private: static CallbackHandle _wrapAndScheduleWork(ScheduleFn scheduleFn, const CallbackFn& work); /** + * Creates an event. + * Returns invalid event handle if the executor is shutting down. + * Otherwise aborts on non-shutdown error. + */ + EventHandle _makeEvent(); + + /** * Schedule notification of election win. */ void _scheduleElectionWinNotification(); diff --git a/src/mongo/db/repl/replication_coordinator_impl_elect_v1.cpp b/src/mongo/db/repl/replication_coordinator_impl_elect_v1.cpp index 337a9ce3ff6..a1b53badd44 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_elect_v1.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_elect_v1.cpp @@ -108,19 +108,17 @@ void ReplicationCoordinatorImpl::_startElectSelfV1() { fassertFailed(28641); } - const StatusWith<ReplicationExecutor::EventHandle> finishEvh = _replExecutor.makeEvent(); - if (finishEvh.getStatus() == ErrorCodes::ShutdownInProgress) { + auto finishedEvent = _makeEvent(); + if (!finishedEvent) { return; } - fassert(28642, finishEvh.getStatus()); - _electionFinishedEvent = finishEvh.getValue(); + _electionFinishedEvent = finishedEvent; - const StatusWith<ReplicationExecutor::EventHandle> dryRunFinishEvh = _replExecutor.makeEvent(); - if (dryRunFinishEvh.getStatus() == ErrorCodes::ShutdownInProgress) { + auto dryRunFinishedEvent = _makeEvent(); + if (!dryRunFinishedEvent) { return; } - fassert(28767, dryRunFinishEvh.getStatus()); - _electionDryRunFinishedEvent = dryRunFinishEvh.getValue(); + _electionDryRunFinishedEvent = dryRunFinishedEvent; LoseElectionDryRunGuardV1 lossGuard(this); diff --git a/src/mongo/db/repl/replication_coordinator_impl_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_test.cpp index 3e1adc2ac88..b2582d33946 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_test.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_test.cpp @@ -2798,6 +2798,59 @@ TEST_F(ReplCoordTest, MetadataUpdatesTermAndPrimaryId) { ASSERT_EQUALS(-1, getTopoCoord().getCurrentPrimaryIndex()); } +TEST_F(ReplCoordTest, + TermAndLastCommittedOpTimeUpdateWhenHeartbeatResponseWithMetadataHasFresherValues) { + // Ensure that the metadata is processed if it is contained in a heartbeat response. + assertStartSuccess(BSON("_id" + << "mySet" + << "version" << 2 << "members" << BSON_ARRAY(BSON("host" + << "node1:12345" + << "_id" << 0) + << BSON("host" + << "node2:12345" + << "_id" << 1)) + << "protocolVersion" << 1), + HostAndPort("node1", 12345)); + ASSERT_EQUALS(OpTime(Timestamp(0, 0), 0), getReplCoord()->getLastCommittedOpTime()); + getReplCoord()->updateTerm(1); + ASSERT_EQUALS(1, getReplCoord()->getTerm()); + + auto replCoord = getReplCoord(); + auto config = replCoord->getConfig(); + + // Higher term - should update term and lastCommittedOpTime. + StatusWith<rpc::ReplSetMetadata> metadata = rpc::ReplSetMetadata::readFromMetadata(BSON( + rpc::kReplSetMetadataFieldName + << BSON("lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 3) << "lastOpVisible" + << BSON("ts" << Timestamp(10, 0) << "t" << 3) << "configVersion" + << config.getConfigVersion() << "primaryIndex" << 1 << "term" << 3 + << "syncSourceIndex" << 1))); + BSONObjBuilder metadataBuilder; + ASSERT_OK(metadata.getValue().writeToMetadata(&metadataBuilder)); + auto metadataObj = metadataBuilder.obj(); + + auto net = getNet(); + net->enterNetwork(); + + ASSERT_TRUE(net->hasReadyRequests()); + auto noi = net->getNextReadyRequest(); + const auto& request = noi->getRequest(); + ASSERT_EQUALS(HostAndPort("node2", 12345), request.target); + ASSERT_EQUALS("replSetHeartbeat", request.cmdObj.firstElement().fieldNameStringData()); + + ReplSetHeartbeatResponse hbResp; + hbResp.setConfigVersion(config.getConfigVersion()); + hbResp.setSetName(config.getReplSetName()); + hbResp.setState(MemberState::RS_SECONDARY); + net->scheduleResponse(noi, net->now(), makeResponseStatus(hbResp.toBSON(true), metadataObj)); + net->runReadyNetworkOperations(); + net->exitNetwork(); + + ASSERT_EQUALS(OpTime(Timestamp(10, 0), 3), getReplCoord()->getLastCommittedOpTime()); + ASSERT_EQUALS(3, getReplCoord()->getTerm()); + ASSERT_EQUALS(-1, getTopoCoord().getCurrentPrimaryIndex()); +} + TEST_F(ReplCoordTest, CancelAndRescheduleElectionTimeout) { assertStartSuccess(BSON("_id" << "mySet" diff --git a/src/mongo/db/repl/replication_coordinator_test_fixture.cpp b/src/mongo/db/repl/replication_coordinator_test_fixture.cpp index c0bc9096c14..539c06d97f0 100644 --- a/src/mongo/db/repl/replication_coordinator_test_fixture.cpp +++ b/src/mongo/db/repl/replication_coordinator_test_fixture.cpp @@ -172,8 +172,15 @@ void ReplCoordTest::assertStartSuccess(const BSONObj& configDoc, const HostAndPo } ResponseStatus ReplCoordTest::makeResponseStatus(const BSONObj& doc, Milliseconds millis) { - log() << "Responding with " << doc; - return ResponseStatus(RemoteCommandResponse(doc, BSONObj(), millis)); + return makeResponseStatus(doc, BSONObj(), millis); +} + +ResponseStatus ReplCoordTest::makeResponseStatus(const BSONObj& doc, + const BSONObj& metadata, + Milliseconds millis) { + log() << "Responding with " << doc << " (metadata: " << metadata << "; elapsed: " << millis + << ")"; + return ResponseStatus(RemoteCommandResponse(doc, metadata, millis)); } void ReplCoordTest::simulateSuccessfulDryRun( diff --git a/src/mongo/db/repl/replication_coordinator_test_fixture.h b/src/mongo/db/repl/replication_coordinator_test_fixture.h index a4023857091..b6b40d6f090 100644 --- a/src/mongo/db/repl/replication_coordinator_test_fixture.h +++ b/src/mongo/db/repl/replication_coordinator_test_fixture.h @@ -64,6 +64,14 @@ public: Milliseconds millis = Milliseconds(0)); /** + * Makes a ResponseStatus with the given "doc" response, metadata and optional elapsed time + * "millis". + */ + static ResponseStatus makeResponseStatus(const BSONObj& doc, + const BSONObj& metadata, + Milliseconds millis = Milliseconds(0)); + + /** * Constructs a ReplicaSetConfig from the given BSON, or raises a test failure exception. */ static ReplicaSetConfig assertMakeRSConfig(const BSONObj& configBSON); |