diff options
author | Benety Goh <benety@mongodb.com> | 2019-11-17 17:29:43 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-11-17 17:29:43 +0000 |
commit | fa6a120e11a01504ff01378231a5ece470af082d (patch) | |
tree | 094ea952d10bad18396ec4187e87ad4f3648f497 | |
parent | b835ac2048d8d759412c26a08bd83d112003d49a (diff) | |
download | mongo-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.js | 62 | ||||
-rw-r--r-- | src/mongo/db/commands/create_indexes.cpp | 20 |
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; } |