summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Noma <gregory.noma@gmail.com>2022-01-25 21:01:10 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-01-25 21:39:40 +0000
commit30f415df521fc9b9a04801464f01880e412decce (patch)
treebc5ee07405fdd084c762536b47832737cc8020ef
parent43f1b480ea6c273aecd9caa355d0dc7a48ab7a04 (diff)
downloadmongo-30f415df521fc9b9a04801464f01880e412decce.tar.gz
SERVER-62455 Add `collectionUUID` parameter to `renameCollection` command
-rw-r--r--buildscripts/resmokeconfig/suites/multi_stmt_txn_jscore_passthrough_with_migration.yml4
-rw-r--r--jstests/core/collection_uuid_rename_collection.js81
-rw-r--r--jstests/core/rename_collection.js1
-rw-r--r--jstests/libs/parallelTester.js1
-rw-r--r--src/mongo/db/catalog/rename_collection.cpp7
-rw-r--r--src/mongo/db/catalog/rename_collection.h1
-rw-r--r--src/mongo/db/commands/rename_collection.idl4
-rw-r--r--src/mongo/db/commands/rename_collection_cmd.cpp1
-rw-r--r--src/mongo/db/s/rename_collection_coordinator.cpp10
-rw-r--r--src/mongo/db/s/rename_collection_participant_service.cpp3
-rw-r--r--src/mongo/s/commands/cluster_rename_collection_cmd.cpp1
-rw-r--r--src/mongo/s/request_types/sharded_ddl_commands.idl4
12 files changed, 114 insertions, 4 deletions
diff --git a/buildscripts/resmokeconfig/suites/multi_stmt_txn_jscore_passthrough_with_migration.yml b/buildscripts/resmokeconfig/suites/multi_stmt_txn_jscore_passthrough_with_migration.yml
index 6635d2da9ea..aacde719bd6 100644
--- a/buildscripts/resmokeconfig/suites/multi_stmt_txn_jscore_passthrough_with_migration.yml
+++ b/buildscripts/resmokeconfig/suites/multi_stmt_txn_jscore_passthrough_with_migration.yml
@@ -273,9 +273,6 @@ selector:
# Does not support tojson of command objects.
- jstests/core/SERVER-23626.js
- # This suite is using zones for migrations but the following test is expecting no entries in config.tags
- - jstests/core/rename_collection.js
-
exclude_with_any_tags:
# "Cowardly refusing to override read concern of command: ..."
- assumes_read_concern_unchanged
@@ -307,6 +304,7 @@ selector:
# startParallelShell()"
- uses_parallel_shell
- does_not_support_causal_consistency
+ - does_not_support_zones
executor:
archive:
diff --git a/jstests/core/collection_uuid_rename_collection.js b/jstests/core/collection_uuid_rename_collection.js
new file mode 100644
index 00000000000..3c3730e104b
--- /dev/null
+++ b/jstests/core/collection_uuid_rename_collection.js
@@ -0,0 +1,81 @@
+/**
+ * Tests the collectionUUID parameter of the renameCollection command.
+ *
+ * @tags: [
+ * does_not_support_zones,
+ * featureFlagCommandsAcceptCollectionUUID,
+ * no_selinux,
+ * tenant_migration_incompatible,
+ * ]
+ */
+(function() {
+'use strict';
+
+const testDB = db.getSiblingDB(jsTestName());
+assert.commandWorked(testDB.dropDatabase());
+
+const coll = testDB.coll;
+const coll2 = testDB.coll_2;
+const coll3 = testDB.coll_3;
+
+const resetColls = function() {
+ coll.drop();
+ coll2.drop();
+ coll3.drop();
+
+ assert.commandWorked(coll.insert({_id: 0}));
+ assert.commandWorked(coll2.insert({_id: 1}));
+};
+
+const uuid = function() {
+ return assert.commandWorked(testDB.runCommand({listCollections: 1}))
+ .cursor.firstBatch.find(c => c.name === coll.getName())
+ .info.uuid;
+};
+
+// The command succeeds when the correct UUID is provided.
+resetColls();
+assert.commandWorked(testDB.adminCommand({
+ renameCollection: coll.getFullName(),
+ to: coll3.getFullName(),
+ dropTarget: true,
+ collectionUUID: uuid(),
+}));
+
+// The command fails when the provided UUID does not correspond to an existing collection.
+resetColls();
+const nonexistentUUID = UUID();
+let res = assert.commandFailedWithCode(testDB.adminCommand({
+ renameCollection: coll.getFullName(),
+ to: coll3.getFullName(),
+ dropTarget: true,
+ 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.
+resetColls();
+res = assert.commandFailedWithCode(testDB.adminCommand({
+ renameCollection: coll2.getFullName(),
+ to: coll3.getFullName(),
+ dropTarget: true,
+ collectionUUID: uuid(),
+}),
+ ErrorCodes.CollectionUUIDMismatch);
+assert.eq(res.collectionUUID, uuid());
+assert.eq(res.actualNamespace, coll.getFullName());
+
+// The collectionUUID parameter cannot be provided when renaming a collection between databases.
+const otherDBColl = db.getSiblingDB(jsTestName() + '_2').coll;
+otherDBColl.drop();
+assert.commandWorked(otherDBColl.insert({_id: 3}));
+assert.commandFailedWithCode(testDB.adminCommand({
+ renameCollection: coll.getFullName(),
+ to: otherDBColl.getFullName(),
+ dropTarget: true,
+ collectionUUID: uuid(),
+}),
+ [ErrorCodes.InvalidOptions, ErrorCodes.CommandFailed]);
+})();
diff --git a/jstests/core/rename_collection.js b/jstests/core/rename_collection.js
index c47fdec0153..ee67447e11c 100644
--- a/jstests/core/rename_collection.js
+++ b/jstests/core/rename_collection.js
@@ -3,6 +3,7 @@
*
* @tags: [
* assumes_no_implicit_collection_creation_after_drop,
+ * does_not_support_zones,
* requires_non_retryable_commands,
* ]
*/
diff --git a/jstests/libs/parallelTester.js b/jstests/libs/parallelTester.js
index 1574c3a29f7..ad8ce6c98a0 100644
--- a/jstests/libs/parallelTester.js
+++ b/jstests/libs/parallelTester.js
@@ -237,6 +237,7 @@ if (typeof _threadInject != "undefined") {
"collection_uuid_find.js",
"collection_uuid_write_commands.js",
"collection_uuid_coll_mod.js",
+ "collection_uuid_rename_collection.js",
]);
// Get files, including files in subdirectories.
diff --git a/src/mongo/db/catalog/rename_collection.cpp b/src/mongo/db/catalog/rename_collection.cpp
index 3695a67363e..806bc5c69a3 100644
--- a/src/mongo/db/catalog/rename_collection.cpp
+++ b/src/mongo/db/catalog/rename_collection.cpp
@@ -35,6 +35,7 @@
#include "mongo/bson/unordered_fields_bsonobj_comparator.h"
#include "mongo/db/catalog/collection_catalog.h"
+#include "mongo/db/catalog/collection_uuid_mismatch.h"
#include "mongo/db/catalog/database_holder.h"
#include "mongo/db/catalog/document_validation.h"
#include "mongo/db/catalog/drop_collection.h"
@@ -318,6 +319,8 @@ Status renameCollectionWithinDB(OperationContext* opCtx,
const auto sourceColl = catalog->lookupCollectionByNamespace(opCtx, source);
const auto targetColl = catalog->lookupCollectionByNamespace(opCtx, target);
+ checkCollectionUUIDMismatch(opCtx, sourceColl, options.expectedSourceUUID);
+
AutoStatsTracker statsTracker(
opCtx,
source,
@@ -459,6 +462,10 @@ Status renameBetweenDBs(OperationContext* opCtx,
str::stream() << "renameBetweenDBs not supported in multi-document transaction: source: "
<< source << "; target: " << target);
+ uassert(ErrorCodes::InvalidOptions,
+ "Cannot provide an expected source collection UUID when renaming between databases",
+ !options.expectedSourceUUID);
+
boost::optional<Lock::DBLock> sourceDbLock;
boost::optional<Lock::CollectionLock> sourceCollLock;
if (!opCtx->lockState()->isCollectionLockedForMode(source, MODE_S)) {
diff --git a/src/mongo/db/catalog/rename_collection.h b/src/mongo/db/catalog/rename_collection.h
index 4dee5f8731f..1f46262aca2 100644
--- a/src/mongo/db/catalog/rename_collection.h
+++ b/src/mongo/db/catalog/rename_collection.h
@@ -48,6 +48,7 @@ class OpTime;
* temporariness.
*/
struct RenameCollectionOptions {
+ boost::optional<UUID> expectedSourceUUID;
bool dropTarget = false;
bool stayTemp = false;
bool markFromMigrate = false;
diff --git a/src/mongo/db/commands/rename_collection.idl b/src/mongo/db/commands/rename_collection.idl
index ba7c19699d1..6ec0e7b97e7 100644
--- a/src/mongo/db/commands/rename_collection.idl
+++ b/src/mongo/db/commands/rename_collection.idl
@@ -55,3 +55,7 @@ commands:
before the rename."
type: bool
default: false
+ collectionUUID:
+ description: "The expected UUID of the collection."
+ type: uuid
+ optional: true
diff --git a/src/mongo/db/commands/rename_collection_cmd.cpp b/src/mongo/db/commands/rename_collection_cmd.cpp
index 7f5565cdba9..7a3bcd029ab 100644
--- a/src/mongo/db/commands/rename_collection_cmd.cpp
+++ b/src/mongo/db/commands/rename_collection_cmd.cpp
@@ -102,6 +102,7 @@ public:
ErrorCodes::IllegalOperation, "Can't rename a collection to itself", fromNss != toNss);
RenameCollectionOptions options;
+ options.expectedSourceUUID = renameRequest.getCollectionUUID();
options.dropTarget = renameRequest.getDropTarget();
options.stayTemp = renameRequest.getStayTemp();
validateAndRunRenameCollection(
diff --git a/src/mongo/db/s/rename_collection_coordinator.cpp b/src/mongo/db/s/rename_collection_coordinator.cpp
index 520faa8289b..ea807af46c5 100644
--- a/src/mongo/db/s/rename_collection_coordinator.cpp
+++ b/src/mongo/db/s/rename_collection_coordinator.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/s/rename_collection_coordinator.h"
#include "mongo/db/catalog/collection_catalog.h"
+#include "mongo/db/catalog/collection_uuid_mismatch.h"
#include "mongo/db/catalog/database_holder.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/ops/insert.h"
@@ -178,9 +179,18 @@ ExecutorFuture<void> RenameCollectionCoordinator::_runImpl(
fromNss.db() == toNss.db());
_doc.setOptShardedCollInfo(optSourceCollType);
} else if (fromNss.db() != toNss.db()) {
+ uassert(ErrorCodes::InvalidOptions,
+ "Cannot provide an expected source collection UUID when renaming "
+ "between databases",
+ !_doc.getCollectionUUID());
sharding_ddl_util::checkDbPrimariesOnTheSameShard(opCtx, fromNss, toNss);
}
+ {
+ AutoGetCollection coll{opCtx, fromNss, MODE_IS};
+ checkCollectionUUIDMismatch(opCtx, *coll, _doc.getCollectionUUID());
+ }
+
// Make sure the target namespace is not a view
{
Lock::DBLock dbLock(opCtx, toNss.db(), MODE_IS);
diff --git a/src/mongo/db/s/rename_collection_participant_service.cpp b/src/mongo/db/s/rename_collection_participant_service.cpp
index 62da2326850..da849f43f72 100644
--- a/src/mongo/db/s/rename_collection_participant_service.cpp
+++ b/src/mongo/db/s/rename_collection_participant_service.cpp
@@ -279,7 +279,8 @@ SemiFuture<void> RenameParticipantInstance::run(
auto* opCtx = opCtxHolder.get();
_doc.getForwardableOpMetadata().setOn(opCtx);
- const RenameCollectionOptions options{_doc.getDropTarget(), _doc.getStayTemp()};
+ const RenameCollectionOptions options{
+ _doc.getCollectionUUID(), _doc.getDropTarget(), _doc.getStayTemp()};
renameOrDropTarget(
opCtx, fromNss(), toNss(), options, _doc.getSourceUUID(), _doc.getTargetUUID());
diff --git a/src/mongo/s/commands/cluster_rename_collection_cmd.cpp b/src/mongo/s/commands/cluster_rename_collection_cmd.cpp
index 3df3b928292..6146de29db4 100644
--- a/src/mongo/s/commands/cluster_rename_collection_cmd.cpp
+++ b/src/mongo/s/commands/cluster_rename_collection_cmd.cpp
@@ -77,6 +77,7 @@ public:
RenameCollectionRequest renameCollReq(request().getTo());
renameCollReq.setDropTarget(request().getDropTarget());
renameCollReq.setStayTemp(request().getStayTemp());
+ renameCollReq.setCollectionUUID(request().getCollectionUUID());
ShardsvrRenameCollection renameCollRequest(fromNss);
renameCollRequest.setDbName(fromNss.db());
diff --git a/src/mongo/s/request_types/sharded_ddl_commands.idl b/src/mongo/s/request_types/sharded_ddl_commands.idl
index 878c9f142c7..03293b1971e 100644
--- a/src/mongo/s/request_types/sharded_ddl_commands.idl
+++ b/src/mongo/s/request_types/sharded_ddl_commands.idl
@@ -78,6 +78,10 @@ structs:
description: "If true, the original collection will remain temp if it was temp
before the rename."
default: false
+ collectionUUID:
+ type: uuid
+ description: "The expected UUID of the collection."
+ optional: true
RenameCollectionResponse:
description: "Response for the rename collection command"