diff options
Diffstat (limited to 'jstests')
4 files changed, 175 insertions, 82 deletions
diff --git a/jstests/libs/chunk_manipulation_util.js b/jstests/libs/chunk_manipulation_util.js index 389c3120169..90ea743ecf3 100644 --- a/jstests/libs/chunk_manipulation_util.js +++ b/jstests/libs/chunk_manipulation_util.js @@ -240,8 +240,6 @@ function waitForMigrateStep(shardConnection, stepNumber) { // function runCommandDuringTransferMods( mongos, staticMongod, ns, bounds, fromShard, toShard, cmdFunc) { - let configDB = mongos.getDB('config'); - // Turn on the fail point and wait for moveChunk to hit the fail point. pauseMoveChunkAtStep(fromShard, moveChunkStepNames.startedMoveChunk); let joinMoveChunk = diff --git a/jstests/sharding/index_and_collection_option_propagation.js b/jstests/sharding/index_and_collection_option_propagation.js index 15f61961b0a..3a814ca76e9 100644 --- a/jstests/sharding/index_and_collection_option_propagation.js +++ b/jstests/sharding/index_and_collection_option_propagation.js @@ -134,18 +134,7 @@ checkShardIndexes("idx2", [st.shard0, st.shard1], [st.shard2]); // dropIndex res = st.s.getDB(dbName).getCollection(collName).dropIndex("idx1_1"); assert.commandWorked(res); -// TODO SERVER-44719: Once createIndex is made to check shard versions, after the createIndex -// above, each shard should have refreshed its cache. So the mongos will not need to retry the -// dropIndex here and will not get IndexNotFound from shard0 (which is ignored and causes the -// response from shard0 to be empty). -if (jsTestOptions().mongosBinVersion == "last-stable") { - assert.eq(res.raw[st.shard0.host].ok, 1, tojson(res)); -} else { - // dropIndexes checks shard versions so causes the first try to succeed on shard0 but not - // on shard1. When it retries after the refresh, it fails with IndexNotFound on shard0 - // so the response from shard0 is empty. - assert.eq(undefined, res.raw[st.shard0.host], tojson(res)); -} +assert.eq(res.raw[st.shard0.host].ok, 1, tojson(res)); assert.eq(res.raw[st.shard1.host].ok, 1, tojson(res)); assert.eq(undefined, res.raw[st.shard2.host], tojson(res)); checkShardIndexes("idx1", [], [st.shard0, st.shard1, st.shard2]); diff --git a/jstests/sharding/index_commands_shard_targeting.js b/jstests/sharding/index_commands_shard_targeting.js index 0eaf9d1914f..f0cf3d0386d 100644 --- a/jstests/sharding/index_commands_shard_targeting.js +++ b/jstests/sharding/index_commands_shard_targeting.js @@ -1,11 +1,16 @@ /* - * Test that the index commands send shard versions, and only target the primary - * shard and the shards that have chunks for the collection. + * Test that the index commands send and check shard versions, and only target the primary + * shard and the shards that have chunks for the collection. Also test that the commands fail + * if they are run when the critical section is in progress, and block until the critical + * section is over. * @tags: [requires_fcv_44] */ (function() { "use strict"; +load('jstests/libs/chunk_manipulation_util.js'); +load("jstests/libs/fail_point_util.js"); + /* * Returns the metadata for the collection in the shard's catalog cache. */ @@ -16,6 +21,25 @@ function getMetadataOnShard(shard, ns) { } /* + * Asserts that the collection version for the collection in the shard's catalog cache + * is equal to the given collection version. + */ +function assertCollectionVersionEquals(shard, ns, collectionVersion) { + assert.eq(getMetadataOnShard(shard, ns).collVersion, collectionVersion); +} + +/* + * Asserts that the collection version for the collection in the shard's catalog cache + * is older than the given collection version. + */ +function assertCollectionVersionOlderThan(shard, ns, collectionVersion) { + let shardCollectionVersion = getMetadataOnShard(shard, ns).collVersion; + if (shardCollectionVersion != undefined) { + assert.lt(shardCollectionVersion.t, collectionVersion.t); + } +} + +/* * Asserts that the shard version of the shard in its catalog cache is equal to the * given shard version. */ @@ -24,6 +48,17 @@ function assertShardVersionEquals(shard, ns, shardVersion) { } /* + * Moves the chunk that matches the given query to toShard. Forces fromShard to skip the + * recipient metadata refresh post-migration commit. + */ +function moveChunkNotRefreshRecipient(mongos, ns, fromShard, toShard, findQuery) { + let failPoint = configureFailPoint(fromShard, "doNotRefreshRecipientAfterCommit"); + assert.commandWorked(mongos.adminCommand( + {moveChunk: ns, find: findQuery, to: toShard.shardName, _waitForDelete: true})); + failPoint.off(); +} + +/* * Asserts that the shard has an index for the collection with the given index key. */ function assertIndexExistsOnShard(shard, dbName, collName, targetIndexKey) { @@ -53,21 +88,83 @@ function assertIndexDoesNotExistOnShard(shard, dbName, collName, targetIndexKey) } /* - * Performs chunk operations to make the primary shard (shard0) not own any chunks for collection, - * and only a subset of non-primary shards (shard1 and shard2) own chunks for collection. + * Runs the command after performing chunk operations to make the primary shard (shard0) not own + * any chunks for the collection, and the subset of non-primary shards (shard1 and shard2) that + * own chunks for the collection have stale catalog cache. + * + * Asserts that the command checks shard versions by checking that the shards to refresh their + * cache after the command is run. */ -function setUpShards(st, ns) { +function assertCommandChecksShardVersions(st, dbName, collName, testCase) { + const ns = dbName + "." + collName; + // Move the initial chunk out of the primary shard. - assert.commandWorked(st.s.adminCommand( - {moveChunk: ns, find: {_id: MinKey}, to: st.shard1.shardName, _waitForDelete: true})); + moveChunkNotRefreshRecipient(st.s, ns, st.shard0, st.shard1, {_id: MinKey}); // Split the chunk to create two chunks on shard1. Move one of the chunks to shard2. assert.commandWorked(st.s.adminCommand({split: ns, middle: {_id: 0}})); - assert.commandWorked(st.s.adminCommand( - {moveChunk: ns, find: {_id: 0}, to: st.shard2.shardName, _waitForDelete: true})); + moveChunkNotRefreshRecipient(st.s, ns, st.shard1, st.shard2, {_id: 0}); // Assert that primary shard does not have any chunks for the collection. assertShardVersionEquals(st.shard0, ns, Timestamp(0, 0)); + + const mongosCollectionVersion = st.s.adminCommand({getShardVersion: ns}).version; + + // Assert that besides the latest donor shard (shard1), all shards have stale collection + // version. + assertCollectionVersionOlderThan(st.shard0, ns, mongosCollectionVersion); + assertCollectionVersionEquals(st.shard1, ns, mongosCollectionVersion); + assertCollectionVersionOlderThan(st.shard2, ns, mongosCollectionVersion); + assertCollectionVersionOlderThan(st.shard3, ns, mongosCollectionVersion); + + if (testCase.setUp) { + testCase.setUp(); + } + assert.commandWorked(st.s.getDB(dbName).runCommand(testCase.command)); + + // Assert that primary shard still has stale collection version after the command is run + // because both the shard version in the command and in the shard's cache are UNSHARDED + // (no chunks). + assertCollectionVersionOlderThan(st.shard0, ns, mongosCollectionVersion); + + // Assert that the other shards have the latest collection version after the command is run. + assertCollectionVersionEquals(st.shard1, ns, mongosCollectionVersion); + assertCollectionVersionEquals(st.shard2, ns, mongosCollectionVersion); + assertCollectionVersionEquals(st.shard3, ns, mongosCollectionVersion); +} + +/* + * Runs the command during a chunk migration after the donor enters the read-only phase of the + * critical section. Asserts that the command is blocked behind the critical section. + * + * Assumes that shard0 is the primary shard. + */ +function assertCommandBlocksIfCriticalSectionInProgress( + st, staticMongod, dbName, collName, testCase) { + const ns = dbName + "." + collName; + const fromShard = st.shard0; + const toShard = st.shard1; + + assert.commandWorked(st.s.adminCommand({split: ns, middle: {_id: 0}})); + + // Turn on the fail point and wait for moveChunk to hit the fail point. + pauseMoveChunkAtStep(fromShard, moveChunkStepNames.chunkDataCommitted); + let joinMoveChunk = + moveChunkParallel(staticMongod, st.s.host, {_id: 0}, null, ns, toShard.shardName); + waitForMoveChunkStep(fromShard, moveChunkStepNames.chunkDataCommitted); + + if (testCase.setUp) { + testCase.setUp(); + } + + // Run the command and assert that it eventually times out. + const cmdWithMaxTimeMS = Object.assign({}, testCase.command, {maxTimeMS: 500}); + assert.commandFailedWithCode(st.s.getDB(dbName).runCommand(cmdWithMaxTimeMS), + ErrorCodes.MaxTimeMSExpired); + + // Turn off the fail point and wait for moveChunk to complete. + unpauseMoveChunkAtStep(fromShard, moveChunkStepNames.chunkDataCommitted); + joinMoveChunk(); } const numShards = 4; @@ -87,84 +184,94 @@ const index = { name: "x_1" }; -const expectedTargetedShards = new Set([st.shard0, st.shard1, st.shard2]); -assert.lt(expectedTargetedShards.size, numShards); +const testCases = { + createIndexes: collName => { + return { + command: {createIndexes: collName, indexes: [index]}, + assertCommandRanOnShard: (shard) => { + assertIndexExistsOnShard(shard, dbName, collName, index.key); + }, + assertCommandDidNotRunOnShard: (shard) => { + assertIndexDoesNotExistOnShard(shard, dbName, collName, index.key); + } + }; + }, + dropIndexes: collName => { + return { + command: {dropIndexes: collName, index: index.name}, + setUp: () => { + // Create the index directly on all the shards. + allShards.forEach(function(shard) { + assert.commandWorked(shard.getDB(dbName).runCommand( + {createIndexes: collName, indexes: [index]})); + }); + }, + assertCommandRanOnShard: (shard) => { + assertIndexDoesNotExistOnShard(shard, dbName, collName, index.key); + }, + assertCommandDidNotRunOnShard: (shard) => { + assertIndexExistsOnShard(shard, dbName, collName, index.key); + } + }; + }, + collMod: collName => { + return { + command: {collMod: collName, validator: {x: {$type: "string"}}}, + assertCommandRanOnShard: (shard) => { + assert.commandFailedWithCode( + shard.getCollection(dbName + "." + collName).insert({x: 1}), + ErrorCodes.DocumentValidationFailure); + }, + assertCommandDidNotRunOnShard: (shard) => { + assert.commandWorked(shard.getCollection(dbName + "." + collName).insert({x: 1})); + } + }; + }, +}; assert.commandWorked(st.s.adminCommand({enableSharding: dbName})); st.ensurePrimaryShard(dbName, st.shard0.shardName); -jsTest.log("Test createIndexes command..."); - -(() => { - let testColl = testDB.testCreateIndexes; - let collName = testColl.getName(); - let ns = testColl.getFullName(); - - assert.commandWorked(st.s.adminCommand({shardCollection: ns, key: shardKey})); - setUpShards(st, ns); - assert.commandWorked(testDB.runCommand({createIndexes: collName, indexes: [index]})); - - // Assert that the index exists on the targeted shards but not on the untargeted shards. - allShards.forEach(function(shard) { - if (expectedTargetedShards.has(shard)) { - assertIndexExistsOnShard(shard, dbName, collName, index.key); - } else { - assertIndexDoesNotExistOnShard(shard, dbName, collName, index.key); - } - }); -})(); - -jsTest.log("Test dropIndexes command..."); +// Test that the indexes commands send and check shard vesions, and only target the primary +// shard and the shards that own chunks for the collection. +const expectedTargetedShards = new Set([st.shard0, st.shard1, st.shard2]); +assert.lt(expectedTargetedShards.size, numShards); -(() => { - let testColl = testDB.testDropIndexes; - let collName = testColl.getName(); - let ns = testColl.getFullName(); +for (const command of Object.keys(testCases)) { + jsTest.log(`Testing that ${command} sends and checks shard version...`); + let collName = command; + let ns = dbName + "." + collName; + let testCase = testCases[command](collName); assert.commandWorked(st.s.adminCommand({shardCollection: ns, key: shardKey})); - setUpShards(st, ns); - - // Create the index directly on all the shards. - allShards.forEach(function(shard) { - assert.commandWorked( - shard.getDB(dbName).runCommand({createIndexes: collName, indexes: [index]})); - }); - - // Drop the index. - assert.commandWorked(testDB.runCommand({dropIndexes: collName, index: index.name})); + assertCommandChecksShardVersions(st, dbName, collName, testCase); - // Assert that the index no longer exists on the targeted shards but still exists on the - // untargeted shards. allShards.forEach(function(shard) { if (expectedTargetedShards.has(shard)) { - assertIndexDoesNotExistOnShard(shard, dbName, collName, index.key); + testCase.assertCommandRanOnShard(shard); } else { - assertIndexExistsOnShard(shard, dbName, collName, index.key); + testCase.assertCommandDidNotRunOnShard(shard); } }); -})(); +} -jsTest.log("Test collMod command..."); +// Test that the indexes commands are blocked behind the critical section. +const staticMongod = MongoRunner.runMongod({}); -(() => { - let testColl = testDB.testCollMod; - let collName = testColl.getName(); - let ns = testColl.getFullName(); +for (const command of Object.keys(testCases)) { + jsTest.log(`Testing that ${command} is blocked behind the critical section...`); + let collName = command + "CriticalSection"; + let ns = dbName + "." + collName; + let testCase = testCases[command](collName); assert.commandWorked(st.s.adminCommand({shardCollection: ns, key: shardKey})); - setUpShards(st, ns); - assert.commandWorked(testDB.runCommand({collMod: collName, validator: {x: {$type: "string"}}})); + assertCommandBlocksIfCriticalSectionInProgress(st, staticMongod, dbName, collName, testCase); - // Assert that the targeted shards do document validation, and the untargeted shards do not. allShards.forEach(function(shard) { - if (expectedTargetedShards.has(shard)) { - assert.commandFailedWithCode(shard.getCollection(ns).insert({x: 1}), - ErrorCodes.DocumentValidationFailure); - } else { - assert.commandWorked(shard.getCollection(ns).insert({x: 1})); - } + testCase.assertCommandDidNotRunOnShard(shard); }); -})(); +} st.stop(); +MongoRunner.stopMongod(staticMongod); })(); diff --git a/jstests/sharding/track_unsharded_collections_check_shard_version.js b/jstests/sharding/track_unsharded_collections_check_shard_version.js index 7b530acd2f9..9b37756978c 100644 --- a/jstests/sharding/track_unsharded_collections_check_shard_version.js +++ b/jstests/sharding/track_unsharded_collections_check_shard_version.js @@ -106,7 +106,6 @@ let testCases = { createIndexes: { implicitlyCreatesCollection: true, whenNamespaceIsViewFailsWith: ErrorCodes.CommandNotSupportedOnView, - doesNotCheckShardVersion: true, command: collName => { return {createIndexes: collName, indexes: [{key: {a: 1}, name: "index"}]}; }, |