Skip to content

Commit 7277c7c

Browse files
GWlodarekevergreen
authored andcommitted
SERVER-41745 Collections with names longer than 120 characters will be gated to FCV v4.4
1 parent 97664ef commit 7277c7c

File tree

6 files changed

+169
-1
lines changed

6 files changed

+169
-1
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/**
2+
* Tests the FCV for long collection names.
3+
*
4+
* On 4.2 and below, the maximum fully qualified collection name is 120 characters or less
5+
* (which includes the database name).
6+
*
7+
* In this multi version test, we ensure that we can create long collection names on the 4.4 binary
8+
* while the FCV document is set to 4.4. Restarting with long collection names present on a 4.2
9+
* binary should not crash the server. Users would need to manually remove or rename the long
10+
* collection names prior to downgrading. Additionally, we should be prevented from creating long
11+
* collection names when using FCV 4.2 on a 4.4 binary.
12+
*/
13+
(function() {
14+
'use strict';
15+
load('jstests/libs/feature_compatibility_version.js');
16+
17+
const dbName = 'test';
18+
const renameDbName = 'rename_test';
19+
const shortCollName = 'short_collection';
20+
const longCollName = 'long_collection' +
21+
'a'.repeat(8192);
22+
const longCollNameRename = 'long_collection' +
23+
'b'.repeat(8192);
24+
25+
const dbpath = MongoRunner.dataPath + 'long_collection_names';
26+
resetDbpath(dbpath);
27+
28+
const mongodOptions42 =
29+
Object.extend({binVersion: 'last-stable'}, {dbpath: dbpath, cleanData: false});
30+
const mongodOptions44 = Object.extend({binVersion: 'latest'}, {dbpath: dbpath, cleanData: false});
31+
32+
/**
33+
* Start up with the latest binary and ensure that long collection names can be created while
34+
* using FCV 4.4.
35+
*/
36+
let conn = MongoRunner.runMongod(mongodOptions44);
37+
assert.neq(null, conn, 'mongod was unable to start with version ' + tojson(mongodOptions44));
38+
39+
let testDb = conn.getDB(dbName);
40+
41+
assert.commandWorked(testDb.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
42+
43+
// Create two collections, one with a short name and the other with a long name.
44+
assert.commandWorked(testDb.createCollection(shortCollName));
45+
assert.commandWorked(testDb.createCollection(longCollName));
46+
47+
// Rename a short collection name to a long collection name within the same database.
48+
assert.commandWorked(testDb.adminCommand(
49+
{renameCollection: dbName + '.' + shortCollName, to: dbName + '.' + longCollNameRename}));
50+
51+
assert.eq(true, testDb.getCollection(longCollNameRename).drop());
52+
assert.commandWorked(testDb.createCollection(shortCollName));
53+
54+
// Rename a short collection name to a long collection name in a different database.
55+
assert.commandWorked(testDb.adminCommand(
56+
{renameCollection: dbName + '.' + shortCollName, to: renameDbName + '.' + longCollNameRename}));
57+
58+
assert.eq(true, testDb.getSiblingDB(renameDbName).getCollection(longCollNameRename).drop());
59+
assert.commandWorked(testDb.createCollection(shortCollName));
60+
61+
MongoRunner.stopMongod(conn);
62+
63+
/**
64+
* Restarting with a 4.2 binary with FCV 4.4 shouldn't startup nor crash.
65+
*/
66+
let restartOpts42 = Object.extend(mongodOptions42, {restart: true});
67+
conn = MongoRunner.runMongod(restartOpts42);
68+
assert.eq(null, conn, 'mongod was able to start with version ' + tojson(restartOpts42));
69+
70+
/**
71+
* Restart with the 4.4 binary to set the FCV to 4.2.
72+
*/
73+
let restartOpts44 = Object.extend(mongodOptions44, {restart: true});
74+
conn = MongoRunner.runMongod(restartOpts44);
75+
assert.neq(null, conn, 'mongod was unable to start with version ' + tojson(restartOpts44));
76+
77+
testDb = conn.getDB(dbName);
78+
assert.commandWorked(testDb.adminCommand({setFeatureCompatibilityVersion: lastStableFCV}));
79+
MongoRunner.stopMongod(conn);
80+
81+
/**
82+
* Restart with the 4.2 binary while in FCV 4.2 with long collection names present. This shouldn't
83+
* crash the server.
84+
*/
85+
conn = MongoRunner.runMongod(restartOpts42);
86+
assert.neq(null, conn, 'mongod was unable to start with version ' + tojson(restartOpts42));
87+
88+
testDb = conn.getDB(dbName);
89+
90+
// Ensure we have the proper collections.
91+
let collNames = testDb.getCollectionNames();
92+
93+
assert.eq(true, collNames.includes(shortCollName));
94+
assert.eq(true, collNames.includes(longCollName));
95+
96+
MongoRunner.stopMongod(conn);
97+
98+
/**
99+
* Restart with the 4.4 binary while in FCV 4.2. We shouldn't be able to create any collections with
100+
* long names.
101+
*/
102+
conn = MongoRunner.runMongod(restartOpts44);
103+
assert.neq(null, conn, 'mongod was unable to start with version ' + tojson(restartOpts44));
104+
105+
testDb = conn.getDB(dbName);
106+
107+
// Creating a long collection name on a 4.4 binary with FCV 4.2 should fail.
108+
assert.commandFailedWithCode(testDb.createCollection('c'.repeat(8192)),
109+
ErrorCodes.IncompatibleServerVersion);
110+
111+
// Running rename within the same database or across two databases should fail for long collection
112+
// names.
113+
assert.commandFailedWithCode(
114+
testDb.adminCommand(
115+
{renameCollection: dbName + '.' + shortCollName, to: dbName + '.' + longCollNameRename}),
116+
ErrorCodes.IllegalOperation);
117+
assert.commandFailedWithCode(testDb.adminCommand({
118+
renameCollection: dbName + '.' + shortCollName,
119+
to: renameDbName + '.' + longCollNameRename
120+
}),
121+
ErrorCodes.IllegalOperation);
122+
123+
MongoRunner.stopMongod(conn);
124+
})();

src/mongo/db/SConscript

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,9 @@ env.Library(
183183
'$BUILD_DIR/mongo/base',
184184
'$BUILD_DIR/mongo/db/repl/optime',
185185
],
186+
LIBDEPS_PRIVATE=[
187+
'server_options_core',
188+
],
186189
)
187190

