0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 01:21:03 +01:00

SERVER-39419 Stepdown interrupting a running dropDatabase command could leave unclean state

This commit is contained in:
Gregory Wlodarek 2019-03-12 12:26:31 -04:00
parent 330c59b671
commit 796ae56683
4 changed files with 62 additions and 13 deletions

View File

@ -0,0 +1,60 @@
/**
* Tests that performing a stepdown on the primary during a dropDatabase command doesn't have any
* negative effects when the new primary runs the same dropDatabase command while the old primary
* is still in the midst of dropping the database.
*
* @tags: [requires_replication]
*/
(function() {
"use strict";
load("jstests/libs/check_log.js");
const dbName = "test";
const collName = "coll";
const replSet = new ReplSetTest({nodes: 2});
replSet.startSet();
replSet.initiate();
let primary = replSet.getPrimary();
let testDB = primary.getDB(dbName);
const size = 5;
jsTest.log("Creating " + size + " test documents.");
var bulk = testDB.getCollection(collName).initializeUnorderedBulkOp();
for (var i = 0; i < size; ++i) {
bulk.insert({i: i});
}
assert.writeOK(bulk.execute());
replSet.awaitReplication();
const failpoint = "dropDatabaseHangAfterAllCollectionsDrop";
assert.commandWorked(primary.adminCommand({configureFailPoint: failpoint, mode: "alwaysOn"}));
// Run the dropDatabase command and stepdown the primary while it is running.
const awaitShell = startParallelShell(() => {
db.dropDatabase();
}, testDB.getMongo().port);
// Ensure the dropDatabase command has begun before stepping down.
checkLog.contains(primary,
"dropDatabase - fail point dropDatabaseHangAfterAllCollectionsDrop " +
"enabled. Blocking until fail point is disabled.");
assert.commandWorked(testDB.adminCommand({replSetStepDown: 60, force: true}));
replSet.waitForState(primary, ReplSetTest.State.SECONDARY);
assert.commandWorked(primary.adminCommand({configureFailPoint: failpoint, mode: "off"}));
awaitShell();
primary = replSet.getPrimary();
testDB = primary.getDB(dbName);
// Run dropDatabase on the new primary. The secondary (formerly the primary) should be able to
// drop the database too.
testDB.dropDatabase();
replSet.awaitReplication();
replSet.stopSet();
})();

View File

@ -152,8 +152,6 @@ public:
* Sets the 'drop-pending' state of this Database.
* This is done at the beginning of a dropDatabase operation and is used to reject subsequent
* collection creation requests on this database.
* Throws a UserAssertion if this is called on a Database that is already in a 'drop-pending'
* state.
* The database must be locked in MODE_X when calling this function.
*/
virtual void setDropPending(OperationContext* opCtx, bool dropPending) = 0;

View File

@ -370,10 +370,6 @@ Status DatabaseImpl::setProfilingLevel(OperationContext* opCtx, int newLevel) {
void DatabaseImpl::setDropPending(OperationContext* opCtx, bool dropPending) {
if (dropPending) {
invariant(opCtx->lockState()->isDbLockedForMode(name(), MODE_X));
uassert(ErrorCodes::DatabaseDropPending,
str::stream() << "Unable to drop database " << name()
<< " because it is already in the process of being dropped.",
!_dropPending);
_dropPending = true;
} else {
invariant(opCtx->lockState()->isDbLockedForMode(name(), MODE_IX));

View File

@ -128,13 +128,8 @@ TEST_F(DatabaseTest, SetDropPendingThrowsExceptionIfDatabaseIsAlreadyInADropPend
db->setDropPending(_opCtx.get(), true);
ASSERT_TRUE(db->isDropPending(_opCtx.get()));
ASSERT_THROWS_CODE_AND_WHAT(
db->setDropPending(_opCtx.get(), true),
AssertionException,
ErrorCodes::DatabaseDropPending,
(StringBuilder() << "Unable to drop database " << _nss.db()
<< " because it is already in the process of being dropped.")
.stringData());
db->setDropPending(_opCtx.get(), true);
ASSERT_TRUE(db->isDropPending(_opCtx.get()));
db->setDropPending(_opCtx.get(), false);
ASSERT_FALSE(db->isDropPending(_opCtx.get()));