summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenety Goh <benety@mongodb.com>2019-11-17 17:29:43 +0000
committerevergreen <evergreen@mongodb.com>2019-11-17 17:29:43 +0000
commitfa6a120e11a01504ff01378231a5ece470af082d (patch)
tree094ea952d10bad18396ec4187e87ad4f3648f497
parentb835ac2048d8d759412c26a08bd83d112003d49a (diff)
downloadmongo-fa6a120e11a01504ff01378231a5ece470af082d.tar.gz
SERVER-44397 two phase index builds with unique indexes do not fail over on stepdown
-rw-r--r--jstests/noPassthrough/index_stepdown_unique.js62
-rw-r--r--src/mongo/db/commands/create_indexes.cpp20
2 files changed, 80 insertions, 2 deletions
diff --git a/jstests/noPassthrough/index_stepdown_unique.js b/jstests/noPassthrough/index_stepdown_unique.js
new file mode 100644
index 00000000000..cbdbe6408fc
--- /dev/null
+++ b/jstests/noPassthrough/index_stepdown_unique.js
@@ -0,0 +1,62 @@
+/**
+ * Confirms that unique index builds on a primary are aborted when the node steps down during the
+ * collection scan phase. This applies to both two phase and single phase index builds.
+ * @tags: [requires_replication]
+ */
+(function() {
+"use strict";
+
+load('jstests/libs/check_log.js');
+load('jstests/noPassthrough/libs/index_build.js');
+
+const rst = new ReplSetTest({
+ nodes: [
+ {},
+ {
+ // Disallow elections on secondary.
+ rsConfig: {
+ priority: 0,
+ votes: 0,
+ },
+ },
+ ]
+});
+const nodes = rst.startSet();
+rst.initiate();
+
+const primary = rst.getPrimary();
+const testDB = primary.getDB('test');
+const coll = testDB.getCollection('test');
+
+assert.commandWorked(coll.insert({a: 1}));
+
+IndexBuildTest.pauseIndexBuilds(primary);
+
+const createIdx =
+ IndexBuildTest.startIndexBuild(primary, coll.getFullName(), {a: 1}, {unique: true});
+
+// When the index build starts, find its op id.
+const opId = IndexBuildTest.waitForIndexBuildToScanCollection(testDB, coll.getName(), 'a_1');
+
+IndexBuildTest.assertIndexBuildCurrentOpContents(testDB, opId);
+
+try {
+ // Step down the primary.
+ assert.commandWorked(primary.adminCommand({replSetStepDown: 60, force: true}));
+} finally {
+ IndexBuildTest.resumeIndexBuilds(primary);
+}
+
+// Wait for the index build to stop.
+IndexBuildTest.waitForIndexBuildToStop(testDB);
+
+const exitCode = createIdx({checkExitSuccess: false});
+assert.neq(0, exitCode, 'expected shell to exit abnormally due to index build being terminated');
+
+// Wait for the IndexBuildCoordinator thread, not the command thread, to report the index build
+// as failed.
+checkLog.contains(primary, '[IndexBuildsCoordinatorMongod-0] Index build failed: ');
+IndexBuildTest.assertIndexes(coll, 1, ['_id_']);
+
+rst.stopSet();
+})();
diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp
index 68bcb6de670..94636ac0247 100644
--- a/src/mongo/db/commands/create_indexes.cpp
+++ b/src/mongo/db/commands/create_indexes.cpp
@@ -398,6 +398,20 @@ Collection* getOrCreateCollection(OperationContext* opCtx,
}
/**
+ * Returns true if index specs include any unique indexes. Due to uniqueness constraints set up at
+ * the start of the index build, we are not able to support failing over a two phase index build on
+ * a unique index to a new primary on stepdown.
+ */
+bool containsUniqueIndexes(const std::vector<BSONObj>& specs) {
+ for (const auto& spec : specs) {
+ if (spec["unique"].trueValue()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
* Creates indexes using the given specs for the mobile storage engine.
* TODO(SERVER-42513): Remove this function.
*/
@@ -741,7 +755,8 @@ bool runCreateIndexesWithCoordinator(OperationContext* opCtx,
// If this node is no longer a primary, the index build will continue to run in the
// background and will complete when this node receives a commitIndexBuild oplog entry
// from the new primary.
- if (indexBuildsCoord->supportsTwoPhaseIndexBuild() &&
+ // TODO(SERVER-44654): re-enable failover support for unique indexes.
+ if (indexBuildsCoord->supportsTwoPhaseIndexBuild() && !containsUniqueIndexes(specs) &&
ErrorCodes::InterruptedDueToReplStateChange == interruptionEx.code()) {
log() << "Index build continuing in background: " << buildUUID;
throw;
@@ -766,7 +781,8 @@ bool runCreateIndexesWithCoordinator(OperationContext* opCtx,
// The index build will continue to run in the background and will complete when this
// node receives a commitIndexBuild oplog entry from the new primary.
- if (indexBuildsCoord->supportsTwoPhaseIndexBuild()) {
+ // TODO(SERVER-44654): re-enable failover support for unique indexes.
+ if (indexBuildsCoord->supportsTwoPhaseIndexBuild() && !containsUniqueIndexes(specs)) {
log() << "Index build continuing in background: " << buildUUID;
throw;
}