summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/sharding/rename_sharded.js18
-rw-r--r--jstests/sharding/shard_collection_basic.js14
-rw-r--r--src/mongo/db/namespace_string.h5
-rw-r--r--src/mongo/db/s/create_collection_coordinator.cpp5
-rw-r--r--src/mongo/db/s/rename_collection_coordinator.cpp4
-rw-r--r--src/mongo/db/s/sharding_ddl_util.cpp14
-rw-r--r--src/mongo/db/s/sharding_ddl_util.h10
-rw-r--r--src/mongo/db/s/sharding_ddl_util_test.cpp55
-rw-r--r--src/mongo/s/catalog/type_chunk.cpp4
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");