summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJudah Schvimer <judah@mongodb.com>2018-04-30 09:54:38 -0400
committerJudah Schvimer <judah@mongodb.com>2018-04-30 09:55:20 -0400
commitbcd6d4e85d9e817892a4433219d1099f1532b413 (patch)
tree0086cbc6d9143921350e2bc190abd7d0d03d15f6
parentc734bb32c3237f67a99c47ca3835967909c2e2d1 (diff)
downloadmongo-bcd6d4e85d9e817892a4433219d1099f1532b413.tar.gz
SERVER-34465 Add a testing parameter to choose a permanent sync source
-rw-r--r--jstests/replsets/force_sync_source_candidate.js40
-rw-r--r--src/mongo/db/repl/topology_coordinator.cpp37
2 files changed, 77 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 fe52da99b42..5ca660a2012 100644
--- a/src/mongo/db/repl/topology_coordinator.cpp
+++ b/src/mongo/db/repl/topology_coordinator.cpp
@@ -63,6 +63,8 @@
namespace mongo {
namespace repl {
+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
@@ -205,6 +207,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());