diff options
author | Xiangyu Yao <xiangyu.yao@mongodb.com> | 2019-04-25 14:54:48 -0400 |
---|---|---|
committer | Xiangyu Yao <xiangyu.yao@mongodb.com> | 2019-04-25 15:11:04 -0400 |
commit | 3a8c33cd95abaa7455b2c01726bdbf413cc938e5 (patch) | |
tree | 568bf26f33eaea6c5f6ccf87c2d58b438cd5fc0e /jstests/core/txns | |
parent | aa4903255505f9072581e8ea4c63b93093f04508 (diff) | |
download | mongo-3a8c33cd95abaa7455b2c01726bdbf413cc938e5.tar.gz |
SERVER-39520 Use database IX lock for dropCollection
Diffstat (limited to 'jstests/core/txns')
-rw-r--r-- | jstests/core/txns/drop_collection_not_blocked_by_txn.js | 32 | ||||
-rw-r--r-- | jstests/core/txns/transactions_profiling_with_drops.js | 87 |
2 files changed, 76 insertions, 43 deletions
diff --git a/jstests/core/txns/drop_collection_not_blocked_by_txn.js b/jstests/core/txns/drop_collection_not_blocked_by_txn.js new file mode 100644 index 00000000000..626a7128a5c --- /dev/null +++ b/jstests/core/txns/drop_collection_not_blocked_by_txn.js @@ -0,0 +1,32 @@ +/** + * Test that drop collection only takes database IX lock and will not be blocked by transactions. + * + * @tags: [uses_transactions, requires_db_locking, assumes_unsharded_collection] + */ + +(function() { + "use strict"; + + let rst = new ReplSetTest({nodes: 1}); + rst.startSet(); + rst.initiate(); + + let db = rst.getPrimary().getDB("test"); + + assert.commandWorked(db.runCommand({insert: "a", documents: [{x: 1}]})); + assert.commandWorked(db.runCommand({insert: "b", documents: [{x: 1}]})); + + const session = db.getMongo().startSession(); + const sessionDb = session.getDatabase("test"); + + session.startTransaction(); + // This holds a database IX lock and a collection IX lock on "a". + sessionDb.a.insert({y: 1}); + + // This only requires database IX lock. + assert.commandWorked(db.runCommand({drop: "b"})); + + session.commitTransaction(); + + rst.stopSet(); +})(); diff --git a/jstests/core/txns/transactions_profiling_with_drops.js b/jstests/core/txns/transactions_profiling_with_drops.js index 418bc45330b..4c2c1c0047a 100644 --- a/jstests/core/txns/transactions_profiling_with_drops.js +++ b/jstests/core/txns/transactions_profiling_with_drops.js @@ -7,20 +7,17 @@ const dbName = "test"; const collName = "transactions_profiling_with_drops"; - const otherCollName = "other"; const adminDB = db.getSiblingDB("admin"); const testDB = db.getSiblingDB(dbName); - const otherColl = testDB[otherCollName]; const session = db.getMongo().startSession({causalConsistency: false}); const sessionDb = session.getDatabase(dbName); const sessionColl = sessionDb[collName]; sessionDb.runCommand({dropDatabase: 1, writeConcern: {w: "majority"}}); assert.commandWorked(sessionColl.insert({_id: "doc"}, {w: "majority"})); - assert.commandWorked(otherColl.insert({_id: "doc"}, {w: "majority"})); assert.commandWorked(sessionDb.runCommand({profile: 1, slowms: 1})); - jsTest.log("Test read profiling with drops."); + jsTest.log("Test read profiling with operation holding database X lock."); jsTest.log("Start transaction."); session.startTransaction(); @@ -32,39 +29,50 @@ profilerHasSingleMatchingEntryOrThrow( {profileDB: testDB, filter: {"command.comment": "read success"}}); - jsTest.log("Start a drop, which will hang."); - let awaitDrop = startParallelShell(function() { - db.getSiblingDB("test").runCommand({drop: "other", writeConcern: {w: "majority"}}); + // Lock 'test' database in X mode. + let lockShell = startParallelShell(function() { + assert.commandFailed(db.adminCommand({ + sleep: 1, + secs: 500, + lock: "w", + lockTarget: "test", + $comment: "transaction_profiling_with_drops lock sleep" + })); }); - // Wait for the drop to have a pending MODE_X lock on the database. - assert.soon( - function() { - return adminDB - .aggregate([ - {$currentOp: {}}, - {$match: {"command.drop": otherCollName, waitingForLock: true}} - ]) - .itcount() === 1; - }, - function() { - return "Failed to find drop in currentOp output: " + - tojson(adminDB.aggregate([{$currentOp: {}}])); + const waitForCommand = function(opFilter) { + let opId = -1; + assert.soon(function() { + const curopRes = testDB.currentOp(); + assert.commandWorked(curopRes); + const foundOp = curopRes["inprog"].filter(opFilter); + + if (foundOp.length == 1) { + opId = foundOp[0]["opid"]; + } + return (foundOp.length == 1); }); + return opId; + }; + + // Wait for sleep to appear in currentOp + let opId = waitForCommand( + op => (op["ns"] == "admin.$cmd" && + op["command"]["$comment"] == "transaction_profiling_with_drops lock sleep")); jsTest.log("Run a slow read. Profiling in the transaction should fail."); assert.sameMembers( [{_id: "doc"}], sessionColl.find({$where: "sleep(1000); return true;"}).comment("read failure").toArray()); session.commitTransaction(); - awaitDrop(); + + assert.commandWorked(testDB.killOp(opId)); + lockShell(); + profilerHasZeroMatchingEntriesOrThrow( {profileDB: testDB, filter: {"command.comment": "read failure"}}); - jsTest.log("Test write profiling with drops."); - - // Recreate the "other" collection so it can be dropped again. - assert.commandWorked(otherColl.insert({_id: "doc"}, {w: "majority"})); + jsTest.log("Test write profiling with operation holding database X lock."); jsTest.log("Start transaction."); session.startTransaction(); @@ -75,31 +83,24 @@ profilerHasSingleMatchingEntryOrThrow( {profileDB: testDB, filter: {"command.collation": {locale: "en"}}}); - jsTest.log("Start a drop, which will hang."); - awaitDrop = startParallelShell(function() { - db.getSiblingDB("test").runCommand({drop: "other", writeConcern: {w: "majority"}}); + // Lock 'test' database in X mode. + lockShell = startParallelShell(function() { + assert.commandFailed(db.getSiblingDB("test").adminCommand( + {sleep: 1, secs: 500, lock: "w", lockTarget: "test", $comment: "lock sleep"})); }); - // Wait for the drop to have a pending MODE_X lock on the database. - assert.soon( - function() { - return adminDB - .aggregate([ - {$currentOp: {}}, - {$match: {"command.drop": otherCollName, waitingForLock: true}} - ]) - .itcount() === 1; - }, - function() { - return "Failed to find drop in currentOp output: " + - tojson(adminDB.aggregate([{$currentOp: {}}])); - }); + // Wait for sleep to appear in currentOp + opId = waitForCommand( + op => (op["ns"] == "admin.$cmd" && op["command"]["$comment"] == "lock sleep")); jsTest.log("Run a slow write. Profiling in the transaction should fail."); assert.commandWorked(sessionColl.update( {$where: "sleep(1000); return true;"}, {$inc: {bad: 1}}, {collation: {locale: "fr"}})); session.commitTransaction(); - awaitDrop(); + + assert.commandWorked(testDB.killOp(opId)); + lockShell(); + profilerHasZeroMatchingEntriesOrThrow( {profileDB: testDB, filter: {"command.collation": {locale: "fr"}}}); |