summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorA. Jesse Jiryu Davis <jesse@mongodb.com>2018-12-17 17:01:47 -0500
committerA. Jesse Jiryu Davis <jesse@mongodb.com>2019-01-07 19:01:46 -0500
commit327a6bd87961eb7d3cd2a4cd90170e868adf2112 (patch)
treebd1c88374aafb81853ffa1762ffe5f6e0dcc1901 /src
parentc2ba9aa09271a916ab5d3e6fc27c94ae10a66ee3 (diff)
downloadmongo-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.cpp54
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.h11
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_elect_v1.cpp14
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();
}