diff options
-rw-r--r-- | jstests/sharding/rename_sharded.js | 18 | ||||
-rw-r--r-- | jstests/sharding/shard_collection_basic.js | 14 | ||||
-rw-r--r-- | src/mongo/db/namespace_string.h | 5 | ||||
-rw-r--r-- | src/mongo/db/s/create_collection_coordinator.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/s/rename_collection_coordinator.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_ddl_util.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_ddl_util.h | 10 | ||||
-rw-r--r-- | src/mongo/db/s/sharding_ddl_util_test.cpp | 55 | ||||
-rw-r--r-- | src/mongo/s/catalog/type_chunk.cpp | 4 |
9 files changed, 103 insertions, 26 deletions
diff --git a/jstests/sharding/rename_sharded.js b/jstests/sharding/rename_sharded.js index 53bc2b3c778..23dd313393b 100644 --- a/jstests/sharding/rename_sharded.js +++ b/jstests/sharding/rename_sharded.js @@ -47,7 +47,7 @@ function testRename(st, dbName, toNs, dropTarget, mustFail) { assert(chunk0.shard != chunk1.shard, 'Chunks expected to be on different shards'); const toColl = mongos.getCollection(toNs); - assert.eq(db.to.find({x: 0}).itcount(), 1, 'Expected exactly one document on the shard'); + assert.eq(toColl.find({x: 0}).itcount(), 1, 'Expected exactly one document on the shard'); assert.eq(toColl.find({x: 2}).itcount(), 1, 'Expected exactly one document on the shard'); // Validate the correctness of the collections metadata in the catalog cache on shards @@ -231,4 +231,20 @@ const mongos = st.s0; assert.commandFailed(fromColl.renameCollection(toNs.split('.')[1], false /* dropTarget*/)); } +// Rename to target collection with very a long name +{ + const dbName = 'testRenameToCollectionWithVeryLongName'; + + const testDB = st.rs0.getPrimary().getDB(dbName); + const fcvDoc = testDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}); + if (MongoRunner.compareBinVersions(fcvDoc.featureCompatibilityVersion.version, '5.3') >= 0) { + const longEnoughNs = dbName + '.' + + 'x'.repeat(235 - dbName.length - 1); + testRename(st, dbName, longEnoughNs, false /* dropTarget */, false /* mustFail */); + + const tooLongNs = longEnoughNs + 'x'; + testRename(st, dbName, tooLongNs, false /* dropTarget */, true /* mustFail */); + } +} + st.stop(); diff --git a/jstests/sharding/shard_collection_basic.js b/jstests/sharding/shard_collection_basic.js index b14d059cd4c..e31ba479ef5 100644 --- a/jstests/sharding/shard_collection_basic.js +++ b/jstests/sharding/shard_collection_basic.js @@ -67,6 +67,20 @@ assert.commandFailed(mongos.adminCommand({shardCollection: 'foo', key: {_id: 1}} assert.commandFailed(mongos.adminCommand({shardCollection: kDbName + '.foo', key: "aaa"})); +const testDB = st.rs0.getPrimary().getDB(kDbName); +const fcvDoc = testDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}); +if (MongoRunner.compareBinVersions(fcvDoc.featureCompatibilityVersion.version, '5.3') >= 0) { + jsTestLog('Verify namespace length limit.'); + + const longEnoughNs = kDbName + '.' + + 'x'.repeat(235 - kDbName.length - 1); + assert.commandWorked(mongos.adminCommand({shardCollection: longEnoughNs, key: {_id: 1}})); + + const tooLongNs = longEnoughNs + 'x'; + assert.commandFailedWithCode(mongos.adminCommand({shardCollection: tooLongNs, key: {_id: 1}}), + ErrorCodes.InvalidNamespace); +} + jsTestLog('shardCollection may only be run against admin database.'); assert.commandFailed( mongos.getDB('test').runCommand({shardCollection: kDbName + '.foo', key: {_id: 1}})); diff --git a/src/mongo/db/namespace_string.h b/src/mongo/db/namespace_string.h index 339c62ce23f..c9fc9e85c6a 100644 --- a/src/mongo/db/namespace_string.h +++ b/src/mongo/db/namespace_string.h @@ -52,6 +52,11 @@ public: constexpr static size_t MaxNSCollectionLenFCV42 = 120U; constexpr static size_t MaxNsCollectionLen = 255; + // The maximum namespace length of sharded collections is less than that of unsharded ones since + // the namespace of the cached chunks metadata, local to each shard, is composed by the + // namespace of the related sharded collection (i.e., config.cache.chunks.<ns>). + constexpr static size_t MaxNsShardedCollectionLen = 235; // 255 - len(ChunkType::ShardNSPrefix) + // Reserved system namespaces // Namespace for the admin database diff --git a/src/mongo/db/s/create_collection_coordinator.cpp b/src/mongo/db/s/create_collection_coordinator.cpp index b10eee0a6a3..916f04b3257 100644 --- a/src/mongo/db/s/create_collection_coordinator.cpp +++ b/src/mongo/db/s/create_collection_coordinator.cpp @@ -610,6 +610,11 @@ void CreateCollectionCoordinator::_checkCommandArguments(OperationContext* opCtx str::stream() << "sharding not enabled for db " << nss().db(), dbEnabledForSharding); + uassert(ErrorCodes::InvalidNamespace, + str::stream() << "Namespace too long. Namespace: " << nss() + << " Max: " << NamespaceString::MaxNsShardedCollectionLen, + nss().size() <= NamespaceString::MaxNsShardedCollectionLen); + if (nss().db() == NamespaceString::kConfigDb) { // Only allowlisted collections in config may be sharded (unless we are in test mode) uassert(ErrorCodes::IllegalOperation, diff --git a/src/mongo/db/s/rename_collection_coordinator.cpp b/src/mongo/db/s/rename_collection_coordinator.cpp index 8fdf34f02d5..655faf971f4 100644 --- a/src/mongo/db/s/rename_collection_coordinator.cpp +++ b/src/mongo/db/s/rename_collection_coordinator.cpp @@ -208,8 +208,8 @@ ExecutorFuture<void> RenameCollectionCoordinator::_runImpl( _doc.setTargetUUID(getCollectionUUID( opCtx, toNss, optTargetCollType, /*throwNotFound*/ false)); - sharding_ddl_util::checkShardedRenamePreconditions( - opCtx, toNss, _doc.getDropTarget()); + sharding_ddl_util::checkRenamePreconditions( + opCtx, sourceIsSharded, toNss, _doc.getDropTarget()); { AutoGetCollection coll{opCtx, toNss, MODE_IS}; diff --git a/src/mongo/db/s/sharding_ddl_util.cpp b/src/mongo/db/s/sharding_ddl_util.cpp index 4d6eb5e8016..ea068f5d654 100644 --- a/src/mongo/db/s/sharding_ddl_util.cpp +++ b/src/mongo/db/s/sharding_ddl_util.cpp @@ -351,9 +351,17 @@ void shardedRenameMetadata(OperationContext* opCtx, opCtx, CollectionType::ConfigNS, fromCollType.toBSON(), writeConcern)); } -void checkShardedRenamePreconditions(OperationContext* opCtx, - const NamespaceString& toNss, - const bool dropTarget) { +void checkRenamePreconditions(OperationContext* opCtx, + bool sourceIsSharded, + const NamespaceString& toNss, + const bool dropTarget) { + if (sourceIsSharded) { + uassert(ErrorCodes::InvalidNamespace, + str::stream() << "Namespace of target collection too long. Namespace: " << toNss + << " Max: " << NamespaceString::MaxNsShardedCollectionLen, + toNss.size() <= NamespaceString::MaxNsShardedCollectionLen); + } + auto catalogClient = Grid::get(opCtx)->catalogClient(); if (!dropTarget) { // Check that the sharded target collection doesn't exist diff --git a/src/mongo/db/s/sharding_ddl_util.h b/src/mongo/db/s/sharding_ddl_util.h index 1cfba12be74..afe53cd5ee6 100644 --- a/src/mongo/db/s/sharding_ddl_util.h +++ b/src/mongo/db/s/sharding_ddl_util.h @@ -104,13 +104,15 @@ void shardedRenameMetadata(OperationContext* opCtx, const WriteConcernOptions& writeConcern); /** - * Ensures rename preconditions for sharded collections are met: + * Ensures rename preconditions for collections are met: + * - Check that the namespace of the destination collection is not too long * - Check that `dropTarget` is true if the destination collection exists * - Check that no tags exist for the destination collection */ -void checkShardedRenamePreconditions(OperationContext* opCtx, - const NamespaceString& toNss, - bool dropTarget); +void checkRenamePreconditions(OperationContext* opCtx, + bool sourceIsSharded, + const NamespaceString& toNss, + bool dropTarget); /** * Throws if the DB primary shards of the provided namespaces differs. diff --git a/src/mongo/db/s/sharding_ddl_util_test.cpp b/src/mongo/db/s/sharding_ddl_util_test.cpp index eacd1372f5f..044e11ccda9 100644 --- a/src/mongo/db/s/sharding_ddl_util_test.cpp +++ b/src/mongo/db/s/sharding_ddl_util_test.cpp @@ -198,14 +198,16 @@ TEST_F(ShardingDDLUtilTest, ShardedRenameMetadata) { } } -// Test all combinations of sharded rename acceptable preconditions: -// (1) Target collection doesn't exist and doesn't have no associated tags -// (2) Target collection exists and doesn't have associated tags -TEST_F(ShardingDDLUtilTest, ShardedRenamePreconditionsAreMet) { +// Test all combinations of rename acceptable preconditions: +// (1) Namespace of target collection is not too long +// (2) Target collection doesn't exist and doesn't have no associated tags +// (3) Target collection exists and doesn't have associated tags +TEST_F(ShardingDDLUtilTest, RenamePreconditionsAreMet) { auto opCtx = operationContext(); // No exception is thrown if the TO collection does not exist and has no associated tags - sharding_ddl_util::checkShardedRenamePreconditions(opCtx, kToNss, false /* dropTarget */); + sharding_ddl_util::checkRenamePreconditions( + opCtx, false /* sourceIsSharded */, kToNss, false /* dropTarget */); // Initialize a chunk ChunkVersion chunkVersion(1, 1, OID::gen(), Timestamp(2, 1)); @@ -221,10 +223,31 @@ TEST_F(ShardingDDLUtilTest, ShardedRenamePreconditionsAreMet) { // Initialize the sharded TO collection setupCollection(kToNss, KeyPattern(BSON("x" << 1)), {chunk}); - sharding_ddl_util::checkShardedRenamePreconditions(opCtx, kToNss, true /* dropTarget */); + sharding_ddl_util::checkRenamePreconditions( + opCtx, false /* sourceIsSharded */, kToNss, true /* dropTarget */); } -TEST_F(ShardingDDLUtilTest, ShardedRenamePreconditionsTargetCollectionExists) { +TEST_F(ShardingDDLUtilTest, RenamePreconditionsTargetNamespaceIsTooLong) { + auto opCtx{operationContext()}; + + const std::string dbName{"test"}; + + // Check that no exception is thrown if the namespace of the target collection is long enough + const NamespaceString longEnoughNss{ + dbName + "." + + std::string(NamespaceString::MaxNsShardedCollectionLen - dbName.length() - 1, 'x')}; + sharding_ddl_util::checkRenamePreconditions( + opCtx, true /* sourceIsSharded */, longEnoughNss, false /* dropTarget */); + + // Check that an exception is thrown if the namespace of the target collection is too long + const NamespaceString tooLongNss{longEnoughNss.ns() + 'x'}; + ASSERT_THROWS_CODE(sharding_ddl_util::checkRenamePreconditions( + opCtx, true /* sourceIsSharded */, tooLongNss, false /* dropTarget */), + AssertionException, + ErrorCodes::InvalidNamespace); +} + +TEST_F(ShardingDDLUtilTest, RenamePreconditionsTargetCollectionExists) { auto opCtx = operationContext(); // Initialize a chunk @@ -242,13 +265,13 @@ TEST_F(ShardingDDLUtilTest, ShardedRenamePreconditionsTargetCollectionExists) { setupCollection(kToNss, KeyPattern(BSON("x" << 1)), {chunk}); // Check that an exception is thrown if the target collection exists and dropTarget is not set - ASSERT_THROWS_CODE( - sharding_ddl_util::checkShardedRenamePreconditions(opCtx, kToNss, false /* dropTarget */), - AssertionException, - ErrorCodes::NamespaceExists); + ASSERT_THROWS_CODE(sharding_ddl_util::checkRenamePreconditions( + opCtx, false /* sourceIsSharded */, kToNss, false /* dropTarget */), + AssertionException, + ErrorCodes::NamespaceExists); } -TEST_F(ShardingDDLUtilTest, ShardedRenamePreconditionTargetCollectionHasTags) { +TEST_F(ShardingDDLUtilTest, RenamePreconditionTargetCollectionHasTags) { auto opCtx = operationContext(); // Associate a tag to the target collection @@ -260,10 +283,10 @@ TEST_F(ShardingDDLUtilTest, ShardedRenamePreconditionTargetCollectionHasTags) { ASSERT_OK(insertToConfigCollection(operationContext(), TagsType::ConfigNS, tagDoc.toBSON())); // Check that an exception is thrown if some tag is associated to the target collection - ASSERT_THROWS_CODE( - sharding_ddl_util::checkShardedRenamePreconditions(opCtx, kToNss, false /* dropTarget */), - AssertionException, - ErrorCodes::CommandFailed); + ASSERT_THROWS_CODE(sharding_ddl_util::checkRenamePreconditions( + opCtx, false /* sourceIsSharded */, kToNss, false /* dropTarget */), + AssertionException, + ErrorCodes::CommandFailed); } } // namespace diff --git a/src/mongo/s/catalog/type_chunk.cpp b/src/mongo/s/catalog/type_chunk.cpp index d29d55cbb69..944a6b6df4c 100644 --- a/src/mongo/s/catalog/type_chunk.cpp +++ b/src/mongo/s/catalog/type_chunk.cpp @@ -48,6 +48,10 @@ namespace mongo { const NamespaceString ChunkType::ConfigNS("config.chunks"); + +// The final namespace of the cached chunks metadata is composed of the namespace of the related +// sharded collection (i.e., config.cache.chunks.<ns>). As a result, the maximum namespace length of +// sharded collections is reduced. See NamespaceString::MaxNsShardedCollectionLen. const std::string ChunkType::ShardNSPrefix = "config.cache.chunks."; const BSONField<OID> ChunkType::name("_id"); |