summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Polato <paolo.polato@mongodb.com>2022-07-18 07:55:47 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-07-18 08:26:16 +0000
commit05f813248226f37f497021765b29b41295c5a60c (patch)
tree551316560c380739631356a645db9e61f70c06bd
parente1ed094bd449e59d3dcb3c83c2e05af3da08830c (diff)
downloadmongo-05f813248226f37f497021765b29b41295c5a60c.tar.gz
SERVER-67633 Use the RecoverableCriticalSection to synch createCollection() with Sharding DDL ops
-rw-r--r--jstests/sharding/create_new_collections_prepared_transactions.js16
-rw-r--r--jstests/sharding/timeseries_sharding_admin_commands.js10
-rw-r--r--src/mongo/db/catalog/create_collection.cpp8
-rw-r--r--src/mongo/s/commands/cluster_create_cmd.cpp38
4 files changed, 52 insertions, 20 deletions
diff --git a/jstests/sharding/create_new_collections_prepared_transactions.js b/jstests/sharding/create_new_collections_prepared_transactions.js
index d38d2dbfabd..52aa344971f 100644
--- a/jstests/sharding/create_new_collections_prepared_transactions.js
+++ b/jstests/sharding/create_new_collections_prepared_transactions.js
@@ -9,6 +9,8 @@
(function() {
"use strict";
+load("jstests/libs/auto_retry_transaction_in_sharding.js");
+
const dbNameShard0 = "test";
const dbNameShard2 = "testOther";
const collName = "foo";
@@ -44,16 +46,20 @@ let doc2 = st.s.getDB(dbNameShard2).getCollection(collName).findOne({_id: 4});
assert.eq(doc2._id, 4);
jsTest.log("Testing collection creation in a cross-shard write transaction.");
-session.startTransaction({writeConcern: {w: "majority"}});
-assert.commandWorked(sessionDBShard0.createCollection(newCollName));
-assert.commandWorked(sessionDBShard2.createCollection(newCollName));
-
+const txnOptions = {
+ writeConcern: {w: "majority"}
+};
+session.startTransaction(txnOptions);
+retryOnceOnTransientAndRestartTxnOnMongos(session, () => {
+ assert.commandWorked(sessionDBShard0.createCollection(newCollName));
+ assert.commandWorked(sessionDBShard2.createCollection(newCollName));
+}, txnOptions);
assert.commandFailedWithCode(session.commitTransaction_forTesting(),
ErrorCodes.OperationNotSupportedInTransaction);
jsTest.log("Testing collection creation in a single-shard write transaction.");
// TODO (SERVER-48340): Re-enable the single-write-shard transaction commit optimization.
-session.startTransaction({writeConcern: {w: "majority"}});
+session.startTransaction(txnOptions);
assert.commandWorked(sessionDBShard0.createCollection(newCollName));
doc2 = sessionDBShard2.getCollection(collName).findOne({_id: 4});
assert.eq(doc2._id, 4);
diff --git a/jstests/sharding/timeseries_sharding_admin_commands.js b/jstests/sharding/timeseries_sharding_admin_commands.js
index 5e6177bb4b0..0219d8c103e 100644
--- a/jstests/sharding/timeseries_sharding_admin_commands.js
+++ b/jstests/sharding/timeseries_sharding_admin_commands.js
@@ -150,13 +150,17 @@ function assertRangeMatch(savedRange, paramRange) {
check({[metaField]: 1}, {[metaField]: 10}, true);
})();
-// Check shardingState commands will return collection info in bucket namespace.
+// Check shardingState commands returns the expected collection info about buckets & view nss.
(function checkShardingStateCommand() {
createTimeSeriesColl(
{index: {[metaField]: 1, [timeField]: 1}, shardKey: {[metaField]: 1, [timeField]: 1}});
const shardingStateRes = mongo.getPrimaryShard(dbName).adminCommand({shardingState: 1});
- const shardingStateColls = Object.keys(shardingStateRes.versions);
- assert(shardingStateColls.includes(bucketNss) && !shardingStateColls.includes(viewNss));
+ const shardingStateColls = shardingStateRes.versions;
+ const bucketNssIsSharded = (bucketNss in shardingStateColls &&
+ timestampCmp(shardingStateColls[bucketNss], Timestamp(0, 0)) !== 0);
+ const viewNssIsSharded = (viewNss in shardingStateColls &&
+ timestampCmp(shardingStateColls[viewNss], Timestamp(0, 0)) !== 0);
+ assert(bucketNssIsSharded && !viewNssIsSharded);
dropTimeSeriesColl();
})();
diff --git a/src/mongo/db/catalog/create_collection.cpp b/src/mongo/db/catalog/create_collection.cpp
index 9b1e61cbc9c..1202eb66696 100644
--- a/src/mongo/db/catalog/create_collection.cpp
+++ b/src/mongo/db/catalog/create_collection.cpp
@@ -53,6 +53,7 @@
#include "mongo/db/ops/insert.h"
#include "mongo/db/query/collation/collator_factory_interface.h"
#include "mongo/db/repl/replication_coordinator.h"
+#include "mongo/db/s/collection_sharding_state.h"
#include "mongo/db/storage/storage_parameters_gen.h"
#include "mongo/db/timeseries/timeseries_index_schema_conversion_functions.h"
#include "mongo/db/timeseries/timeseries_options.h"
@@ -173,6 +174,8 @@ Status _createView(OperationContext* opCtx,
str::stream() << "Not primary while creating collection " << nss);
}
+ CollectionShardingState::get(opCtx, nss)->checkShardVersionOrThrow(opCtx);
+
if (collectionOptions.changeStreamPreAndPostImagesOptions.getEnabled()) {
return Status(ErrorCodes::InvalidOptions,
"option not supported on a view: changeStreamPreAndPostImages");
@@ -332,6 +335,8 @@ Status _createTimeseries(OperationContext* opCtx,
str::stream() << "Not primary while creating collection " << ns);
}
+ CollectionShardingState::get(opCtx, bucketsNs)->checkShardVersionOrThrow(opCtx);
+
WriteUnitOfWork wuow(opCtx);
AutoStatsTracker bucketsStatsTracker(
opCtx,
@@ -413,6 +418,7 @@ Status _createTimeseries(OperationContext* opCtx,
str::stream() << "Not primary while creating collection " << ns};
}
+ CollectionShardingState::get(opCtx, ns)->checkShardVersionOrThrow(opCtx);
_createSystemDotViewsIfNecessary(opCtx, db);
@@ -527,6 +533,8 @@ Status _createCollection(OperationContext* opCtx,
str::stream() << "Not primary while creating collection " << nss);
}
+ CollectionShardingState::get(opCtx, nss)->checkShardVersionOrThrow(opCtx);
+
WriteUnitOfWork wunit(opCtx);
AutoStatsTracker statsTracker(
diff --git a/src/mongo/s/commands/cluster_create_cmd.cpp b/src/mongo/s/commands/cluster_create_cmd.cpp
index eba994dfb74..05cec7b1606 100644
--- a/src/mongo/s/commands/cluster_create_cmd.cpp
+++ b/src/mongo/s/commands/cluster_create_cmd.cpp
@@ -130,18 +130,32 @@ public:
// Manually forward the create collection command to the primary shard.
const auto dbInfo =
uassertStatusOK(Grid::get(opCtx)->catalogCache()->getDatabase(opCtx, dbName));
- auto response = uassertStatusOK(
- executeCommandAgainstDatabasePrimary(
- opCtx,
- dbName,
- dbInfo,
- applyReadWriteConcern(
- opCtx,
- this,
- CommandHelpers::filterCommandRequestForPassthrough(cmd.toBSON({}))),
- ReadPreferenceSetting(ReadPreference::PrimaryOnly),
- Shard::RetryPolicy::kIdempotent)
- .swResponse);
+ auto response = [&] {
+ auto cmdToSend = cmd.toBSON({});
+ cmdToSend = CommandHelpers::filterCommandRequestForPassthrough(cmd.toBSON({}));
+ cmdToSend = applyReadWriteConcern(opCtx, this, cmdToSend);
+ // If the DB primary resides on a shard, forward the create command applying the
+ // metadata that characterise an unsharded CRUD request according to the versioning
+ // protocol (the received DB version + an "UNSHARDED" shard version): this will
+ // guarantee that sharded DDL ops targeting the same namespace won't be executed in
+ // parallel.
+ // If the DB primary is hosted by the config server, apply the original metadata.
+ if (dbInfo->getPrimary() != ShardId::kConfigServerId) {
+ cmdToSend = appendShardVersion(cmdToSend, ChunkVersion::UNSHARDED());
+ }
+ cmdToSend = appendDbVersionIfPresent(cmdToSend, dbInfo);
+
+ std::vector<AsyncRequestsSender::Request> arsRequests{
+ AsyncRequestsSender::Request(dbInfo->getPrimary(), cmdToSend)};
+
+ auto arsResponses =
+ gatherResponses(opCtx,
+ dbName,
+ ReadPreferenceSetting(ReadPreference::PrimaryOnly),
+ Shard::RetryPolicy::kIdempotent,
+ arsRequests);
+ return uassertStatusOK(arsResponses.front().swResponse);
+ }();
const auto createStatus = mongo::getStatusFromCommandResult(response.data);
if (createStatus == ErrorCodes::NamespaceExists &&