diff options
author | Louis Williams <louis.williams@mongodb.com> | 2019-01-15 17:35:43 -0500 |
---|---|---|
committer | Louis Williams <louis.williams@mongodb.com> | 2019-01-17 15:54:40 -0500 |
commit | 9e87f6e272df4f97013dfccc4018efb79f68653a (patch) | |
tree | dc37d192f1821eba066af51c1ad9035a57e6c954 | |
parent | b956c24930044004fb229adc52e34f20d81a36bb (diff) | |
download | mongo-9e87f6e272df4f97013dfccc4018efb79f68653a.tar.gz |
SERVER-37272 Disable hybrid index builds on FCV 4.0
-rw-r--r-- | jstests/multiVersion/hybrid_indexes.js | 109 | ||||
-rw-r--r-- | src/mongo/db/catalog/multi_index_block.cpp | 13 |
2 files changed, 121 insertions, 1 deletions
diff --git a/jstests/multiVersion/hybrid_indexes.js b/jstests/multiVersion/hybrid_indexes.js new file mode 100644 index 00000000000..ecebef1d543 --- /dev/null +++ b/jstests/multiVersion/hybrid_indexes.js @@ -0,0 +1,109 @@ +/** + * Tests that hybrid index builds are only enabled in FCV 4.2. + */ +(function() { + 'use strict'; + + const dbName = "test"; + const collName = "hybrid_indexes"; + const dbpath = MongoRunner.dataPath + "hybrid_indexes"; + + load("jstests/libs/feature_compatibility_version.js"); + + let conn = MongoRunner.runMongod({binVersion: "latest", cleanData: true, dbpath: dbpath}); + let testDB = conn.getDB(dbName); + let testColl = testDB[collName]; + testColl.insert({i: 0}); + assert.commandWorked(conn.adminCommand({setFeatureCompatibilityVersion: "4.0"})); + + let buildIndex = function(config) { + const background = config.background; + const expected = config.expected; + + let res = testDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}); + assert.commandWorked(res); + let fcv = res.version; + + clearRawMongoProgramOutput(); + assert.commandWorked(testDB.adminCommand( + {configureFailPoint: 'hangBeforeIndexBuildOf', mode: "alwaysOn", data: {"i": 0}})); + + let awaitBuild; + if (background) { + awaitBuild = startParallelShell(function() { + assert.commandWorked(db.hybrid_indexes.createIndex({i: 1}, {background: true})); + }, conn.port); + } else { + awaitBuild = startParallelShell(function() { + assert.commandWorked(db.hybrid_indexes.createIndex({i: 1}, {background: false})); + }, conn.port); + } + + let msg = + "starting on test.hybrid_indexes properties: { v: 2, key: { i: 1.0 }, name: \"i_1\"" + + ", ns: \"test.hybrid_indexes\", background: " + background + " } using method: " + + expected; + print(msg); + assert.soon( + () => rawMongoProgramOutput().indexOf(msg) >= 0, "Index build not started", 1000); + assert.soon(() => rawMongoProgramOutput().indexOf("Hanging before index build of i=0") >= 0, + "Index build not hanging", + 1000); + + if (expected === "Background" || expected === "Hybrid") { + assert.commandWorked(testColl.insert({i: 1})); + } else { + assert.commandFailedWithCode( + testDB.runCommand({insert: collName, documents: [{i: 2}], maxTimeMS: 100}), + ErrorCodes.MaxTimeMSExpired); + } + + assert.commandWorked( + testDB.adminCommand({configureFailPoint: 'hangBeforeIndexBuildOf', mode: "off"})); + awaitBuild(); + assert.commandWorked(testColl.dropIndex("i_1")); + }; + + // Test: Background indexes behave as background indexes on FCV 4.0. + + buildIndex({background: true, expected: "Background"}); + + // Test: Foreground indexes behave as foreground idnexes on FCV 4.0. + + buildIndex({background: false, expected: "Foreground"}); + + // Test: Upgrade to FCV 4.2 while a background index build is in progress fails. This is subject + // to change, but characterizes the current behavior. + + clearRawMongoProgramOutput(); + assert.commandWorked(testDB.adminCommand( + {configureFailPoint: 'hangAfterStartingIndexBuildUnlocked', mode: "alwaysOn"})); + + let awaitBuild = startParallelShell(function() { + // This fails because of the unlock failpoint. + assert.commandFailedWithCode(db.hybrid_indexes.createIndex({i: 1}, {background: true}), + ErrorCodes.OperationFailed); + }, conn.port); + + assert.soon(() => rawMongoProgramOutput().indexOf("Hanging index build with no locks") >= 0, + "Index build not hanging"); + + assert.commandFailedWithCode(testDB.adminCommand({setFeatureCompatibilityVersion: "4.2"}), + ErrorCodes.BackgroundOperationInProgressForNamespace); + + assert.commandWorked(testDB.adminCommand( + {configureFailPoint: 'hangAfterStartingIndexBuildUnlocked', mode: "off"})); + awaitBuild(); + + // Test: Background indexes behave as hybrid indexes on FCV 4.2. + + assert.commandWorked(conn.adminCommand({setFeatureCompatibilityVersion: "4.2"})); + + buildIndex({background: true, expected: "Hybrid"}); + + // Test: Foreground indexes behave as hybrid indexes on FCV 4.2. + + buildIndex({background: false, expected: "Hybrid"}); + + MongoRunner.stopMongod(conn); +})(); diff --git a/src/mongo/db/catalog/multi_index_block.cpp b/src/mongo/db/catalog/multi_index_block.cpp index 2dcfe29b4e3..93389f0567b 100644 --- a/src/mongo/db/catalog/multi_index_block.cpp +++ b/src/mongo/db/catalog/multi_index_block.cpp @@ -140,7 +140,18 @@ bool MultiIndexBlock::areHybridIndexBuildsEnabled() { return false; } - // TODO: SERVER-37272 Disable hybrid if in FCV 4.0. + // Hybrid index builds must only be used when in FCV 4.2. This restriction is due to the case + // where an index build starts in FCV 4.0, then continues during an upgrade to FCV 4.2. Because + // prepared transactions yield locks on secondaries, hybrid index builds may miss prepared, but + // uncommitted writes, leading to data corruption. With two-phase index builds, an FCV 4.2-only + // feature, the hybrid build will not complete until the primary writes an oplog entry + // indicating the index build can finish, implying that there are no uncommitted prepared + // transactions. + if (!serverGlobalParams.featureCompatibility.isVersionInitialized() || + serverGlobalParams.featureCompatibility.getVersion() != + ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo42) { + return false; + } return enableHybridIndexBuilds.load(); } |