diff options
author | Benety Goh <benety@mongodb.com> | 2018-07-13 09:56:32 -0400 |
---|---|---|
committer | Benety Goh <benety@mongodb.com> | 2018-07-13 09:56:32 -0400 |
commit | 6a7e25af6aeb1f612019c15c73258341a5779c16 (patch) | |
tree | 77d19d6380c87dd22a30557b28bbed40b5f84f07 | |
parent | 2c19e062e4ea38cb242a17e9b5cc0f160dc970ae (diff) | |
download | mongo-6a7e25af6aeb1f612019c15c73258341a5779c16.tar.gz |
SERVER-35824 disallow downgrade to 4.0 if long index namespaces are detected
-rw-r--r-- | jstests/noPassthrough/long_index_downgrade.js | 41 | ||||
-rw-r--r-- | src/mongo/base/error_codes.err | 1 | ||||
-rw-r--r-- | src/mongo/db/catalog/coll_mod.cpp | 59 | ||||
-rw-r--r-- | src/mongo/db/catalog/coll_mod.h | 6 | ||||
-rw-r--r-- | src/mongo/db/commands/set_feature_compatibility_version_command.cpp | 4 |
5 files changed, 105 insertions, 6 deletions
diff --git a/jstests/noPassthrough/long_index_downgrade.js b/jstests/noPassthrough/long_index_downgrade.js new file mode 100644 index 00000000000..f7b29cc5292 --- /dev/null +++ b/jstests/noPassthrough/long_index_downgrade.js @@ -0,0 +1,41 @@ +/** + * Long index namespaces exceeding 127 characters are supported starting in 4.2. + * Since these are not supported in 4.0, we should not allow a server to be downgraded to FCV 4.0 + * when there are indexes with long namespaces. + * @tags: [requires_replication] + * TODO: remove this test in 4.4. + */ +(function() { + 'use strict'; + + const rst = new ReplSetTest({nodes: 1}); + + rst.startSet(); + rst.initiate(); + + const primary = rst.getPrimary(); + const mydb = primary.getDB('test'); + const coll = mydb.getCollection('long_index_name'); + + // Compute maximum index name length for this collection under FCV 4.0. + const maxNsLength = 127; + const maxIndexNameLength = maxNsLength - (coll.getFullName() + ".$").length; + jsTestLog('Max index name length under FCV 4.0 = ' + maxIndexNameLength); + + // Create an index with the longest name allowed for this collection under FCV 4.0. + assert.commandWorked(coll.createIndex({a: 1}, {name: 'a'.repeat(maxIndexNameLength)})); + + // Create an index with a name that exceeds the limit in 4.0. + const longName = 'b'.repeat(maxIndexNameLength + 1); + assert.commandWorked(coll.createIndex({b: 1}, {name: longName})); + + // Downgrades should fail while we have indexes that are not compatible with 4.0. + assert.commandFailedWithCode(mydb.adminCommand({setFeatureCompatibilityVersion: '4.0'}), + ErrorCodes.IndexNamespaceTooLong); + + // Drop index with long name before retrying downgrade. + assert.commandWorked(coll.dropIndex(longName)); + assert.commandWorked(mydb.adminCommand({setFeatureCompatibilityVersion: '4.0'})); + + rst.stopSet(); +})(); diff --git a/src/mongo/base/error_codes.err b/src/mongo/base/error_codes.err index 74620aa4fe7..9477dcaf9eb 100644 --- a/src/mongo/base/error_codes.err +++ b/src/mongo/base/error_codes.err @@ -262,6 +262,7 @@ error_code("TooManyFilesOpen", 261); error_code("FailPointSetFailed", 262) error_code("OperationNotSupportedInTransaction", 263) error_code("TooManyLogicalSessions", 264); +error_code("IndexNamespaceTooLong", 265); # Error codes 4000-8999 are reserved. diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp index 14c1ba4f3c3..936a99a368e 100644 --- a/src/mongo/db/catalog/coll_mod.cpp +++ b/src/mongo/db/catalog/coll_mod.cpp @@ -66,6 +66,19 @@ namespace { // databases if none are provided). MONGO_FAIL_POINT_DEFINE(hangBeforeDatabaseUpgrade); +/** + * Returns list of database names. + */ +std::vector<std::string> getDatabaseNames(OperationContext* opCtx) { + std::vector<std::string> dbNames; + auto storageEngine = opCtx->getServiceContext()->getStorageEngine(); + { + Lock::GlobalLock lk(opCtx, MODE_IS); + storageEngine->listDatabases(&dbNames); + } + return dbNames; +} + struct CollModRequest { const IndexDescriptor* idx = nullptr; BSONElement indexExpireAfterSeconds = {}; @@ -600,12 +613,7 @@ Status updateNonReplicatedUniqueIndexes(OperationContext* opCtx) { // Update all unique indexes belonging to all non-replicated collections. // (_id indexes are not updated). - std::vector<std::string> dbNames; - StorageEngine* storageEngine = opCtx->getServiceContext()->getStorageEngine(); - { - Lock::GlobalLock lk(opCtx, MODE_IS); - storageEngine->listDatabases(&dbNames); - } + auto dbNames = getDatabaseNames(opCtx); for (auto it = dbNames.begin(); it != dbNames.end(); ++it) { auto dbName = *it; auto schemaStatus = _updateNonReplicatedUniqueIndexesPerDatabase(opCtx, dbName); @@ -616,4 +624,43 @@ Status updateNonReplicatedUniqueIndexes(OperationContext* opCtx) { return Status::OK(); } +Status checkIndexNamespacesOnDowngrade(OperationContext* opCtx) { + auto dbNames = getDatabaseNames(opCtx); + for (const auto& dbName : dbNames) { + AutoGetDb autoDb(opCtx, dbName, MODE_IS); + auto db = autoDb.getDb(); + // If the database no longer exists, there's nothing to do. + if (!db) { + continue; + } + + for (auto collIter : *db) { + const auto nss = collIter->ns(); + if (nss.isDropPendingNamespace()) { + continue; + } + + AutoGetCollectionForRead autoColl(opCtx, nss); + auto coll = autoColl.getCollection(); + if (!coll) { + continue; + } + + const bool includeUnfinishedIndexes = true; + auto it = coll->getIndexCatalog()->getIndexIterator(opCtx, includeUnfinishedIndexes); + while (it.more()) { + auto desc = it.next(); + if (desc->indexNamespace().length() > NamespaceString::MaxNsLen) { + return Status(ErrorCodes::IndexNamespaceTooLong, + str::stream() << "index namespace \"" << desc->indexNamespace() + << "\" is too long for downgrade to 4.0 (" + << NamespaceString::MaxNsLen + << " byte max)"); + } + } + } + } + return Status::OK(); +} + } // namespace mongo diff --git a/src/mongo/db/catalog/coll_mod.h b/src/mongo/db/catalog/coll_mod.h index 3cf618ac803..c7d69ed197a 100644 --- a/src/mongo/db/catalog/coll_mod.h +++ b/src/mongo/db/catalog/coll_mod.h @@ -69,4 +69,10 @@ void updateUniqueIndexesOnUpgrade(OperationContext* opCtx); * Updates non-replicated unique indexes to timestamp safe unique index format. */ Status updateNonReplicatedUniqueIndexes(OperationContext* opCtx); + +/* + * Checks index namespaces that would exceed 4.0 constraints on setFCV=4.0. + */ +Status checkIndexNamespacesOnDowngrade(OperationContext* opCtx); + } // namespace mongo diff --git a/src/mongo/db/commands/set_feature_compatibility_version_command.cpp b/src/mongo/db/commands/set_feature_compatibility_version_command.cpp index e751532068b..347f90939fb 100644 --- a/src/mongo/db/commands/set_feature_compatibility_version_command.cpp +++ b/src/mongo/db/commands/set_feature_compatibility_version_command.cpp @@ -199,6 +199,10 @@ public: return true; } + // Before starting the downgrade process, check indexes for index namespaces that would + // fail 4.0 length constraints. + uassertStatusOK(checkIndexNamespacesOnDowngrade(opCtx)); + FeatureCompatibilityVersion::setTargetDowngrade(opCtx); { |