summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMisha Tyulenev <misha.tyulenev@mongodb.com>2020-07-08 22:28:55 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-07-10 16:39:11 +0000
commitd6f3aebf450e53dd41ca31947cc0cc9ccf30e1bc (patch)
tree371500baa998a5489cf3e25f7c4ac71a07fdef7f
parentff8a74db8a39fbc89bb25fee964dc2d1173acacd (diff)
downloadmongo-d6f3aebf450e53dd41ca31947cc0cc9ccf30e1bc.tar.gz
SERVER-49091 fail with MovePrimaryInProgress on create drop collMod renameCollection commands
-rw-r--r--jstests/sharding/move_primary_with_writes.js84
-rw-r--r--src/mongo/db/catalog/database_impl.cpp23
2 files changed, 92 insertions, 15 deletions
diff --git a/jstests/sharding/move_primary_with_writes.js b/jstests/sharding/move_primary_with_writes.js
index 8c58f37da86..11d9e8f6150 100644
--- a/jstests/sharding/move_primary_with_writes.js
+++ b/jstests/sharding/move_primary_with_writes.js
@@ -29,6 +29,7 @@ function createCollections() {
assert.commandWorked(st.s.adminCommand({movePrimary: dbName, to: st.shard0.shardName}));
assert.commandWorked(db.createCollection('unshardedFoo'));
+ assert.commandWorked(db.createView('viewOnFoo', 'unshardedFoo', [{$match: {}}]));
assert.commandWorked(db.createCollection('shardedBar'));
for (let i = 0; i < 3; i++) {
@@ -46,14 +47,33 @@ function createCollections() {
function buildCommands(collName) {
const commands = [
- {insert: collName, documents: [{a: 10}]},
- {update: collName, updates: [{q: {a: 1}, u: {$set: {a: 11}}}]},
- {findAndModify: collName, query: {a: 2}, update: {$set: {a: 11}}},
- {delete: collName, deletes: [{q: {a: 0}, limit: 1}]}
+ {command: {insert: collName, documents: [{a: 10}]}, alwaysFail: false},
+ {
+ command: {update: collName, updates: [{q: {a: 1}, u: {$set: {a: 11}}}]},
+ alwaysFail: false
+ },
+ {
+ command: {findAndModify: collName, query: {_id: 2}, update: {$set: {a: 11}}},
+ alwaysFail: false
+ },
+ {command: {delete: collName, deletes: [{q: {_id: 0}, limit: 1}]}, alwaysFail: false},
+ {command: {create: "testCollection"}, alwaysFail: true},
+ {
+ command: {collMod: "viewOnFoo", viewOn: "unshardedFoo", pipeline: [{$match: {_id: 1}}]},
+ alwaysFail: true
+ },
];
return commands;
}
+function buildDDLCommands() {
+ const commands = [{
+ command: {renameCollection: "testdb.unshardedFoo", to: "testdb.testCollection"},
+ alwaysFail: true
+ }];
+ return commands;
+}
+
function testMovePrimary(failpoint, fromShard, toShard, db, shouldFail, sharded) {
let codeToRunInParallelShell = '{ db.getSiblingDB("admin").runCommand({movePrimary: "' +
dbName + '", to: "' + toShard.name + '"}); }';
@@ -75,13 +95,46 @@ function testMovePrimary(failpoint, fromShard, toShard, db, shouldFail, sharded)
collName = "unshardedFoo";
}
- buildCommands(collName).forEach(command => {
+ buildCommands(collName).forEach(commandObj => {
+ if (shouldFail) {
+ jsTestLog("running command: " + tojson(commandObj.command) +
+ ",\nshoudFail: " + shouldFail);
+ assert.commandFailedWithCode(db.runCommand(commandObj.command),
+ ErrorCodes.MovePrimaryInProgress);
+ } else if (!commandObj.alwaysFail) {
+ jsTestLog("running command: " + tojson(commandObj.command) +
+ ",\nshoudFail: " + shouldFail);
+ assert.commandWorked(db.runCommand(commandObj.command));
+ }
+ });
+
+ assert.commandWorked(fromShard.adminCommand({configureFailPoint: failpoint, mode: 'off'}));
+
+ awaitShell();
+}
+
+function testMovePrimaryDDL(failpoint, fromShard, toShard, db, shouldFail) {
+ let codeToRunInParallelShell = '{ db.getSiblingDB("admin").runCommand({movePrimary: "' +
+ dbName + '", to: "' + toShard.name + '"}); }';
+
+ assert.commandWorked(fromShard.adminCommand({configureFailPoint: failpoint, mode: 'alwaysOn'}));
+
+ let awaitShell = startParallelShell(codeToRunInParallelShell, st.s.port);
+
+ jsTestLog("Waiting for failpoint " + failpoint);
+ waitForFailpoint("Hit " + failpoint, 1);
+ clearRawMongoProgramOutput();
+
+ buildDDLCommands().forEach(commandObj => {
if (shouldFail) {
- jsTestLog("running command: " + tojson(command) + ",\nshoudFail: " + shouldFail);
- assert.commandFailedWithCode(db.runCommand(command), ErrorCodes.MovePrimaryInProgress);
- } else {
- jsTestLog("running command: " + tojson(command) + ",\nshoudFail: " + shouldFail);
- assert.commandWorked(db.runCommand(command));
+ jsTestLog("running command: " + tojson(commandObj.command) +
+ ",\nshoudFail: " + shouldFail);
+ assert.commandFailedWithCode(db.runCommand(commandObj.command),
+ ErrorCodes.MovePrimaryInProgress);
+ } else if (!commandObj.alwaysFail) {
+ jsTestLog("running command: " + tojson(commandObj.command) +
+ ",\nshoudFail: " + shouldFail);
+ assert.commandWorked(db.runCommand(commandObj.command));
}
});
@@ -94,21 +147,22 @@ createCollections();
let fromShard = st.getPrimaryShard(dbName);
let toShard = st.getOther(fromShard);
-testMovePrimary('hangInCloneStage', fromShard, toShard, fromShard.getDB(dbName), true, false);
+testMovePrimary('hangInCloneStage', fromShard, toShard, st.s.getDB(dbName), true, false);
verifyDocuments(toShard.getDB(dbName), 3);
verifyDocuments(fromShard.getDB(dbName), 0);
createCollections();
fromShard = st.getPrimaryShard(dbName);
toShard = st.getOther(fromShard);
-testMovePrimary('hangInCloneStage', fromShard, toShard, fromShard.getDB(dbName), false, true);
+
+testMovePrimary('hangInCloneStage', fromShard, toShard, st.s.getDB(dbName), false, true);
+verifyDocuments(toShard.getDB(dbName), 3);
+verifyDocuments(fromShard.getDB(dbName), 0);
createCollections();
fromShard = st.getPrimaryShard(dbName);
toShard = st.getOther(fromShard);
-testMovePrimary('hangInCloneStage', fromShard, toShard, st.s.getDB(dbName), true, false);
-verifyDocuments(toShard.getDB(dbName), 3);
-verifyDocuments(fromShard.getDB(dbName), 0);
+testMovePrimaryDDL('hangInCloneStage', fromShard, toShard, st.s.getDB("admin"), true);
createCollections();
fromShard = st.getPrimaryShard(dbName);
diff --git a/src/mongo/db/catalog/database_impl.cpp b/src/mongo/db/catalog/database_impl.cpp
index afe29c7cc83..f164a08e99a 100644
--- a/src/mongo/db/catalog/database_impl.cpp
+++ b/src/mongo/db/catalog/database_impl.cpp
@@ -62,6 +62,7 @@
#include "mongo/db/repl/drop_pending_collection_reaper.h"
#include "mongo/db/repl/oplog.h"
#include "mongo/db/repl/replication_coordinator.h"
+#include "mongo/db/s/database_sharding_state.h"
#include "mongo/db/s/operation_sharding_state.h"
#include "mongo/db/server_options.h"
#include "mongo/db/service_context.h"
@@ -106,6 +107,25 @@ Status validateDBNameForWindows(StringData dbname) {
PseudoRandom uniqueCollectionNamespacePseudoRandom(Date_t::now().asInt64());
Mutex uniqueCollectionNamespaceMutex = MONGO_MAKE_LATCH("DatabaseUniqueCollectionNamespaceMutex");
+
+void assertMovePrimaryInProgress(OperationContext* opCtx, NamespaceString const& nss) {
+ Lock::DBLock dblock(opCtx, nss.db(), MODE_IS);
+ auto dss = DatabaseShardingState::get(opCtx, nss.db().toString());
+ if (!dss) {
+ return;
+ }
+
+ auto dssLock = DatabaseShardingState::DSSLock::lockShared(opCtx, dss);
+ auto mpsm = dss->getMovePrimarySourceManager(dssLock);
+
+ if (mpsm) {
+ LOGV2(4909100, "assertMovePrimaryInProgress", "movePrimaryNss"_attr = nss.toString());
+
+ uasserted(ErrorCodes::MovePrimaryInProgress,
+ "movePrimary is in progress for namespace " + nss.toString());
+ }
+}
+
} // namespace
Status DatabaseImpl::validateDBName(StringData dbname) {
@@ -505,6 +525,8 @@ Status DatabaseImpl::renameCollection(OperationContext* opCtx,
return Status(ErrorCodes::NamespaceNotFound, "collection not found to rename");
}
+ assertMovePrimaryInProgress(opCtx, fromNss);
+
LOGV2(20319,
"renameCollection: renaming collection {collToRename_uuid} from {fromNss} to {toNss}",
"renameCollection",
@@ -557,6 +579,7 @@ void DatabaseImpl::_checkCanCreateCollection(OperationContext* opCtx,
str::stream() << "Cannot create collection " << nss
<< " - database is in the process of being dropped.",
!_dropPending.load());
+ assertMovePrimaryInProgress(opCtx, nss);
}
Status DatabaseImpl::createView(OperationContext* opCtx,