summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjannaerin <golden.janna@gmail.com>2019-06-26 17:11:20 -0400
committerjannaerin <golden.janna@gmail.com>2019-06-27 17:22:42 -0400
commitd960519275aba7e6611294903cd2b5156710a73b (patch)
tree98483c9fafe0e1fea3a9c09bfe6de4fded4a0f04
parent644fc54e18049e0737ae1621aec5eb7afbe1934f (diff)
downloadmongo-d960519275aba7e6611294903cd2b5156710a73b.tar.gz
SERVER-41825 Remove FCV checks related to mutable shard key fields
-rw-r--r--jstests/multiVersion/update_shard_key_disallowed_fcv40.js273
-rw-r--r--src/mongo/db/exec/update_stage.cpp23
2 files changed, 5 insertions, 291 deletions
diff --git a/jstests/multiVersion/update_shard_key_disallowed_fcv40.js b/jstests/multiVersion/update_shard_key_disallowed_fcv40.js
deleted file mode 100644
index ee7648679ab..00000000000
--- a/jstests/multiVersion/update_shard_key_disallowed_fcv40.js
+++ /dev/null
@@ -1,273 +0,0 @@
-// Test that shard key fields cannot be updated when one or more shards is in FCV 4.0.
-// @tags: [uses_transactions, uses_multi_shard_transaction]
-
-(function() {
- "use strict";
-
- load("jstests/libs/feature_compatibility_version.js");
- load("jstests/sharding/libs/update_shard_key_helpers.js");
-
- let st = new ShardingTest({
- shards: {rs0: {nodes: 3, binVersion: "latest"}, rs1: {nodes: 3, binVersion: "latest"}},
- mongos: 1,
- other: {mongosOptions: {binVersion: "latest"}, configOptions: {binVersion: "latest"}}
- });
- let mongos = st.s0;
- let kDbName = "test";
- let collName = "foo";
- let ns = kDbName + "." + collName;
-
- assert.commandWorked(mongos.adminCommand({enableSharding: kDbName}));
- st.ensurePrimaryShard(kDbName, st.shard0.shardName);
-
- function shardCollectionAndMoveChunks(docsToInsert, shardKey, splitDoc, moveDoc) {
- for (let i = 0; i < docsToInsert.length; i++) {
- assert.commandWorked(mongos.getDB(kDbName).foo.insert(docsToInsert[i]));
- }
-
- assert.commandWorked(mongos.getDB(kDbName).foo.createIndex(shardKey));
- assert.commandWorked(mongos.adminCommand({shardCollection: ns, key: shardKey}));
- assert.commandWorked(mongos.adminCommand({split: ns, find: splitDoc}));
- assert.commandWorked(
- mongos.adminCommand({moveChunk: ns, find: moveDoc, to: st.shard1.shardName}));
-
- assert.commandWorked(mongos.adminCommand({flushRouterConfig: 1}));
- st.rs0.getPrimary().adminCommand({_flushRoutingTableCacheUpdates: ns});
- st.rs1.getPrimary().adminCommand({_flushRoutingTableCacheUpdates: ns});
- st.rs0.getPrimary().adminCommand({_flushDatabaseCacheUpdates: kDbName});
- st.rs1.getPrimary().adminCommand({_flushDatabaseCacheUpdates: kDbName});
- }
-
- function assertCannotUpdateShardKey(isMixedCluster) {
- // ------------------------------------------------
- // Test changes to shard key run as retryable write
- // ------------------------------------------------
- let session = st.s.startSession({retryWrites: true});
- let sessionDB = session.getDatabase(kDbName);
-
- // Updates to full shard key
- shardCollectionMoveChunks(
- st, kDbName, ns, {x: 1}, [{x: 30}, {x: 50}, {x: 80}], {x: 50}, {x: 80});
- cleanupOrphanedDocs(st, ns);
-
- // Assert that updating the shard key when the doc would remain on the same shard fails for
- // both modify and replacement updates
- assert.writeError(sessionDB.foo.update({x: 80}, {$set: {x: 100}}));
- assert.writeError(sessionDB.foo.update({x: 80}, {x: 100}));
- assert.throws(function() {
- sessionDB.foo.findAndModify({query: {x: 80}, update: {$set: {x: 100}}});
- });
- assert.throws(function() {
- sessionDB.foo.findAndModify({query: {x: 80}, update: {x: 100}});
- });
-
- // Assert that updating the shard key when the doc would move shards fails for both modify
- // and replacement updates.
- assert.writeError(sessionDB.foo.update({x: 80}, {$set: {x: 3}}));
- assert.commandFailedWithCode(sessionDB.foo.update({x: 80}, {x: 3}),
- [ErrorCodes.ImmutableField, ErrorCodes.InvalidOptions]);
- assert.eq(1, mongos.getDB(kDbName).foo.find({x: 80}).itcount());
- assert.eq(0, mongos.getDB(kDbName).foo.find({x: 3}).itcount());
-
- assert.throws(function() {
- sessionDB.foo.findAndModify({query: {x: 80}, update: {$set: {x: 3}}});
- });
- assert.throws(function() {
- sessionDB.foo.findAndModify({query: {x: 80}, update: {x: 3}});
- });
-
- mongos.getDB(kDbName).foo.drop();
-
- // Updates to partial shard key
- shardCollectionMoveChunks(st,
- kDbName,
- ns,
- {x: 1, y: 1},
- [{x: 30, y: 4}, {x: 50, y: 50}, {x: 80, y: 100}],
- {x: 50, y: 50},
- {x: 80, y: 100});
- cleanupOrphanedDocs(st, ns);
-
- // Assert that updating the shard key when the doc would remain on the same shard fails for
- // both modify and replacement updates
- assert.writeError(sessionDB.foo.update({x: 80}, {$set: {x: 100}}));
- assert.writeError(sessionDB.foo.update({x: 80}, {x: 100}));
- assert.throws(function() {
- sessionDB.foo.findAndModify({query: {x: 80}, update: {$set: {x: 100}}});
- });
- assert.throws(function() {
- sessionDB.foo.findAndModify({query: {x: 80}, update: {x: 100}});
- });
-
- // Assert that updating the shard key when the doc would move shards fails for both modify
- // and replacement updates
- assert.writeError(sessionDB.foo.update({x: 80}, {$set: {x: 3}}));
- assert.writeError(sessionDB.foo.update({x: 80}, {x: 3}));
- assert.throws(function() {
- sessionDB.foo.findAndModify({query: {x: 80}, update: {$set: {x: 3}}});
- });
- assert.throws(function() {
- sessionDB.foo.findAndModify({query: {x: 80}, update: {x: 3}});
- });
-
- mongos.getDB(kDbName).foo.drop();
-
- // -----------------------------------------------
- // Test changes to shard key run in a transaction
- // -----------------------------------------------
- session = st.s.startSession();
- sessionDB = session.getDatabase(kDbName);
-
- // Updates to full shard key
- shardCollectionMoveChunks(
- st, kDbName, ns, {x: 1}, [{x: 30}, {x: 50}, {x: 80}], {x: 50}, {x: 80});
- cleanupOrphanedDocs(st, ns);
-
- // Assert that updating the shard key when the doc would remain on the same shard fails for
- // both modify and replacement updates
- session.startTransaction();
- assert.writeError(sessionDB.foo.update({x: 80}, {$set: {x: 100}}));
- assert.commandFailedWithCode(session.abortTransaction_forTesting(),
- ErrorCodes.NoSuchTransaction);
-
- session.startTransaction();
- assert.throws(function() {
- sessionDB.foo.findAndModify({query: {x: 80}, update: {x: 100}});
- });
- assert.commandFailedWithCode(session.abortTransaction_forTesting(),
- ErrorCodes.NoSuchTransaction);
-
- mongos.getDB(kDbName).foo.drop();
-
- if (isMixedCluster) {
- // Assert that updating the shard key when the doc would move shards fails on commit
- // because one of the participants is not in FCV 4.2. If the original write is a
- // retryable write, the write will fail when mongos attempts to run commitTransaction.
- // If the original write is part of a transaction, the write itself will complete
- // successfully, but the transaction will fail to commit.
-
- // Retryable write - updates to full shard key
- session = st.s.startSession({retryWrites: true});
- sessionDB = session.getDatabase(kDbName);
-
- shardCollectionMoveChunks(
- st, kDbName, ns, {x: 1}, [{x: 30}, {x: 50}, {x: 80}], {x: 50}, {x: 80});
- cleanupOrphanedDocs(st, ns);
-
- // Doc will move shards
- assert.writeError(sessionDB.foo.update({x: 30}, {$set: {x: 100}}));
- assert.throws(function() {
- sessionDB.foo.findAndModify({query: {x: 30}, update: {$set: {x: 100}}});
- });
-
- // Doc will remain on the same shard. Because shard 0 is on FCV 4.2, these should
- // complete successfully.
- sessionDB.foo.findAndModify({query: {x: 30}, update: {$set: {x: 5}}});
- st.rs0.awaitReplication();
- assert.eq(1, st.rs0.getPrimary().getDB(kDbName).foo.find({x: 5}).itcount());
- assert.eq(1, st.rs0.getSecondaries()[0].getDB(kDbName).foo.find({x: 5}).itcount());
- assert.eq(0, st.rs0.getPrimary().getDB(kDbName).foo.find({x: 30}).itcount());
- assert.eq(0, st.rs0.getSecondaries()[0].getDB(kDbName).foo.find({x: 30}).itcount());
-
- sessionDB.foo.findAndModify({query: {x: 5}, update: {x: 10}});
- st.rs0.awaitReplication();
- assert.eq(0, st.rs0.getPrimary().getDB(kDbName).foo.find({x: 5}).itcount());
- assert.eq(0, st.rs0.getSecondaries()[0].getDB(kDbName).foo.find({x: 5}).itcount());
- assert.eq(1, st.rs0.getPrimary().getDB(kDbName).foo.find({x: 10}).itcount());
- assert.eq(1, st.rs0.getSecondaries()[0].getDB(kDbName).foo.find({x: 10}).itcount());
-
- assert.commandWorked(sessionDB.foo.update({x: 10}, {$set: {x: 25}}));
- st.rs0.awaitReplication();
- assert.eq(1, st.rs0.getPrimary().getDB(kDbName).foo.find({x: 25}).itcount());
- assert.eq(1, st.rs0.getSecondaries()[0].getDB(kDbName).foo.find({x: 25}).itcount());
- assert.eq(0, st.rs0.getPrimary().getDB(kDbName).foo.find({x: 10}).itcount());
- assert.eq(0, st.rs0.getSecondaries()[0].getDB(kDbName).foo.find({x: 10}).itcount());
-
- assert.commandWorked(sessionDB.foo.update({x: 25}, {x: 3}));
- st.rs0.awaitReplication();
- assert.eq(0, st.rs0.getPrimary().getDB(kDbName).foo.find({x: 25}).itcount());
- assert.eq(0, st.rs0.getSecondaries()[0].getDB(kDbName).foo.find({x: 25}).itcount());
- assert.eq(1, st.rs0.getPrimary().getDB(kDbName).foo.find({x: 3}).itcount());
- assert.eq(1, st.rs0.getSecondaries()[0].getDB(kDbName).foo.find({x: 3}).itcount());
-
- mongos.getDB(kDbName).foo.drop();
-
- // Retryable write - updates to partial shard key
- shardCollectionMoveChunks(st,
- kDbName,
- ns,
- {x: 1, y: 1},
- [{x: 30, y: 4}, {x: 50, y: 50}, {x: 80, y: 100}],
- {x: 50, y: 50},
- {x: 80, y: 100});
- cleanupOrphanedDocs(st, ns);
-
- assert.writeError(sessionDB.foo.update({x: 30}, {$set: {x: 100}}));
- assert.throws(function() {
- sessionDB.foo.findAndModify({query: {x: 30}, update: {x: 100}});
- });
-
- mongos.getDB(kDbName).foo.drop();
-
- // Transactional writes
- session = st.s.startSession();
- sessionDB = session.getDatabase(kDbName);
-
- shardCollectionMoveChunks(
- st, kDbName, ns, {x: 1}, [{x: 10}, {x: 30}, {x: 50}, {x: 80}], {x: 50}, {x: 80});
- cleanupOrphanedDocs(st, ns);
-
- session.startTransaction();
- assert.commandWorked(sessionDB.foo.update({x: 30}, {$set: {x: 100}}));
- assert.commandFailed(session.commitTransaction_forTesting());
-
- assert.eq(1, mongos.getDB(kDbName).foo.find({x: 30}).itcount());
- assert.eq(0, mongos.getDB(kDbName).foo.find({x: 100}).itcount());
-
- session.startTransaction();
- sessionDB.foo.findAndModify({query: {x: 30}, update: {x: 100}});
- assert.commandFailed(session.commitTransaction_forTesting());
-
- assert.eq(1, mongos.getDB(kDbName).foo.find({x: 30}).itcount());
- assert.eq(0, mongos.getDB(kDbName).foo.find({x: 100}).itcount());
-
- // Doc will remain on the same shard. Because shard 0 is on FCV 4.2, this should
- // complete successfully.
- session.startTransaction();
- sessionDB.foo.findAndModify({query: {x: 10}, update: {x: 1}});
- assert.commandWorked(sessionDB.foo.update({x: 30}, {$set: {x: 5}}));
- assert.commandWorked(session.commitTransaction_forTesting());
- st.rs0.awaitReplication();
-
- assert.eq(0, st.rs0.getPrimary().getDB(kDbName).foo.find({x: 30}).itcount());
- assert.eq(0, st.rs0.getSecondaries()[0].getDB(kDbName).foo.find({x: 30}).itcount());
- assert.eq(0, st.rs0.getPrimary().getDB(kDbName).foo.find({x: 10}).itcount());
- assert.eq(0, st.rs0.getSecondaries()[0].getDB(kDbName).foo.find({x: 10}).itcount());
- assert.eq(1, st.rs0.getPrimary().getDB(kDbName).foo.find({x: 5}).itcount());
- assert.eq(1, st.rs0.getSecondaries()[0].getDB(kDbName).foo.find({x: 5}).itcount());
- assert.eq(1, st.rs0.getPrimary().getDB(kDbName).foo.find({x: 1}).itcount());
- assert.eq(1, st.rs0.getSecondaries()[0].getDB(kDbName).foo.find({x: 1}).itcount());
-
- mongos.getDB(kDbName).foo.drop();
- }
- }
-
- // Check that updating the shard key fails when all shards are in FCV 4.0
- assert.commandWorked(st.s.getDB("admin").runCommand({setFeatureCompatibilityVersion: "4.0"}));
- checkFCV(st.configRS.getPrimary().getDB("admin"), "4.0");
- checkFCV(st.rs0.getPrimary().getDB("admin"), "4.0");
- checkFCV(st.rs1.getPrimary().getDB("admin"), "4.0");
-
- assertCannotUpdateShardKey(false);
-
- // Check that updating the shard key fails when shard0 is in FCV 4.2 but shard 1 is in FCV 4.0
- assert.commandWorked(
- st.rs0.getPrimary().getDB("admin").runCommand({setFeatureCompatibilityVersion: "4.2"}));
- checkFCV(st.configRS.getPrimary().getDB("admin"), "4.0");
- checkFCV(st.rs0.getPrimary().getDB("admin"), "4.2");
- checkFCV(st.rs1.getPrimary().getDB("admin"), "4.0");
-
- assertCannotUpdateShardKey(true);
-
- st.stop();
-})();
diff --git a/src/mongo/db/exec/update_stage.cpp b/src/mongo/db/exec/update_stage.cpp
index 7f079f27d9f..85bce89da40 100644
--- a/src/mongo/db/exec/update_stage.cpp
+++ b/src/mongo/db/exec/update_stage.cpp
@@ -213,10 +213,6 @@ BSONObj UpdateStage::transformAndUpdate(const Snapshotted<BSONObj>& oldObj, Reco
bool docWasModified = false;
- const auto isFCV42 = serverGlobalParams.featureCompatibility.isVersionInitialized() &&
- serverGlobalParams.featureCompatibility.getVersion() ==
- ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo42;
-
auto* const css = CollectionShardingState::get(getOpCtx(), collection()->ns());
auto metadata = css->getCurrentMetadata();
Status status = Status::OK();
@@ -224,8 +220,7 @@ BSONObj UpdateStage::transformAndUpdate(const Snapshotted<BSONObj>& oldObj, Reco
const bool isInsert = false;
FieldRefSet immutablePaths;
if (getOpCtx()->writesAreReplicated() && !request->isFromMigration()) {
- if (metadata->isSharded() &&
- (!OperationShardingState::isOperationVersioned(getOpCtx()) || !isFCV42)) {
+ if (metadata->isSharded() && !OperationShardingState::isOperationVersioned(getOpCtx())) {
auto& immutablePathsVector = metadata->getKeyPatternFields();
immutablePaths.fillFrom(
transitional_tools_do_not_use::unspool_vector(immutablePathsVector));
@@ -323,7 +318,7 @@ BSONObj UpdateStage::transformAndUpdate(const Snapshotted<BSONObj>& oldObj, Reco
Snapshotted<RecordData> snap(oldObj.snapshotId(), oldRec);
- if (isFCV42 && metadata->isSharded() && _shouldCheckForShardKeyUpdate) {
+ if (metadata->isSharded() && _shouldCheckForShardKeyUpdate) {
bool changesShardKeyOnSameNode =
checkUpdateChangesShardKeyFields(metadata, oldObj);
if (changesShardKeyOnSameNode && !args.preImageDoc) {
@@ -351,7 +346,7 @@ BSONObj UpdateStage::transformAndUpdate(const Snapshotted<BSONObj>& oldObj, Reco
newObj.objsize() <= BSONObjMaxUserSize);
if (!request->isExplain()) {
- if (isFCV42 && metadata->isSharded() && _shouldCheckForShardKeyUpdate) {
+ if (metadata->isSharded() && _shouldCheckForShardKeyUpdate) {
bool changesShardKeyOnSameNode =
checkUpdateChangesShardKeyFields(metadata, oldObj);
if (changesShardKeyOnSameNode && !args.preImageDoc) {
@@ -412,13 +407,8 @@ BSONObj UpdateStage::applyUpdateOpsForInsert(OperationContext* opCtx,
auto* const css = CollectionShardingState::get(opCtx, ns);
auto metadata = css->getCurrentMetadata();
- const auto isFCV42 = serverGlobalParams.featureCompatibility.isVersionInitialized() &&
- serverGlobalParams.featureCompatibility.getVersion() ==
- ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo42;
-
FieldRefSet immutablePaths;
- if (metadata->isSharded() &&
- (!OperationShardingState::isOperationVersioned(opCtx) || !isFCV42)) {
+ if (metadata->isSharded() && !OperationShardingState::isOperationVersioned(opCtx)) {
auto& immutablePathsVector = metadata->getKeyPatternFields();
immutablePaths.fillFrom(
transitional_tools_do_not_use::unspool_vector(immutablePathsVector));
@@ -594,13 +584,10 @@ void UpdateStage::doInsert() {
// fields in the 'q' field belong to this shard, but those in the 'u' field do not. In this case
// we need to throw so that MongoS can target the insert to the correct shard.
if (_shouldCheckForShardKeyUpdate) {
- const auto isFCV42 = serverGlobalParams.featureCompatibility.isVersionInitialized() &&
- serverGlobalParams.featureCompatibility.getVersion() ==
- ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo42;
auto* const css = CollectionShardingState::get(getOpCtx(), collection()->ns());
const auto& metadata = css->getCurrentMetadata();
- if (isFCV42 && metadata->isSharded()) {
+ if (metadata->isSharded()) {
const ShardKeyPattern shardKeyPattern(metadata->getKeyPattern());
auto newShardKey = shardKeyPattern.extractShardKeyFromDoc(newObj);