summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeert Bosch <geert@mongodb.com>2017-10-23 11:54:05 -0400
committerBenety Goh <benety@mongodb.com>2017-10-23 14:38:28 -0400
commit9af189775db7b17b265d18a04ca0dc314792a4c5 (patch)
treee4093f56c08cf030f65a279514f9def861b3b205
parent04a7b956a32f5b1d6d3b169bb4e8ad829ac6e733 (diff)
downloadmongo-9af189775db7b17b265d18a04ca0dc314792a4c5.tar.gz
SERVER-31539 applyOps create fails if UUID already exists in different DB
-rw-r--r--jstests/replsets/apply_ops_create_with_uuid.js50
-rw-r--r--src/mongo/db/catalog/create_collection.cpp6
2 files changed, 56 insertions, 0 deletions
diff --git a/jstests/replsets/apply_ops_create_with_uuid.js b/jstests/replsets/apply_ops_create_with_uuid.js
new file mode 100644
index 00000000000..3628d6700f2
--- /dev/null
+++ b/jstests/replsets/apply_ops_create_with_uuid.js
@@ -0,0 +1,50 @@
+(function() {
+ // Test applyOps behavior for collection creation with explicit UUIDs.
+ "use strict";
+
+ const replTest = new ReplSetTest({nodes: 1});
+ replTest.startSet();
+ replTest.initiate();
+
+ const db = replTest.getPrimary().getDB('test');
+
+ const uuid = UUID();
+ // Two applyOps to create a foo collection with given uuid, one each for 'test' and 'test2' dbs.
+ var ops = (uuid => ["test", "test2"].map(db => {
+ return {op: "c", ns: db + ".$cmd", ui: uuid, o: {create: "foo"}};
+ }))(uuid);
+
+ function checkUUID(coll, uuid) {
+ const cmd = {listCollections: 1, filter: {name: coll}};
+ const res = assert.commandWorked(db.runCommand(cmd), tojson(cmd));
+ assert.eq(res.cursor.firstBatch[0].info.uuid,
+ uuid,
+ tojson(cmd) + " did not return expected uuid: " + tojson(res));
+ }
+
+ jsTestLog("Create a test.foo collection with uuid " + uuid + " through applyOps.");
+ let cmd = {applyOps: [ops[0]]};
+ let res = assert.commandWorked(db.runCommand(cmd), tojson(cmd));
+
+ // Check that test.foo has the expected UUID.
+ jsTestLog("Check that test.foo has UUID " + uuid);
+ checkUUID("foo", uuid);
+
+ // Change the ops to refer to bar, instead of foo. Command should still work, renaming the
+ // collection. Second command should fail as it tries to associate the "test2.foo" name with
+ // an existing collection in the "test" database. This must fail.
+ jsTestLog("Create test.bar and try to create test2.foo collections with the same UUID.");
+ ops[0].o.create = "bar";
+ res = assert.commandFailed(db.runCommand({applyOps: ops}));
+ assert.eq(res.results,
+ [true, false],
+ "expected first operation " + tojson(ops[0]) + " to succeed, and second operation " +
+ tojson(ops[1]) + " to fail, got " + tojson(res));
+
+ jsTestLog("Check that test.bar has UUID " + uuid);
+ checkUUID("bar", uuid);
+ jsTestLog("Check that test.foo no longer exists");
+ assert.eq(db.getCollectionInfos({name: "foo"}).length,
+ 0,
+ "expected foo collection to no longer exist");
+}());
diff --git a/src/mongo/db/catalog/create_collection.cpp b/src/mongo/db/catalog/create_collection.cpp
index 4164ffd510a..b4f1565f01c 100644
--- a/src/mongo/db/catalog/create_collection.cpp
+++ b/src/mongo/db/catalog/create_collection.cpp
@@ -41,6 +41,7 @@
#include "mongo/db/operation_context.h"
#include "mongo/db/ops/insert.h"
#include "mongo/db/repl/replication_coordinator_global.h"
+#include "mongo/logger/redaction.h"
namespace mongo {
namespace {
@@ -188,6 +189,11 @@ Status createCollectionForApplyOps(OperationContext* opCtx,
// If the collection with the requested UUID already exists, but with a different
// name, just rename it to 'newCollName'.
if (catalog.lookupCollectionByUUID(uuid)) {
+ uassert(40655,
+ str::stream() << "Invalid name " << redact(newCollName.ns())
+ << " for UUID "
+ << uuid.toString(),
+ currentName.db() == newCollName.db());
Status status =
db->renameCollection(opCtx, currentName.ns(), newCollName.ns(), stayTemp);
if (!status.isOK())