diff options
author | Judah Schvimer <judah@mongodb.com> | 2018-04-30 09:54:38 -0400 |
---|---|---|
committer | Xiangyu Yao <xiangyu.yao@mongodb.com> | 2018-09-06 12:29:46 -0400 |
commit | 1dae0760368101502647aa4c58f98e7b640d3e59 (patch) | |
tree | 8af4c2f5f2edaf5eefef3f2874c5de18328cb43a | |
parent | 828a110f9697c7a9eb1e8db96984b7956671a703 (diff) | |
download | mongo-1dae0760368101502647aa4c58f98e7b640d3e59.tar.gz |
SERVER-34465 Add a testing parameter to choose a permanent sync source
(cherry picked from commit bcd6d4e85d9e817892a4433219d1099f1532b413)
-rw-r--r-- | jstests/replsets/force_sync_source_candidate.js | 40 | ||||
-rw-r--r-- | src/mongo/db/repl/topology_coordinator.cpp | 39 |
2 files changed, 79 insertions, 0 deletions
diff --git a/jstests/replsets/force_sync_source_candidate.js b/jstests/replsets/force_sync_source_candidate.js new file mode 100644 index 00000000000..4be7b3bb668 --- /dev/null +++ b/jstests/replsets/force_sync_source_candidate.js @@ -0,0 +1,40 @@ +/* + * Tests that the 'forceSyncSourceCandidate' failpoint correctly forces a sync source. + * + * @tags: [requires_replication] + */ + +(function() { + "use strict"; + + const failpointName = "forceSyncSourceCandidate"; + + const rst = new ReplSetTest({ + nodes: + [{}, {rsConfig: {priority: 0}}, {rsConfig: {priority: 0}}, {rsConfig: {priority: 0}}], + // Allow many initial sync attempts. Initial sync may fail if the sync source does not have + // an oplog yet because it has not conducted its own initial sync yet. + // We turn on the noop writer to encourage successful sync source selection. + nodeOptions: {setParameter: {numInitialSyncAttempts: 100, writePeriodicNoops: true}} + }); + const nodes = rst.startSet(); + + function setFailPoint(node, syncSource) { + const dataObj = {hostAndPort: syncSource.host}; + assert.commandWorked(node.adminCommand( + {configureFailPoint: failpointName, mode: "alwaysOn", data: dataObj})); + } + + setFailPoint(nodes[1], nodes[0]); + setFailPoint(nodes[2], nodes[1]); + setFailPoint(nodes[3], nodes[2]); + + rst.initiate(); + const primary = rst.getPrimary(); + + rst.awaitSyncSource(nodes[1], nodes[0]); + rst.awaitSyncSource(nodes[2], nodes[1]); + rst.awaitSyncSource(nodes[3], nodes[2]); + + rst.stopSet(); +})(); diff --git a/src/mongo/db/repl/topology_coordinator.cpp b/src/mongo/db/repl/topology_coordinator.cpp index f311550930a..aaab0687ded 100644 --- a/src/mongo/db/repl/topology_coordinator.cpp +++ b/src/mongo/db/repl/topology_coordinator.cpp @@ -61,7 +61,11 @@ namespace mongo { namespace repl { + using std::vector; + +MONGO_FP_DECLARE(forceSyncSourceCandidate); + const Seconds TopologyCoordinator::VoteLease::leaseTime = Seconds(30); // Controls how caught up in replication a secondary with higher priority than the current primary @@ -204,6 +208,41 @@ HostAndPort TopologyCoordinator::chooseNewSyncSource(Date_t now, return HostAndPort(); } + MONGO_FAIL_POINT_BLOCK(forceSyncSourceCandidate, customArgs) { + const auto& data = customArgs.getData(); + const auto hostAndPortElem = data["hostAndPort"]; + if (!hostAndPortElem) { + severe() << "'forceSyncSoureCandidate' parameter set with invalid host and port: " + << data; + fassertFailed(50835); + } + + const auto hostAndPort = HostAndPort(hostAndPortElem.checkAndGetStringData()); + const int syncSourceIndex = _rsConfig.findMemberIndexByHostAndPort(hostAndPort); + if (syncSourceIndex < 0) { + log() << "'forceSyncSourceCandidate' failed due to host and port not in " + "replica set config: " + << hostAndPort.toString(); + fassertFailed(50836); + } + + + if (_memberIsBlacklisted(_rsConfig.getMemberAt(syncSourceIndex), now)) { + log() << "Cannot select a sync source because forced candidate is blacklisted: " + << hostAndPort.toString(); + _syncSource = HostAndPort(); + return _syncSource; + } + + _syncSource = _rsConfig.getMemberAt(syncSourceIndex).getHostAndPort(); + log() << "choosing sync source candidate due to 'forceSyncSourceCandidate' parameter: " + << _syncSource; + std::string msg(str::stream() << "syncing from: " << _syncSource.toString() + << " by 'forceSyncSourceCandidate' parameter"); + setMyHeartbeatMessage(now, msg); + return _syncSource; + } + // if we have a target we've requested to sync from, use it if (_forceSyncSourceIndex != -1) { invariant(_forceSyncSourceIndex < _rsConfig.getNumMembers()); |