diff options
author | A. Jesse Jiryu Davis <jesse@mongodb.com> | 2018-12-17 17:01:47 -0500 |
---|---|---|
committer | A. Jesse Jiryu Davis <jesse@mongodb.com> | 2019-01-07 19:01:46 -0500 |
commit | 327a6bd87961eb7d3cd2a4cd90170e868adf2112 (patch) | |
tree | bd1c88374aafb81853ffa1762ffe5f6e0dcc1901 /src | |
parent | c2ba9aa09271a916ab5d3e6fc27c94ae10a66ee3 (diff) | |
download | mongo-327a6bd87961eb7d3cd2a4cd90170e868adf2112.tar.gz |
SERVER-37255 Fix invariant when reconfig races with election
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl.cpp | 54 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl.h | 11 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl_elect_v1.cpp | 14 |
3 files changed, 48 insertions, 31 deletions
diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index c66445f02d2..1b313c4c440 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -572,7 +572,7 @@ void ReplicationCoordinatorImpl::_finishLoadLocalConfig( if (localConfig.getReplSetName() != _settings.ourSetName()) { warning() << "Local replica set configuration document reports set name of " << localConfig.getReplSetName() << ", but command line reports " - << _settings.ourSetName() << "; waitng for reconfig or remote heartbeat"; + << _settings.ourSetName() << "; waiting for reconfig or remote heartbeat"; myIndex = StatusWith<int>(-1); } @@ -2440,7 +2440,7 @@ void ReplicationCoordinatorImpl::_finishReplSetReconfig( const PostMemberStateUpdateAction action = _setCurrentRSConfig(lk, opCtx.get(), newConfig, myIndex); - // On a reconfig we drop all snapshots so we don't mistakenely read from the wrong one. + // On a reconfig we drop all snapshots so we don't mistakenly read from the wrong one. // For example, if we change the meaning of the "committed" snapshot from applied -> durable. _dropAllSnapshots_inlock(); @@ -2695,37 +2695,13 @@ void ReplicationCoordinatorImpl::_performPostMemberStateUpdateAction( case kActionNone: break; case kActionFollowerModeStateChange: - // In follower mode, or sub-mode so ensure replication is active - _externalState->signalApplierToChooseNewSyncSource(); + _onFollowerModeStateChange(); break; case kActionCloseAllConnections: _externalState->closeConnections(); _externalState->shardingOnStepDownHook(); _externalState->stopNoopWriter(); break; - case kActionWinElection: { - stdx::unique_lock<stdx::mutex> lk(_mutex); - invariant(_topCoord->getTerm() != OpTime::kUninitializedTerm); - _electionId = OID::fromTerm(_topCoord->getTerm()); - - auto ts = LogicalClock::get(getServiceContext())->reserveTicks(1).asTimestamp(); - _topCoord->processWinElection(_electionId, ts); - const PostMemberStateUpdateAction nextAction = - _updateMemberStateFromTopologyCoordinator(lk, nullptr); - invariant(nextAction != kActionWinElection); - lk.unlock(); - _performPostMemberStateUpdateAction(nextAction); - lk.lock(); - if (!_getMemberState_inlock().primary()) { - break; - } - // Notify all secondaries of the election win. - _restartHeartbeats_inlock(); - invariant(!_catchupState); - _catchupState = stdx::make_unique<CatchupState>(this); - _catchupState->start_inlock(); - break; - } case kActionStartSingleNodeElection: // In protocol version 1, single node replset will run an election instead of // kActionWinElection as in protocol version 0. @@ -2737,6 +2713,30 @@ void ReplicationCoordinatorImpl::_performPostMemberStateUpdateAction( } } +void ReplicationCoordinatorImpl::_postWonElectionUpdateMemberState(WithLock lk) { + invariant(_topCoord->getTerm() != OpTime::kUninitializedTerm); + _electionId = OID::fromTerm(_topCoord->getTerm()); + auto ts = LogicalClock::get(getServiceContext())->reserveTicks(1).asTimestamp(); + _topCoord->processWinElection(_electionId, ts); + const PostMemberStateUpdateAction nextAction = + _updateMemberStateFromTopologyCoordinator(lk, nullptr); + + invariant(nextAction == kActionFollowerModeStateChange, + str::stream() << "nextAction == " << static_cast<int>(nextAction)); + invariant(_getMemberState_inlock().primary()); + // Clear the sync source. + _onFollowerModeStateChange(); + // Notify all secondaries of the election win. + _restartHeartbeats_inlock(); + invariant(!_catchupState); + _catchupState = stdx::make_unique<CatchupState>(this); + _catchupState->start_inlock(); +} + +void ReplicationCoordinatorImpl::_onFollowerModeStateChange() { + _externalState->signalApplierToChooseNewSyncSource(); +} + void ReplicationCoordinatorImpl::CatchupState::start_inlock() { log() << "Entering primary catch-up mode."; diff --git a/src/mongo/db/repl/replication_coordinator_impl.h b/src/mongo/db/repl/replication_coordinator_impl.h index 765e4559c13..f4aa0b4146b 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.h +++ b/src/mongo/db/repl/replication_coordinator_impl.h @@ -441,7 +441,6 @@ private: kActionNone, kActionCloseAllConnections, // Also indicates that we should clear sharding state. kActionFollowerModeStateChange, - kActionWinElection, kActionStartSingleNodeElection }; @@ -845,6 +844,16 @@ private: void _performPostMemberStateUpdateAction(PostMemberStateUpdateAction action); /** + * Update state after winning an election. + */ + void _postWonElectionUpdateMemberState(WithLock lk); + + /** + * Helper to select appropriate sync source after transitioning from a follower state. + */ + void _onFollowerModeStateChange(); + + /** * Begins an attempt to elect this node. * Called after an incoming heartbeat changes this node's view of the set such that it * believes it can be elected PRIMARY. 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 51b4d47980c..f5d047e9406 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_elect_v1.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_elect_v1.cpp @@ -290,8 +290,10 @@ void ReplicationCoordinatorImpl::_startVoteRequester_inlock(long long newTerm) { .status_with_transitional_ignore(); } +MONGO_FAIL_POINT_DEFINE(electionHangsBeforeUpdateMemberState); + void ReplicationCoordinatorImpl::_onVoteRequestComplete(long long newTerm) { - stdx::unique_lock<stdx::mutex> lk(_mutex); + stdx::lock_guard<stdx::mutex> lk(_mutex); LoseElectionGuardV1 lossGuard(this); invariant(_voteRequester); @@ -329,9 +331,15 @@ void ReplicationCoordinatorImpl::_onVoteRequestComplete(long long newTerm) { _voteRequester.reset(); auto electionFinishedEvent = _electionFinishedEvent; - lk.unlock(); - _performPostMemberStateUpdateAction(kActionWinElection); + MONGO_FAIL_POINT_BLOCK(electionHangsBeforeUpdateMemberState, customWait) { + auto waitForMillis = Milliseconds(customWait.getData()["waitForMillis"].numberInt()); + log() << "election succeeded - electionHangsBeforeUpdateMemberState fail point " + "enabled, sleeping " + << waitForMillis; + sleepFor(waitForMillis); + } + _postWonElectionUpdateMemberState(lk); _replExecutor->signalEvent(electionFinishedEvent); lossGuard.dismiss(); } |