summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/replsets/standalone_replication_recovery_relaxes_index_constaints.js61
-rw-r--r--src/mongo/db/index_builds_coordinator.cpp3
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.cpp3
3 files changed, 66 insertions, 1 deletions
diff --git a/jstests/replsets/standalone_replication_recovery_relaxes_index_constaints.js b/jstests/replsets/standalone_replication_recovery_relaxes_index_constaints.js
new file mode 100644
index 00000000000..64f7216d815
--- /dev/null
+++ b/jstests/replsets/standalone_replication_recovery_relaxes_index_constaints.js
@@ -0,0 +1,61 @@
+/*
+ * Tests that 'recoverFromOplogAsStandalone' relaxes index constraints. This test is
+ * non-deterministic. If there were a bug, it would still succeed with low probability, but should
+ * never fail without a bug.
+ *
+ * This test only makes sense for storage engines that support recover to stable timestamp.
+ * @tags: [requires_wiredtiger, requires_persistence, requires_journaling, requires_replication,
+ * requires_majority_read_concern]
+ */
+
+(function() {
+"use strict";
+load("jstests/replsets/rslib.js");
+load("jstests/libs/write_concern_util.js");
+
+const name = jsTestName();
+const dbName = name;
+const collName = 'coll';
+const logLevel = tojson({storage: {recovery: 2}, replication: 3});
+
+const rst = new ReplSetTest({
+ nodes: 1,
+});
+
+function getColl(conn) {
+ return conn.getDB(dbName)[collName];
+}
+
+jsTestLog("Initiating as a replica set.");
+rst.startSet();
+rst.initiate();
+let node = rst.getPrimary();
+
+assert.commandWorked(getColl(node).insert({_id: 1}, {writeConcern: {w: 1, j: 1}}));
+assert.commandWorked(getColl(node).createIndex({x: 1}, {unique: true}));
+
+jsTestLog("Running inserts and removes");
+const start = (new Date()).getTime();
+const waitTimeMillis = 5 * 1000;
+const baseNum = 10;
+let iter = 2;
+Random.setRandomSeed();
+while (((new Date()).getTime() - start) < waitTimeMillis) {
+ iter++;
+ const uniqueKey = Math.floor(Random.rand() * baseNum);
+ assert.commandWorked(getColl(node).insert({_id: iter, x: uniqueKey}));
+ assert.commandWorked(getColl(node).remove({_id: iter}));
+}
+
+jsTestLog("Kill the node");
+rst.stop(node, 9, {allowedExitCode: MongoRunner.EXIT_SIGKILL});
+
+jsTestLog("Restart the node with 'recoverFromOplogAsStandalone'");
+node = rst.restart(node, {
+ noReplSet: true,
+ setParameter: {recoverFromOplogAsStandalone: true, logComponentVerbosity: logLevel}
+});
+reconnect(node);
+
+rst.stopSet();
+})();
diff --git a/src/mongo/db/index_builds_coordinator.cpp b/src/mongo/db/index_builds_coordinator.cpp
index 586364fed55..51aeb7d574e 100644
--- a/src/mongo/db/index_builds_coordinator.cpp
+++ b/src/mongo/db/index_builds_coordinator.cpp
@@ -2250,7 +2250,8 @@ IndexBuildsCoordinator::CommitResult IndexBuildsCoordinator::_insertKeysFromSide
// new signal from a new primary because we cannot commit. Note that two-phase index builds can
// retry because a new signal should be received. Single-phase builds will be unable to commit
// and will self-abort.
- bool isMaster = replCoord->canAcceptWritesFor(opCtx, dbAndUUID);
+ bool isMaster = replCoord->canAcceptWritesFor(opCtx, dbAndUUID) &&
+ !replCoord->getSettings().shouldRecoverFromOplogAsStandalone();
if (!isMaster && IndexBuildAction::kCommitQuorumSatisfied == action) {
return CommitResult::kNoLongerPrimary;
}
diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp
index 6a634f09168..943768b94b1 100644
--- a/src/mongo/db/repl/replication_coordinator_impl.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl.cpp
@@ -2867,6 +2867,9 @@ bool ReplicationCoordinatorImpl::isInPrimaryOrSecondaryState_UNSAFE() const {
bool ReplicationCoordinatorImpl::shouldRelaxIndexConstraints(OperationContext* opCtx,
const NamespaceString& ns) {
+ if (ReplSettings::shouldRecoverFromOplogAsStandalone()) {
+ return true;
+ }
return !canAcceptWritesFor(opCtx, ns);
}