188191
env.Library(

src/mongo/db/catalog/database_impl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include "mongo/db/catalog/drop_indexes.h"
5151
#include "mongo/db/catalog/index_catalog.h"
5252
#include "mongo/db/clientcursor.h"
53+
#include "mongo/db/commands/feature_compatibility_version_parser.h"
5354
#include "mongo/db/concurrency/d_concurrency.h"
5455
#include "mongo/db/concurrency/write_conflict_exception.h"
5556
#include "mongo/db/curop.h"
@@ -559,6 +560,13 @@ void DatabaseImpl::_checkCanCreateCollection(OperationContext* opCtx,
559560
str::stream() << "Cannot create collection " << nss
560561
<< " - database is in the process of being dropped.",
561562
!_dropPending.load());
563+
564+
uassert(ErrorCodes::IncompatibleServerVersion,
565+
str::stream() << "Cannot create collection with a long name " << nss
566+
<< " - upgrade to feature compatibility version "
567+
<< FeatureCompatibilityVersionParser::kVersion44
568+
<< " to be able to do so.",
569+
nss.checkLengthForFCV());
562570
}
563571

564572
Status DatabaseImpl::createView(OperationContext* opCtx,

src/mongo/db/namespace_string.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <ostream>
3535

3636
#include "mongo/base/parse_number.h"
37+
#include "mongo/db/server_options.h"
3738
#include "mongo/util/str.h"
3839

3940
namespace mongo {
@@ -141,6 +142,25 @@ bool NamespaceString::isDropPendingNamespace() const {
141142
return coll().startsWith(dropPendingNSPrefix);
142143
}
143144

145+
bool NamespaceString::checkLengthForFCV() const {
146+
// Prior to longer collection names, the limit in older versions was 120 characters.
147+
const size_t previousMaxNSLength = 120U;
148+
if (size() <= previousMaxNSLength) {
149+
return true;
150+
}
151+
152+
if (!serverGlobalParams.featureCompatibility.isVersionInitialized()) {
153+
return false;
154+
}
155+
156+
if (serverGlobalParams.featureCompatibility.getVersion() ==
157+
ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo44) {
158+
return true;
159+
}
160+
161+
return false;
162+
}
163+
144164
NamespaceString NamespaceString::makeDropPendingNamespace(const repl::OpTime& opTime) const {
145165
StringBuilder ss;
146166
ss << db() << "." << dropPendingNSPrefix;

src/mongo/db/namespace_string.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,11 @@ class NamespaceString {
283283
*/
284284
bool isDropPendingNamespace() const;
285285

286+
/**
287+
* Returns true if the namespace length is valid based on the FCV setting.
288+
*/
289+
bool checkLengthForFCV() const;
290+
286291
/**
287292
* Returns the drop-pending namespace name for this namespace, provided the given optime.
288293
*

src/mongo/db/ops/insert.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <vector>
3434

3535
#include "mongo/bson/bson_depth.h"
36+
#include "mongo/db/commands/feature_compatibility_version_parser.h"
3637
#include "mongo/db/logical_clock.h"
3738
#include "mongo/db/logical_time.h"
3839
#include "mongo/db/views/durable_view_catalog.h"
@@ -202,7 +203,14 @@ Status userAllowedCreateNS(StringData db, StringData coll) {
202203
if (!NamespaceString::validCollectionName(coll))
203204
return Status(ErrorCodes::InvalidNamespace, "invalid collection name");
204205

205-
// check spceial areas
206+
if (!NamespaceString(db, coll).checkLengthForFCV())
207+
return Status(ErrorCodes::IncompatibleServerVersion,
208+
str::stream() << "Cannot create collection with a long name " << db << "."
209+
<< coll << " - upgrade to feature compatibility version "
210+
<< FeatureCompatibilityVersionParser::kVersion44
211+
<< " to be able to do so.");
212+
213+
// check special areas
206214

207215
if (db == "system")
208216
return Status(ErrorCodes::InvalidNamespace, "cannot use 'system' database");

0 commit comments

Comments
 (0)