From 4c0d9383a76c82c0e46ce8d82ed17d3687f12d8f Mon Sep 17 00:00:00 2001 From: William Schultz Date: Tue, 14 Jul 2020 08:54:10 -0400 Subject: SERVER-47845 Remove obsolete logic related to storing and updating the stable optime candidates list This commit removes the now unused '_stableOpTimeCandidates' member variable and the '_chooseStableOpTimeFromCandidates' and '_cleanupStableOpTimeCandidates' methods, along with associated test methods, from ReplicationCoordinator. --- src/mongo/db/repl/replication_coordinator_impl.cpp | 99 ------- src/mongo/db/repl/replication_coordinator_impl.h | 35 +-- .../db/repl/replication_coordinator_impl_test.cpp | 299 +-------------------- 3 files changed, 4 insertions(+), 429 deletions(-) diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index 6f293809254..441f088648a 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -1357,7 +1357,6 @@ void ReplicationCoordinatorImpl::_resetMyLastOpTimes(WithLock lk) { _setMyLastAppliedOpTimeAndWallTime( lk, OpTimeAndWallTime(), isRollbackAllowed, DataConsistency::Inconsistent); _setMyLastDurableOpTimeAndWallTime(lk, OpTimeAndWallTime(), isRollbackAllowed); - _stableOpTimeCandidates.clear(); } void ReplicationCoordinatorImpl::_reportUpstream_inlock(stdx::unique_lock lock) { @@ -1429,7 +1428,6 @@ void ReplicationCoordinatorImpl::_setMyLastAppliedOpTimeAndWallTime( if (consistency == DataConsistency::Consistent) { invariant(opTime.getTimestamp().getInc() > 0, str::stream() << "Impossible optime received: " << opTime.toString()); - _stableOpTimeCandidates.insert(opTimeAndWallTime); // If we are lagged behind the commit optime, set a new stable timestamp here. When majority // read concern is disabled, the stable timestamp is set to lastApplied. if (opTime <= _topCoord->getLastCommittedOpTime() || @@ -4130,16 +4128,7 @@ ReplicationCoordinatorImpl::_updateMemberStateFromTopologyCoordinator(WithLock l _dropAllSnapshots_inlock(); } - // Upon transitioning out of ROLLBACK, we must clear any stable optime candidates that may have - // been rolled back. if (_memberState.rollback()) { - // Our 'lastApplied' optime at this point should be the rollback common point. We should - // remove any stable optime candidates greater than the common point. - auto lastApplied = _getMyLastAppliedOpTimeAndWallTime_inlock(); - // The upper bound will give us the first optime T such that T > lastApplied. - auto deletePoint = _stableOpTimeCandidates.upper_bound(lastApplied); - _stableOpTimeCandidates.erase(deletePoint, _stableOpTimeCandidates.end()); - // Ensure that no snapshots were created while we were in rollback. invariant(!_currentCommittedSnapshot); } @@ -4825,93 +4814,6 @@ void ReplicationCoordinatorImpl::_updateLastCommittedOpTimeAndWallTime(WithLock } } -boost::optional ReplicationCoordinatorImpl::_chooseStableOpTimeFromCandidates( - WithLock lk, - const std::set& candidates, - OpTimeAndWallTime maximumStableOpTime) { - - // No optime candidates. - if (candidates.empty()) { - return boost::none; - } - - auto maximumStableTimestamp = maximumStableOpTime.opTime.getTimestamp(); - if (_readWriteAbility->canAcceptNonLocalWrites(lk) && _storage->supportsDocLocking(_service)) { - // If the storage engine supports document level locking, then it is possible for oplog - // writes to commit out of order. In that case, we don't want to set the stable timestamp - // ahead of the all_durable timestamp. This is not a problem for oplog application - // because we only set lastApplied between batches when the all_durable timestamp cannot - // be behind. During oplog application the all_durable timestamp can jump around since - // we first write oplog entries to the oplog and then go back and apply them. - // - // We must construct an upper bound for the stable optime candidates such that the upper - // bound is at most 'maximumStableOpTime' and any candidate with a timestamp higher than the - // all_durable is greater than the upper bound. If the timestamp of 'maximumStableOpTime' - // is <= the all_durable, then we use 'maximumStableOpTime'. Otherwise, we construct an - // optime using the all_durable and the term of 'maximumStableOpTime'. We must argue that - // there are no stable optime candidates with a timestamp greater than the all_durable and - // a term less than that of 'maximumStableOpTime'. Suppose there were. The - // 'maximumStableOpTime' is either the commit point or the lastApplied, so the all_durable - // can only be behind 'maximumStableOpTime' on a primary. If there is a candidate with a - // higher timestamp than the all_durable but a lower term than 'maximumStableOpTime', then - // the all_durable corresponds to a write in an earlier term than the current one. But - // this is not possible on a primary, since on step-up, the primary storage commits a 'new - // primary' oplog entry in the new term before accepting any new writes, so the all - // durable must be in the current term. - maximumStableTimestamp = std::min(_storage->getAllDurableTimestamp(_service), - maximumStableOpTime.opTime.getTimestamp()); - } - - maximumStableOpTime = {OpTime(maximumStableTimestamp, maximumStableOpTime.opTime.getTerm()), - maximumStableOpTime.wallTime}; - - // Find the greatest optime candidate that is less than or equal to 'maximumStableOpTime'. To do - // this we first find the upper bound of 'maximumStableOpTime', which points to the smallest - // element in 'candidates' that is greater than 'maximumStableOpTime'. We then step back one - // element, which should give us the largest element in 'candidates' that is less than or equal - // to the 'maximumStableOpTime'. - auto upperBoundIter = candidates.upper_bound(maximumStableOpTime); - - // All optime candidates are greater than the commit point. - if (upperBoundIter == candidates.begin()) { - return boost::none; - } - // There is a valid stable optime. - else { - auto stableOpTime = *std::prev(upperBoundIter); - invariant(stableOpTime.opTime.getTimestamp() <= maximumStableTimestamp); - return stableOpTime; - } -} - -void ReplicationCoordinatorImpl::_cleanupStableOpTimeCandidates( - std::set* candidates, OpTimeAndWallTime stableOpTime) { - // Discard optime candidates earlier than the current stable optime, since we don't need - // them anymore. To do this, we find the lower bound of the 'stableOpTime' which is the first - // element that is greater than or equal to the 'stableOpTime'. Then we discard everything up - // to but not including this lower bound i.e. 'deletePoint'. - auto deletePoint = candidates->lower_bound(stableOpTime); - - // Delete the entire range of unneeded optimes. - candidates->erase(candidates->begin(), deletePoint); -} - -boost::optional -ReplicationCoordinatorImpl::chooseStableOpTimeFromCandidates_forTest( - const std::set& candidates, const OpTimeAndWallTime& maximumStableOpTime) { - stdx::lock_guard lk(_mutex); - return _chooseStableOpTimeFromCandidates(lk, candidates, maximumStableOpTime); -} -void ReplicationCoordinatorImpl::cleanupStableOpTimeCandidates_forTest( - std::set* candidates, OpTimeAndWallTime stableOpTime) { - _cleanupStableOpTimeCandidates(candidates, stableOpTime); -} - -std::set ReplicationCoordinatorImpl::getStableOpTimeCandidates_forTest() { - stdx::unique_lock lk(_mutex); - return _stableOpTimeCandidates; -} - void ReplicationCoordinatorImpl::attemptToAdvanceStableTimestamp() { stdx::unique_lock lk(_mutex); _setStableTimestampForStorage(lk); @@ -5067,7 +4969,6 @@ void ReplicationCoordinatorImpl::_setStableTimestampForStorage(WithLock lk) { } } } - _cleanupStableOpTimeCandidates(&_stableOpTimeCandidates, stableOpTime.get()); } } diff --git a/src/mongo/db/repl/replication_coordinator_impl.h b/src/mongo/db/repl/replication_coordinator_impl.h index e73d5398acf..1a7d685c4a8 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.h +++ b/src/mongo/db/repl/replication_coordinator_impl.h @@ -446,12 +446,6 @@ public: /** * Simple test wrappers that expose private methods. */ - boost::optional chooseStableOpTimeFromCandidates_forTest( - const std::set& candidates, - const OpTimeAndWallTime& maximumStableOpTime); - void cleanupStableOpTimeCandidates_forTest(std::set* candidates, - OpTimeAndWallTime stableOpTime); - std::set getStableOpTimeCandidates_forTest(); void handleHeartbeatResponse_forTest(BSONObj response, int targetIndex, Milliseconds ping = Milliseconds(100)); @@ -1352,28 +1346,7 @@ private: boost::optional _recalculateStableOpTime(WithLock lk); /** - * Calculates the 'stable' replication optime given a set of optime candidates and a maximum - * stable optime. The stable optime is the greatest optime in 'candidates' that is also less - * than or equal to 'maximumStableOpTime' and other criteria. - * - * Returns boost::none if there is no satisfactory candidate. - */ - boost::optional _chooseStableOpTimeFromCandidates( - WithLock lk, - const std::set& candidates, - OpTimeAndWallTime maximumStableOpTime); - - /** - * Removes any optimes from the optime set 'candidates' that are less than - * 'stableOpTime'. - */ - void _cleanupStableOpTimeCandidates(std::set* candidates, - OpTimeAndWallTime stableOpTime); - - /** - * Calculates and sets the value of the 'stable' replication optime for the storage engine. See - * ReplicationCoordinatorImpl::_chooseStableOpTimeFromCandidates for a definition of 'stable', - * in this context. + * Calculates and sets the value of the 'stable' replication optime for the storage engine. */ void _setStableTimestampForStorage(WithLock lk); @@ -1630,12 +1603,6 @@ private: // When engaged, this must be <= _lastCommittedOpTime. boost::optional _currentCommittedSnapshot; // (M) - // A set of optimes that are used for computing the replication system's current 'stable' - // optime. Every time a node's applied optime is updated, it will be added to this set. - // Optimes that are older than the current stable optime should get removed from this set. - // This set should also be cleared if a rollback occurs. - std::set _stableOpTimeCandidates; // (M) - // A flag that enables/disables advancement of the stable timestamp for storage. bool _shouldSetStableTimestamp = true; // (M) diff --git a/src/mongo/db/repl/replication_coordinator_impl_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_test.cpp index 6a84d60930a..c98bc0e070c 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_test.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_test.cpp @@ -5572,190 +5572,12 @@ TEST_F(ReplCoordTest, * Tests to ensure that ReplicationCoordinator correctly calculates and updates the stable * optime. */ -class StableOpTimeTest : public ReplCoordTest { -protected: - /** - * Return a string representation of the given set 's'. - */ - std::string opTimeSetString(std::set s) { - std::stringstream ss; - ss << "{ "; - for (auto const& el : s) { - ss << el << " "; - } - ss << "}"; - return ss.str(); - } - - void initReplSetMode() { - auto settings = ReplSettings(); - settings.setReplSetString("replset"); - init(settings); - } -}; - -// An equality assertion for two std::set values. Prints the elements of each set when -// the assertion fails. Only to be used in a 'StableOpTimeTest' unit test function. -#define ASSERT_OPTIME_SET_EQ(a, b) \ - ASSERT(a == b) << (opTimeSetString(a) + " != " + opTimeSetString(b)); - -TEST_F(StableOpTimeTest, CalculateStableOpTime) { - - /** - * Tests the 'ReplicationCoordinatorImpl::_calculateStableOpTime' method. - */ - - initReplSetMode(); - auto repl = getReplCoord(); - OpTimeAndWallTime commitPoint; - boost::optional expectedStableOpTime; - boost::optional stableOpTime; - std::set stableOpTimeCandidates; - long long term = 0; - - // There is a valid stable optime less than the commit point. - commitPoint = {OpTime({0, 3}, term), Date_t()}; - stableOpTimeCandidates = {{OpTime({0, 0}, term), Date_t()}, - {OpTime({0, 1}, term), Date_t()}, - {OpTime({0, 2}, term), Date_t() + Seconds(20)}, - {OpTime({0, 4}, term), Date_t()}}; - expectedStableOpTime = makeOpTimeAndWallTime(OpTime({0, 2}, term), Date_t() + Seconds(20)); - stableOpTime = - repl->chooseStableOpTimeFromCandidates_forTest(stableOpTimeCandidates, commitPoint); - ASSERT_EQ(expectedStableOpTime, stableOpTime); - - // There is a valid stable optime equal to the commit point. - commitPoint = {OpTime({0, 2}, term), Date_t()}; - stableOpTimeCandidates = {{OpTime({0, 0}, term), Date_t()}, - {OpTime({0, 1}, term), Date_t()}, - {OpTime({0, 2}, term), Date_t() + Seconds(30)}, - {OpTime({0, 3}, term), Date_t()}}; - expectedStableOpTime = makeOpTimeAndWallTime(OpTime({0, 2}, term), Date_t() + Seconds(30)); - stableOpTime = - repl->chooseStableOpTimeFromCandidates_forTest(stableOpTimeCandidates, commitPoint); - ASSERT_EQ(expectedStableOpTime, stableOpTime); - - // There is a valid stable optime, all candidates are smaller than the commit point. - commitPoint = {OpTime({0, 4}, term), Date_t()}; - stableOpTimeCandidates = {{OpTime({0, 1}, term), Date_t()}, - {OpTime({0, 2}, term), Date_t()}, - {OpTime({0, 3}, term), Date_t() + Seconds(40)}}; - expectedStableOpTime = makeOpTimeAndWallTime(OpTime({0, 3}, term), Date_t() + Seconds(40)); - stableOpTime = - repl->chooseStableOpTimeFromCandidates_forTest(stableOpTimeCandidates, commitPoint); - ASSERT_EQ(expectedStableOpTime, stableOpTime); - - // There is no valid stable optime, all candidates are greater than the commit point. - commitPoint = {OpTime({0, 0}, term), Date_t()}; - stableOpTimeCandidates = {{OpTime({0, 1}, term), Date_t()}, - {OpTime({0, 2}, term), Date_t()}, - {OpTime({0, 3}, term), Date_t()}}; - expectedStableOpTime = boost::none; - stableOpTime = - repl->chooseStableOpTimeFromCandidates_forTest(stableOpTimeCandidates, commitPoint); - ASSERT_EQ(expectedStableOpTime, stableOpTime); - - // There are no timestamp candidates. - commitPoint = {OpTime({0, 0}, term), Date_t()}; - stableOpTimeCandidates = {}; - expectedStableOpTime = boost::none; - stableOpTime = - repl->chooseStableOpTimeFromCandidates_forTest(stableOpTimeCandidates, commitPoint); - ASSERT_EQ(expectedStableOpTime, stableOpTime); - - // There is a single timestamp candidate which is equal to the commit point. - commitPoint = {OpTime({0, 1}, term), Date_t()}; - stableOpTimeCandidates = {{OpTime({0, 1}, term), Date_t() + Seconds(60)}}; - expectedStableOpTime = makeOpTimeAndWallTime(OpTime({0, 1}, term), Date_t() + Seconds(60)); - stableOpTime = - repl->chooseStableOpTimeFromCandidates_forTest(stableOpTimeCandidates, commitPoint); - ASSERT_EQ(expectedStableOpTime, stableOpTime); - - // There is a single timestamp candidate which is greater than the commit point. - commitPoint = {OpTime({0, 0}, term), Date_t()}; - stableOpTimeCandidates = {{OpTime({0, 1}, term), Date_t()}}; - expectedStableOpTime = boost::none; - stableOpTime = - repl->chooseStableOpTimeFromCandidates_forTest(stableOpTimeCandidates, commitPoint); - ASSERT_EQ(expectedStableOpTime, stableOpTime); - - // There is a single timestamp candidate which is less than the commit point. - commitPoint = {OpTime({0, 2}, term), Date_t()}; - stableOpTimeCandidates = {{OpTime({0, 1}, term), Date_t() + Seconds(70)}}; - expectedStableOpTime = makeOpTimeAndWallTime(OpTime({0, 1}, term), Date_t() + Seconds(70)); - stableOpTime = - repl->chooseStableOpTimeFromCandidates_forTest(stableOpTimeCandidates, commitPoint); - ASSERT_EQ(expectedStableOpTime, stableOpTime); -} - -TEST_F(StableOpTimeTest, CleanupStableOpTimeCandidates) { - - /** - * Tests the 'ReplicationCoordinatorImpl::_cleanupStableOpTimeCandidates' method. - */ - - initReplSetMode(); - auto repl = getReplCoord(); - OpTimeAndWallTime stableOpTime; - std::set opTimeCandidates, expectedOpTimeCandidates; - long long term = 0; - - // Cleanup should remove all timestamp candidates < the stable optime. - stableOpTime = makeOpTimeAndWallTime(OpTime({0, 3}, term)); - opTimeCandidates = {makeOpTimeAndWallTime(OpTime({0, 1}, term)), - makeOpTimeAndWallTime(OpTime({0, 2}, term)), - makeOpTimeAndWallTime(OpTime({0, 3}, term), Date_t() + Seconds(80)), - makeOpTimeAndWallTime(OpTime({0, 4}, term))}; - expectedOpTimeCandidates = {makeOpTimeAndWallTime(OpTime({0, 3}, term), Date_t() + Seconds(80)), - makeOpTimeAndWallTime(OpTime({0, 4}, term))}; - repl->cleanupStableOpTimeCandidates_forTest(&opTimeCandidates, stableOpTime); - ASSERT_OPTIME_SET_EQ(expectedOpTimeCandidates, opTimeCandidates); - - // Cleanup should remove all timestamp candidates if they are all < the stable optime. - stableOpTime = makeOpTimeAndWallTime(OpTime({0, 5}, term)); - opTimeCandidates = {makeOpTimeAndWallTime(OpTime({0, 1}, term)), - makeOpTimeAndWallTime(OpTime({0, 2}, term)), - makeOpTimeAndWallTime(OpTime({0, 3}, term)), - makeOpTimeAndWallTime(OpTime({0, 4}, term))}; - expectedOpTimeCandidates = {}; - repl->cleanupStableOpTimeCandidates_forTest(&opTimeCandidates, stableOpTime); - ASSERT_OPTIME_SET_EQ(expectedOpTimeCandidates, opTimeCandidates); - - // Cleanup should have no effect when stable optime is less than all candidates. - stableOpTime = makeOpTimeAndWallTime(OpTime({0, 0}, term)); - opTimeCandidates = {makeOpTimeAndWallTime(OpTime({0, 1}, term)), - makeOpTimeAndWallTime(OpTime({0, 2}, term)), - makeOpTimeAndWallTime(OpTime({0, 3}, term)), - makeOpTimeAndWallTime(OpTime({0, 4}, term))}; - expectedOpTimeCandidates = {makeOpTimeAndWallTime(OpTime({0, 1}, term)), - makeOpTimeAndWallTime(OpTime({0, 2}, term)), - makeOpTimeAndWallTime(OpTime({0, 3}, term)), - makeOpTimeAndWallTime(OpTime({0, 4}, term))}; - repl->cleanupStableOpTimeCandidates_forTest(&opTimeCandidates, stableOpTime); - ASSERT_OPTIME_SET_EQ(expectedOpTimeCandidates, opTimeCandidates); - - // Cleanup should have no effect for a single candidate that is equal to stable optime. - stableOpTime = makeOpTimeAndWallTime(OpTime({0, 1}, term)); - opTimeCandidates = {makeOpTimeAndWallTime(OpTime({0, 1}, term))}; - expectedOpTimeCandidates = {makeOpTimeAndWallTime(OpTime({0, 1}, term))}; - repl->cleanupStableOpTimeCandidates_forTest(&opTimeCandidates, stableOpTime); - ASSERT_OPTIME_SET_EQ(expectedOpTimeCandidates, opTimeCandidates); - - // Cleanup should leave an empty candidate list unchanged. - stableOpTime = makeOpTimeAndWallTime(OpTime({0, 0}, term)); - opTimeCandidates = {}; - expectedOpTimeCandidates = {}; - repl->cleanupStableOpTimeCandidates_forTest(&opTimeCandidates, stableOpTime); - ASSERT_OPTIME_SET_EQ(expectedOpTimeCandidates, opTimeCandidates); -} - +class StableOpTimeTest : public ReplCoordTest {}; TEST_F(StableOpTimeTest, SetMyLastAppliedSetsStableOpTimeForStorage) { /** - * Test that 'setMyLastAppliedOpTime' sets the stable timestamp properly for the storage engine - * and that timestamp cleanup occurs. This test is not meant to fully exercise the stable - * optime calculation logic. + * Test that 'setMyLastAppliedOpTime' sets the stable timestamp properly for the storage engine. */ init("mySet/test1:1234,test2:1234,test3:1234"); assertStartSuccess(BSON("_id" @@ -5769,7 +5591,6 @@ TEST_F(StableOpTimeTest, SetMyLastAppliedSetsStableOpTimeForStorage) { << "test3:1234"))), HostAndPort("test2", 1234)); - auto repl = getReplCoord(); Timestamp stableTimestamp; getStorageInterface()->supportsDocLockingBool = true; @@ -5802,11 +5623,6 @@ TEST_F(StableOpTimeTest, SetMyLastAppliedSetsStableOpTimeForStorage) { replCoordSetMyLastAppliedOpTime(OpTimeWithTermOne(2, 2), Date_t() + Seconds(100)); stableTimestamp = getStorageInterface()->getStableTimestamp(); ASSERT_EQUALS(Timestamp(2, 2), stableTimestamp); - - auto opTimeCandidates = repl->getStableOpTimeCandidates_forTest(); - std::set expectedOpTimeCandidates = { - makeOpTimeAndWallTime(OpTimeWithTermOne(2, 2), Date_t() + Seconds(100))}; - ASSERT_OPTIME_SET_EQ(expectedOpTimeCandidates, opTimeCandidates); } TEST_F(StableOpTimeTest, SetMyLastAppliedSetsStableOpTimeForStorageDisableMajorityReadConcern) { @@ -5849,9 +5665,7 @@ TEST_F(StableOpTimeTest, SetMyLastAppliedSetsStableOpTimeForStorageDisableMajori TEST_F(StableOpTimeTest, AdvanceCommitPointSetsStableOpTimeForStorage) { /** - * Test that 'advanceCommitPoint' sets the stable optime for the storage engine and that - * timestamp cleanup occurs. This test is not meant to fully exercise the stable optime - * calculation logic. + * Test that 'advanceCommitPoint' sets the stable optime for the storage engine. */ init("mySet/test1:1234,test2:1234,test3:1234"); @@ -5903,12 +5717,6 @@ TEST_F(StableOpTimeTest, AdvanceCommitPointSetsStableOpTimeForStorage) { Date_t() + Seconds(3)); stableTimestamp = getStorageInterface()->getStableTimestamp(); ASSERT_EQUALS(Timestamp(3, 2), stableTimestamp); - - // Check that timestamp candidate cleanup occurs. - auto opTimeCandidates = getReplCoord()->getStableOpTimeCandidates_forTest(); - std::set expectedOpTimeCandidates = { - makeOpTimeAndWallTime(OpTime({3, 2}, term), Date_t() + Seconds(3))}; - ASSERT_OPTIME_SET_EQ(expectedOpTimeCandidates, opTimeCandidates); } TEST_F(StableOpTimeTest, @@ -5969,107 +5777,6 @@ TEST_F(StableOpTimeTest, ASSERT_EQUALS(Timestamp(1, 2), getStorageInterface()->getStableTimestamp()); } -TEST_F(StableOpTimeTest, ClearOpTimeCandidatesPastCommonPointAfterRollback) { - - assertStartSuccess(BSON("_id" - << "mySet" - << "version" << 1 << "members" - << BSON_ARRAY(BSON("host" - << "node1:12345" - << "_id" << 0)) - << "protocolVersion" << 1), - HostAndPort("node1", 12345)); - - auto repl = getReplCoord(); - long long term = 0; - ASSERT_OK(repl->setFollowerMode(MemberState::RS_SECONDARY)); - - OpTime rollbackCommonPoint = OpTime({1, 2}, term); - OpTimeAndWallTime commitPoint = - makeOpTimeAndWallTime(OpTime({1, 2}, term), Date_t() + Seconds(100)); - ASSERT_EQUALS(Timestamp::min(), getStorageInterface()->getStableTimestamp()); - - replCoordSetMyLastAppliedOpTime(OpTime({0, 1}, term), Date_t() + Seconds(100)); - // Advance commit point when it has the same term as the last applied. - replCoordAdvanceCommitPoint(commitPoint, false); - - replCoordSetMyLastAppliedOpTime(OpTime({1, 1}, term), Date_t() + Seconds(100)); - replCoordSetMyLastAppliedOpTime(OpTime({1, 2}, term), Date_t() + Seconds(100)); - replCoordSetMyLastAppliedOpTime(OpTime({1, 3}, term), Date_t() + Seconds(100)); - replCoordSetMyLastAppliedOpTime(OpTime({1, 4}, term), Date_t() + Seconds(100)); - - // The stable timestamp should be equal to the commit point timestamp. - const Timestamp stableTimestamp = getStorageInterface()->getStableTimestamp(); - Timestamp expectedStableTimestamp = commitPoint.opTime.getTimestamp(); - ASSERT_EQUALS(expectedStableTimestamp, stableTimestamp); - - // The stable optime candidate set should contain optimes >= the stable optime. - std::set opTimeCandidates = repl->getStableOpTimeCandidates_forTest(); - std::set expectedOpTimeCandidates = { - makeOpTimeAndWallTime(OpTime({1, 2}, term), Date_t() + Seconds(100)), - makeOpTimeAndWallTime(OpTime({1, 3}, term), Date_t() + Seconds(100)), - makeOpTimeAndWallTime(OpTime({1, 4}, term), Date_t() + Seconds(100))}; - ASSERT_OPTIME_SET_EQ(expectedOpTimeCandidates, opTimeCandidates); - - // We must take the RSTL in mode X before transitioning to RS_ROLLBACK. - const auto opCtx = makeOperationContext(); - ReplicationStateTransitionLockGuard transitionGuard(opCtx.get(), MODE_X); - - // Transition to ROLLBACK. The set of stable optime candidates should not have changed. - ASSERT_OK(repl->setFollowerModeRollback(opCtx.get())); - opTimeCandidates = repl->getStableOpTimeCandidates_forTest(); - ASSERT_OPTIME_SET_EQ(expectedOpTimeCandidates, opTimeCandidates); - - // Simulate a rollback to the common point. - getExternalState()->setLastOpTimeAndWallTime(rollbackCommonPoint, - Date_t() + Seconds(rollbackCommonPoint.getSecs())); - repl->resetLastOpTimesFromOplog(opCtx.get(), - ReplicationCoordinator::DataConsistency::Inconsistent); - - // Transition to RECOVERING from ROLLBACK. - ASSERT_OK(repl->setFollowerMode(MemberState::RS_RECOVERING)); - - // Make sure the stable optime candidate set has been cleared of all entries past the common - // point. - opTimeCandidates = repl->getStableOpTimeCandidates_forTest(); - auto stableOpTime = - repl->chooseStableOpTimeFromCandidates_forTest(opTimeCandidates, commitPoint); - ASSERT(stableOpTime); - expectedOpTimeCandidates = {*stableOpTime}; - ASSERT_OPTIME_SET_EQ(expectedOpTimeCandidates, opTimeCandidates); -} - -TEST_F(StableOpTimeTest, OpTimeCandidatesAreNotAddedWhenStateIsNotConsistent) { - - initReplSetMode(); - auto repl = getReplCoord(); - long long term = getTopoCoord().getTerm(); - - OpTimeAndWallTime consistentOpTime = - makeOpTimeAndWallTime(OpTime({1, 1}, term), Date_t() + Seconds(100)); - OpTimeAndWallTime inconsistentOpTime = - makeOpTimeAndWallTime(OpTime({1, 2}, term), Date_t() + Seconds(100)); - std::set expectedOpTimeCandidates = { - makeOpTimeAndWallTime(OpTime({1, 1}, term), Date_t() + Seconds(100))}; - - // Set the lastApplied optime forward when data is consistent, and check that it was added to - // the candidate set. - replCoordSetMyLastAppliedOpTimeForward(consistentOpTime.opTime, - ReplicationCoordinator::DataConsistency::Consistent, - consistentOpTime.wallTime); - ASSERT_EQUALS(consistentOpTime, repl->getMyLastAppliedOpTimeAndWallTime()); - ASSERT_OPTIME_SET_EQ(expectedOpTimeCandidates, repl->getStableOpTimeCandidates_forTest()); - - // Set the lastApplied optime forward when data is not consistent, and check that it wasn't - // added to the candidate set. - replCoordSetMyLastAppliedOpTimeForward(inconsistentOpTime.opTime, - ReplicationCoordinator::DataConsistency::Inconsistent, - inconsistentOpTime.wallTime); - ASSERT_EQUALS(inconsistentOpTime, repl->getMyLastAppliedOpTimeAndWallTime()); - ASSERT_OPTIME_SET_EQ(expectedOpTimeCandidates, repl->getStableOpTimeCandidates_forTest()); -} - - TEST_F(ReplCoordTest, NodeReturnsShutdownInProgressWhenWaitingUntilAnOpTimeDuringShutdown) { assertStartSuccess(BSON("_id" << "mySet" -- cgit v1.2.1