diff options
author | Gregory Noma <gregory.noma@gmail.com> | 2022-01-12 15:42:07 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-01-12 16:38:00 +0000 |
commit | eb75b6ccc62f7c8ea26a57c1b5eb96a41809396a (patch) | |
tree | 854e337b4437f11d54b40690f18728f44050e700 | |
parent | 36e150219f44b029289135099236b328f3ed432a (diff) | |
download | mongo-eb75b6ccc62f7c8ea26a57c1b5eb96a41809396a.tar.gz |
SERVER-62443 Add `collectionUUID` parameter to `find` command
-rw-r--r-- | jstests/core/collection_uuid_find.js | 56 | ||||
-rw-r--r-- | jstests/libs/parallelTester.js | 6 | ||||
-rw-r--r-- | jstests/noPassthroughWithMongod/collection_uuid_find_by_uuid.js | 18 | ||||
-rw-r--r-- | src/mongo/db/commands/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/commands/find_cmd.cpp | 18 | ||||
-rw-r--r-- | src/mongo/db/query/find_command.idl | 5 |
6 files changed, 103 insertions, 1 deletions
diff --git a/jstests/core/collection_uuid_find.js b/jstests/core/collection_uuid_find.js new file mode 100644 index 00000000000..e958bffa890 --- /dev/null +++ b/jstests/core/collection_uuid_find.js @@ -0,0 +1,56 @@ +/** + * Tests the collectionUUID parameter of the find command. + * + * @tags: [ + * featureFlagCommandsAcceptCollectionUUID, + * tenant_migration_incompatible, + * ] + */ +(function() { +'use strict'; + +const testDB = db.getSiblingDB(jsTestName()); +assert.commandWorked(testDB.dropDatabase()); + +const coll = testDB['coll']; +assert.commandWorked(coll.insert({_id: 0})); + +const uuid = + assert.commandWorked(testDB.runCommand({listCollections: 1})).cursor.firstBatch[0].info.uuid; + +// The command succeeds when the correct UUID is provided. +assert.commandWorked(testDB.runCommand({find: coll.getName(), collectionUUID: uuid})); + +// The command fails when the provided UUID does not correspond to an existing collection. +const nonexistentUUID = UUID(); +let res = assert.commandFailedWithCode( + testDB.runCommand({find: coll.getName(), collectionUUID: nonexistentUUID}), + ErrorCodes.CollectionUUIDMismatch); +assert.eq(res.collectionUUID, nonexistentUUID); +assert.eq(res.actualNamespace, ""); + +// The command fails when the provided UUID corresponds to a different collection. +const coll2 = testDB['coll_2']; +assert.commandWorked(coll2.insert({_id: 1})); +res = assert.commandFailedWithCode(testDB.runCommand({find: coll2.getName(), collectionUUID: uuid}), + ErrorCodes.CollectionUUIDMismatch); +assert.eq(res.collectionUUID, uuid); +assert.eq(res.actualNamespace, coll.getFullName()); + +// The command fails when the provided UUID corresponds to a different collection, even if the +// provided namespace does not exist. +coll2.drop(); +res = assert.commandFailedWithCode(testDB.runCommand({find: coll2.getName(), collectionUUID: uuid}), + ErrorCodes.CollectionUUIDMismatch); +assert.eq(res.collectionUUID, uuid); +assert.eq(res.actualNamespace, coll.getFullName()); + +// The command fails when the provided UUID corresponds to a different collection, even if the +// provided namespace is a view. +const view = db['view']; +assert.commandWorked(testDB.createView(view.getName(), coll.getName(), [])); +res = assert.commandFailedWithCode(testDB.runCommand({find: view.getName(), collectionUUID: uuid}), + ErrorCodes.CollectionUUIDMismatch); +assert.eq(res.collectionUUID, uuid); +assert.eq(res.actualNamespace, coll.getFullName()); +})(); diff --git a/jstests/libs/parallelTester.js b/jstests/libs/parallelTester.js index 7f4365aa798..67859ae65e3 100644 --- a/jstests/libs/parallelTester.js +++ b/jstests/libs/parallelTester.js @@ -230,7 +230,11 @@ if (typeof _threadInject != "undefined") { "timeseries/timeseries_delete_hint.js", "timeseries/timeseries_update_hint.js", "timeseries/timeseries_delete_concurrent.js", - "timeseries/timeseries_update_concurrent.js" + "timeseries/timeseries_update_concurrent.js", + + // TODO (SERVER-60185): Remove the collection_uuid_*.js exclusions once the feature flag + // is enabled by default. + "collection_uuid_find.js", ]); // Get files, including files in subdirectories. diff --git a/jstests/noPassthroughWithMongod/collection_uuid_find_by_uuid.js b/jstests/noPassthroughWithMongod/collection_uuid_find_by_uuid.js new file mode 100644 index 00000000000..26a4f56e135 --- /dev/null +++ b/jstests/noPassthroughWithMongod/collection_uuid_find_by_uuid.js @@ -0,0 +1,18 @@ +/** + * Tests that when running the find command by UUID, the collectionUUID parameter cannot also be + * specified. + */ +(function() { +'use strict'; + +const coll = db[jsTestName()]; +coll.drop(); +assert.commandWorked(coll.insert({_id: 0})); + +const uuid = assert.commandWorked(db.runCommand({listCollections: 1})) + .cursor.firstBatch.find(c => c.name === coll.getName()) + .info.uuid; + +assert.commandFailedWithCode(db.runCommand({find: uuid, collectionUUID: uuid}), + ErrorCodes.InvalidOptions); +})(); diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index c8e94e111c9..587aaf45c24 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -355,6 +355,7 @@ env.Library( '$BUILD_DIR/mongo/db/catalog/catalog_helpers', '$BUILD_DIR/mongo/db/catalog/collection_catalog_helper', '$BUILD_DIR/mongo/db/catalog/collection_query_info', + '$BUILD_DIR/mongo/db/catalog/collection_uuid_mismatch', '$BUILD_DIR/mongo/db/catalog/collection_validation', '$BUILD_DIR/mongo/db/catalog/database_holder', '$BUILD_DIR/mongo/db/catalog/index_key_validate', diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index f0eeb4fe30d..3ab8d7d8d6a 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -33,6 +33,7 @@ #include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" +#include "mongo/db/catalog/collection_uuid_mismatch.h" #include "mongo/db/client.h" #include "mongo/db/clientcursor.h" #include "mongo/db/commands.h" @@ -400,6 +401,11 @@ public: !(repl::ReadConcernArgs::get(opCtx).isSpeculativeMajority() && !findCommand->getAllowSpeculativeMajorityRead())); + uassert(ErrorCodes::InvalidOptions, + "When using the find command by UUID, the collectionUUID parameter cannot also " + "be specified", + !findCommand->getNamespaceOrUUID().uuid() || !findCommand->getCollectionUUID()); + auto replCoord = repl::ReplicationCoordinator::get(opCtx); const auto txnParticipant = TransactionParticipant::get(opCtx); uassert(ErrorCodes::InvalidOptions, @@ -472,6 +478,18 @@ public: << " specified in query request not found", ctx || !findCommand->getNamespaceOrUUID().uuid()); + uassert(ErrorCodes::InvalidOptions, + "The collectionUUID parameter is not enabled", + !findCommand->getCollectionUUID() || + feature_flags::gCommandsAcceptCollectionUUID.isEnabled( + serverGlobalParams.featureCompatibility)); + + if (findCommand->getCollectionUUID() && + (!ctx->getCollection() || + findCommand->getCollectionUUID() != ctx->getCollection()->uuid())) { + uassertCollectionUUIDMismatch(opCtx, *findCommand->getCollectionUUID()); + } + // Set the namespace if a collection was found, as opposed to nothing or a view. if (ctx) { query_request_helper::refreshNSS(ctx->getNss(), findCommand.get()); diff --git a/src/mongo/db/query/find_command.idl b/src/mongo/db/query/find_command.idl index 2760dcb9c2b..bb89213f4aa 100644 --- a/src/mongo/db/query/find_command.idl +++ b/src/mongo/db/query/find_command.idl @@ -239,3 +239,8 @@ commands: type: LegacyRuntimeConstants optional: true unstable: true + collectionUUID: + description: "The expected UUID of the collection." + type: uuid + optional: true + unstable: true |