summaryrefslogtreecommitdiff
path: root/jstests/sharding/update_replace_id.js
diff options
context:
space:
mode:
Diffstat (limited to 'jstests/sharding/update_replace_id.js')
-rw-r--r--jstests/sharding/update_replace_id.js355
1 files changed, 175 insertions, 180 deletions
diff --git a/jstests/sharding/update_replace_id.js b/jstests/sharding/update_replace_id.js
index db8c878674f..0cd19ef1d88 100644
--- a/jstests/sharding/update_replace_id.js
+++ b/jstests/sharding/update_replace_id.js
@@ -12,191 +12,186 @@
* filter.
*/
(function() {
- load("jstests/libs/profiler.js"); // For profilerHas*OrThrow helper functions.
+load("jstests/libs/profiler.js"); // For profilerHas*OrThrow helper functions.
- const st = new ShardingTest({shards: 2, mongos: 1, config: 1, other: {enableBalancer: false}});
+const st = new ShardingTest({shards: 2, mongos: 1, config: 1, other: {enableBalancer: false}});
- const mongosDB = st.s0.getDB(jsTestName());
- const mongosColl = mongosDB.test;
+const mongosDB = st.s0.getDB(jsTestName());
+const mongosColl = mongosDB.test;
- const shard0DB = st.shard0.getDB(jsTestName());
- const shard1DB = st.shard1.getDB(jsTestName());
+const shard0DB = st.shard0.getDB(jsTestName());
+const shard1DB = st.shard1.getDB(jsTestName());
- assert.commandWorked(mongosDB.dropDatabase());
+assert.commandWorked(mongosDB.dropDatabase());
- // Enable sharding on the test DB and ensure its primary is shard0.
- assert.commandWorked(mongosDB.adminCommand({enableSharding: mongosDB.getName()}));
- st.ensurePrimaryShard(mongosDB.getName(), st.shard0.shardName);
+// Enable sharding on the test DB and ensure its primary is shard0.
+assert.commandWorked(mongosDB.adminCommand({enableSharding: mongosDB.getName()}));
+st.ensurePrimaryShard(mongosDB.getName(), st.shard0.shardName);
- // Enables profiling on both shards so that we can verify the targeting behaviour.
- function restartProfiling() {
- for (let shardDB of[shard0DB, shard1DB]) {
- shardDB.setProfilingLevel(0);
- shardDB.system.profile.drop();
- shardDB.setProfilingLevel(2);
- }
- }
-
- function setUpData() {
- // Write a single document to shard0 and verify that it is present.
- mongosColl.insert({_id: -100, a: -100, msg: "not_updated"});
- assert.docEq(shard0DB.test.find({_id: -100}).toArray(),
- [{_id: -100, a: -100, msg: "not_updated"}]);
-
- // Write a document with the same key directly to shard1. This simulates an orphaned
- // document, or the duplicate document which temporarily exists during a chunk migration.
- shard1DB.test.insert({_id: -100, a: -100, msg: "not_updated"});
-
- // Clear and restart the profiler on both shards.
- restartProfiling();
- }
-
- function runReplacementUpdateTestsForHashedShardKey() {
- setUpData();
-
- // Perform a replacement update whose query is an exact match on _id and whose replacement
- // document contains the remainder of the shard key. Despite the fact that the replacement
- // document does not contain the entire shard key, we expect that mongoS will extract the
- // _id from the query and combine it with the replacement doc to target a single shard.
- let writeRes = assert.commandWorked(
- mongosColl.update({_id: -100}, {a: -100, msg: "update_extracted_id_from_query"}));
-
- // Verify that the update did not modify the orphan document.
- assert.docEq(shard1DB.test.find({_id: -100}).toArray(),
- [{_id: -100, a: -100, msg: "not_updated"}]);
- assert.eq(writeRes.nMatched, 1);
- assert.eq(writeRes.nModified, 1);
-
- // Verify that the update only targeted shard0 and that the resulting document appears as
- // expected.
- assert.docEq(mongosColl.find({_id: -100}).toArray(),
- [{_id: -100, a: -100, msg: "update_extracted_id_from_query"}]);
- profilerHasSingleMatchingEntryOrThrow({
- profileDB: shard0DB,
- filter: {op: "update", "command.u.msg": "update_extracted_id_from_query"}
- });
- profilerHasZeroMatchingEntriesOrThrow({
- profileDB: shard1DB,
- filter: {op: "update", "command.u.msg": "update_extracted_id_from_query"}
- });
-
- // Perform an upsert replacement whose query is an exact match on _id and whose replacement
- // doc contains the remainder of the shard key. The _id taken from the query should be used
- // both in targeting the update and in generating the new document.
- writeRes = assert.commandWorked(mongosColl.update(
- {_id: 101}, {a: 101, msg: "upsert_extracted_id_from_query"}, {upsert: true}));
- assert.eq(writeRes.nUpserted, 1);
-
- // Verify that the update only targeted shard1, and that the resulting document appears as
- // expected. At this point in the test we expect shard1 to be stale, because it was the
- // destination shard for the first moveChunk; we therefore explicitly check the profiler for
- // a successful update, i.e. one which did not report a stale config exception.
- assert.docEq(mongosColl.find({_id: 101}).toArray(),
- [{_id: 101, a: 101, msg: "upsert_extracted_id_from_query"}]);
- assert.docEq(shard1DB.test.find({_id: 101}).toArray(),
- [{_id: 101, a: 101, msg: "upsert_extracted_id_from_query"}]);
- profilerHasZeroMatchingEntriesOrThrow({
- profileDB: shard0DB,
- filter: {op: "update", "command.u.msg": "upsert_extracted_id_from_query"}
- });
- profilerHasSingleMatchingEntryOrThrow({
- profileDB: shard1DB,
- filter: {
- op: "update",
- "command.u.msg": "upsert_extracted_id_from_query",
- errName: {$exists: false}
- }
- });
+// Enables profiling on both shards so that we can verify the targeting behaviour.
+function restartProfiling() {
+ for (let shardDB of [shard0DB, shard1DB]) {
+ shardDB.setProfilingLevel(0);
+ shardDB.system.profile.drop();
+ shardDB.setProfilingLevel(2);
}
-
- function runReplacementUpdateTestsForCompoundShardKey() {
- setUpData();
-
- // Perform a replacement update whose query is an exact match on _id and whose replacement
- // document contains the remainder of the shard key. Despite the fact that the replacement
- // document does not contain the entire shard key, we expect that mongoS will extract the
- // _id from the query and combine it with the replacement doc to target a single shard.
- let writeRes = assert.commandWorked(
- mongosColl.update({_id: -100}, {a: -100, msg: "update_extracted_id_from_query"}));
-
- // Verify that the update did not modify the orphan document.
- assert.docEq(shard1DB.test.find({_id: -100}).toArray(),
- [{_id: -100, a: -100, msg: "not_updated"}]);
- assert.eq(writeRes.nMatched, 1);
- assert.eq(writeRes.nModified, 1);
-
- // Verify that the update only targeted shard0 and that the resulting document appears as
- // expected.
- assert.docEq(mongosColl.find({_id: -100}).toArray(),
- [{_id: -100, a: -100, msg: "update_extracted_id_from_query"}]);
- profilerHasSingleMatchingEntryOrThrow({
- profileDB: shard0DB,
- filter: {op: "update", "command.u.msg": "update_extracted_id_from_query"}
- });
- profilerHasZeroMatchingEntriesOrThrow({
- profileDB: shard1DB,
- filter: {op: "update", "command.u.msg": "update_extracted_id_from_query"}
- });
-
- // An upsert whose query doesn't have full shard key will fail.
- assert.commandFailedWithCode(
- mongosColl.update(
- {_id: 101}, {a: 101, msg: "upsert_extracted_id_from_query"}, {upsert: true}),
- ErrorCodes.ShardKeyNotFound);
-
- // Verify that the document did not perform any writes.
- assert.docEq(mongosColl.find({_id: 101}).itcount(), 0);
-
- // Verify that an update whose query contains an exact match on _id but whose replacement
- // doc does not contain all other shard key fields will be rejected by mongoS.
- writeRes = assert.commandFailedWithCode(
- mongosColl.update({_id: -100, a: -100}, {msg: "update_failed_missing_shard_key_field"}),
- ErrorCodes.ShardKeyNotFound);
-
- // Check that the existing document remains unchanged, and that the update did not reach
- // either shard per their respective profilers.
- assert.docEq(mongosColl.find({_id: -100, a: -100}).toArray(),
- [{_id: -100, a: -100, msg: "update_extracted_id_from_query"}]);
- profilerHasZeroMatchingEntriesOrThrow({
- profileDB: shard0DB,
- filter: {op: "update", "command.u.msg": "update_failed_missing_shard_key_field"}
- });
- profilerHasZeroMatchingEntriesOrThrow({
- profileDB: shard1DB,
- filter: {op: "update", "command.u.msg": "update_failed_missing_shard_key_field"}
- });
-
- // Verify that an upsert whose query contains an exact match on _id but whose replacement
- // document does not contain all other shard key fields will be rejected by mongoS, since it
- // does not contain an exact shard key match.
- writeRes = assert.commandFailedWithCode(
- mongosColl.update({_id: 200, a: 200}, {msg: "upsert_targeting_failed"}, {upsert: true}),
- ErrorCodes.ShardKeyNotFound);
- profilerHasZeroMatchingEntriesOrThrow({
- profileDB: shard0DB,
- filter: {op: "update", "command.u.msg": "upsert_targeting_failed"}
- });
- profilerHasZeroMatchingEntriesOrThrow({
- profileDB: shard1DB,
- filter: {op: "update", "command.u.msg": "upsert_targeting_failed"}
- });
- assert.eq(mongosColl.find({_id: 200, a: 200}).itcount(), 0);
- }
-
- // Shard the test collection on {_id: 1, a: 1}, split it into two chunks, and migrate one of
- // these to the second shard.
- st.shardColl(
- mongosColl, {_id: 1, a: 1}, {_id: 0, a: 0}, {_id: 1, a: 1}, mongosDB.getName(), true);
-
- // Run the replacement behaviour tests that are relevant to a compound key that includes _id.
- runReplacementUpdateTestsForCompoundShardKey();
-
- // Drop and reshard the collection on {_id: "hashed"}, which will autosplit across both shards.
- assert(mongosColl.drop());
- mongosDB.adminCommand({shardCollection: mongosColl.getFullName(), key: {_id: "hashed"}});
-
- // Run the replacement behaviour tests relevant to a collection sharded on {_id: "hashed"}.
- runReplacementUpdateTestsForHashedShardKey();
-
- st.stop();
+}
+
+function setUpData() {
+ // Write a single document to shard0 and verify that it is present.
+ mongosColl.insert({_id: -100, a: -100, msg: "not_updated"});
+ assert.docEq(shard0DB.test.find({_id: -100}).toArray(),
+ [{_id: -100, a: -100, msg: "not_updated"}]);
+
+ // Write a document with the same key directly to shard1. This simulates an orphaned
+ // document, or the duplicate document which temporarily exists during a chunk migration.
+ shard1DB.test.insert({_id: -100, a: -100, msg: "not_updated"});
+
+ // Clear and restart the profiler on both shards.
+ restartProfiling();
+}
+
+function runReplacementUpdateTestsForHashedShardKey() {
+ setUpData();
+
+ // Perform a replacement update whose query is an exact match on _id and whose replacement
+ // document contains the remainder of the shard key. Despite the fact that the replacement
+ // document does not contain the entire shard key, we expect that mongoS will extract the
+ // _id from the query and combine it with the replacement doc to target a single shard.
+ let writeRes = assert.commandWorked(
+ mongosColl.update({_id: -100}, {a: -100, msg: "update_extracted_id_from_query"}));
+
+ // Verify that the update did not modify the orphan document.
+ assert.docEq(shard1DB.test.find({_id: -100}).toArray(),
+ [{_id: -100, a: -100, msg: "not_updated"}]);
+ assert.eq(writeRes.nMatched, 1);
+ assert.eq(writeRes.nModified, 1);
+
+ // Verify that the update only targeted shard0 and that the resulting document appears as
+ // expected.
+ assert.docEq(mongosColl.find({_id: -100}).toArray(),
+ [{_id: -100, a: -100, msg: "update_extracted_id_from_query"}]);
+ profilerHasSingleMatchingEntryOrThrow({
+ profileDB: shard0DB,
+ filter: {op: "update", "command.u.msg": "update_extracted_id_from_query"}
+ });
+ profilerHasZeroMatchingEntriesOrThrow({
+ profileDB: shard1DB,
+ filter: {op: "update", "command.u.msg": "update_extracted_id_from_query"}
+ });
+
+ // Perform an upsert replacement whose query is an exact match on _id and whose replacement
+ // doc contains the remainder of the shard key. The _id taken from the query should be used
+ // both in targeting the update and in generating the new document.
+ writeRes = assert.commandWorked(mongosColl.update(
+ {_id: 101}, {a: 101, msg: "upsert_extracted_id_from_query"}, {upsert: true}));
+ assert.eq(writeRes.nUpserted, 1);
+
+ // Verify that the update only targeted shard1, and that the resulting document appears as
+ // expected. At this point in the test we expect shard1 to be stale, because it was the
+ // destination shard for the first moveChunk; we therefore explicitly check the profiler for
+ // a successful update, i.e. one which did not report a stale config exception.
+ assert.docEq(mongosColl.find({_id: 101}).toArray(),
+ [{_id: 101, a: 101, msg: "upsert_extracted_id_from_query"}]);
+ assert.docEq(shard1DB.test.find({_id: 101}).toArray(),
+ [{_id: 101, a: 101, msg: "upsert_extracted_id_from_query"}]);
+ profilerHasZeroMatchingEntriesOrThrow({
+ profileDB: shard0DB,
+ filter: {op: "update", "command.u.msg": "upsert_extracted_id_from_query"}
+ });
+ profilerHasSingleMatchingEntryOrThrow({
+ profileDB: shard1DB,
+ filter: {
+ op: "update",
+ "command.u.msg": "upsert_extracted_id_from_query",
+ errName: {$exists: false}
+ }
+ });
+}
+
+function runReplacementUpdateTestsForCompoundShardKey() {
+ setUpData();
+
+ // Perform a replacement update whose query is an exact match on _id and whose replacement
+ // document contains the remainder of the shard key. Despite the fact that the replacement
+ // document does not contain the entire shard key, we expect that mongoS will extract the
+ // _id from the query and combine it with the replacement doc to target a single shard.
+ let writeRes = assert.commandWorked(
+ mongosColl.update({_id: -100}, {a: -100, msg: "update_extracted_id_from_query"}));
+
+ // Verify that the update did not modify the orphan document.
+ assert.docEq(shard1DB.test.find({_id: -100}).toArray(),
+ [{_id: -100, a: -100, msg: "not_updated"}]);
+ assert.eq(writeRes.nMatched, 1);
+ assert.eq(writeRes.nModified, 1);
+
+ // Verify that the update only targeted shard0 and that the resulting document appears as
+ // expected.
+ assert.docEq(mongosColl.find({_id: -100}).toArray(),
+ [{_id: -100, a: -100, msg: "update_extracted_id_from_query"}]);
+ profilerHasSingleMatchingEntryOrThrow({
+ profileDB: shard0DB,
+ filter: {op: "update", "command.u.msg": "update_extracted_id_from_query"}
+ });
+ profilerHasZeroMatchingEntriesOrThrow({
+ profileDB: shard1DB,
+ filter: {op: "update", "command.u.msg": "update_extracted_id_from_query"}
+ });
+
+ // An upsert whose query doesn't have full shard key will fail.
+ assert.commandFailedWithCode(
+ mongosColl.update(
+ {_id: 101}, {a: 101, msg: "upsert_extracted_id_from_query"}, {upsert: true}),
+ ErrorCodes.ShardKeyNotFound);
+
+ // Verify that the document did not perform any writes.
+ assert.docEq(mongosColl.find({_id: 101}).itcount(), 0);
+
+ // Verify that an update whose query contains an exact match on _id but whose replacement
+ // doc does not contain all other shard key fields will be rejected by mongoS.
+ writeRes = assert.commandFailedWithCode(
+ mongosColl.update({_id: -100, a: -100}, {msg: "update_failed_missing_shard_key_field"}),
+ ErrorCodes.ShardKeyNotFound);
+
+ // Check that the existing document remains unchanged, and that the update did not reach
+ // either shard per their respective profilers.
+ assert.docEq(mongosColl.find({_id: -100, a: -100}).toArray(),
+ [{_id: -100, a: -100, msg: "update_extracted_id_from_query"}]);
+ profilerHasZeroMatchingEntriesOrThrow({
+ profileDB: shard0DB,
+ filter: {op: "update", "command.u.msg": "update_failed_missing_shard_key_field"}
+ });
+ profilerHasZeroMatchingEntriesOrThrow({
+ profileDB: shard1DB,
+ filter: {op: "update", "command.u.msg": "update_failed_missing_shard_key_field"}
+ });
+
+ // Verify that an upsert whose query contains an exact match on _id but whose replacement
+ // document does not contain all other shard key fields will be rejected by mongoS, since it
+ // does not contain an exact shard key match.
+ writeRes = assert.commandFailedWithCode(
+ mongosColl.update({_id: 200, a: 200}, {msg: "upsert_targeting_failed"}, {upsert: true}),
+ ErrorCodes.ShardKeyNotFound);
+ profilerHasZeroMatchingEntriesOrThrow(
+ {profileDB: shard0DB, filter: {op: "update", "command.u.msg": "upsert_targeting_failed"}});
+ profilerHasZeroMatchingEntriesOrThrow(
+ {profileDB: shard1DB, filter: {op: "update", "command.u.msg": "upsert_targeting_failed"}});
+ assert.eq(mongosColl.find({_id: 200, a: 200}).itcount(), 0);
+}
+
+// Shard the test collection on {_id: 1, a: 1}, split it into two chunks, and migrate one of
+// these to the second shard.
+st.shardColl(mongosColl, {_id: 1, a: 1}, {_id: 0, a: 0}, {_id: 1, a: 1}, mongosDB.getName(), true);
+
+// Run the replacement behaviour tests that are relevant to a compound key that includes _id.
+runReplacementUpdateTestsForCompoundShardKey();
+
+// Drop and reshard the collection on {_id: "hashed"}, which will autosplit across both shards.
+assert(mongosColl.drop());
+mongosDB.adminCommand({shardCollection: mongosColl.getFullName(), key: {_id: "hashed"}});
+
+// Run the replacement behaviour tests relevant to a collection sharded on {_id: "hashed"}.
+runReplacementUpdateTestsForHashedShardKey();
+
+st.stop();
})(); \ No newline at end of file