summaryrefslogtreecommitdiff
path: root/jstests/core/txns
diff options
context:
space:
mode:
authorXiangyu Yao <xiangyu.yao@mongodb.com>2019-04-25 14:54:48 -0400
committerXiangyu Yao <xiangyu.yao@mongodb.com>2019-04-25 15:11:04 -0400
commit3a8c33cd95abaa7455b2c01726bdbf413cc938e5 (patch)
tree568bf26f33eaea6c5f6ccf87c2d58b438cd5fc0e /jstests/core/txns
parentaa4903255505f9072581e8ea4c63b93093f04508 (diff)
downloadmongo-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.js32
-rw-r--r--jstests/core/txns/transactions_profiling_with_drops.js87
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"}}});