summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
Diffstat (limited to 'jstests')
-rw-r--r--jstests/libs/chunk_manipulation_util.js2
-rw-r--r--jstests/sharding/index_and_collection_option_propagation.js13
-rw-r--r--jstests/sharding/index_commands_shard_targeting.js241
-rw-r--r--jstests/sharding/track_unsharded_collections_check_shard_version.js1
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"}]};
},