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:
parent
330c59b671
commit
796ae56683
60
jstests/noPassthrough/step_down_during_drop_database.js
Normal file
60
jstests/noPassthrough/step_down_during_drop_database.js
Normal 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();
|
||||
})();
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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()));
|
||||
|
Loading…
Reference in New Issue
Block a user