summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorLouis Williams <louis.williams@mongodb.com>2019-04-12 11:39:39 -0400
committerLouis Williams <louis.williams@mongodb.com>2019-04-12 11:39:39 -0400
commitee9c8b7d7382cb7f91b72c2e680f18016754ee35 (patch)
tree5481fcb8a9a6514a63cba6b699287b5aef2e61a3 /jstests
parentc6560dd65c6a2eac9f83045e6197d7dbce512c6e (diff)
downloadmongo-ee9c8b7d7382cb7f91b72c2e680f18016754ee35.tar.gz
SERVER-40105 Improve diagnostic information in currentOp for writeConflicts and prepareConflicts
Diffstat (limited to 'jstests')
-rw-r--r--jstests/core/txns/currentop_blocked_operations.js83
-rw-r--r--jstests/core/txns/write_conflicts_with_non_txns.js3
2 files changed, 85 insertions, 1 deletions
diff --git a/jstests/core/txns/currentop_blocked_operations.js b/jstests/core/txns/currentop_blocked_operations.js
new file mode 100644
index 00000000000..8e51334bdff
--- /dev/null
+++ b/jstests/core/txns/currentop_blocked_operations.js
@@ -0,0 +1,83 @@
+/**
+ * Tests that currentOp reports debug information for operations that are blocked on transactions.
+ *
+ * @tags: [uses_transactions, uses_prepare_transaction]
+ */
+(function() {
+ "use strict";
+ load("jstests/core/txns/libs/prepare_helpers.js");
+
+ const dbName = "test";
+ const collName = "currentop_blocked_operations";
+ const testDB = db.getSiblingDB(dbName);
+ const testColl = testDB.getCollection(collName);
+
+ testColl.drop({writeConcern: {w: "majority"}});
+ assert.commandWorked(testDB.runCommand({create: collName, writeConcern: {w: "majority"}}));
+
+ const session = db.getMongo().startSession();
+ const sessionDB = session.getDatabase(dbName);
+ const sessionColl = sessionDB.getCollection(collName);
+
+ // Returns when the operation matching the 'matchExpr' is blocked, as evaluated by the
+ // 'isBlockedFunc'.
+ let waitForBlockedOp = function(matchExpr, isBlockedFunc) {
+ assert.soon(function() {
+ let cursor =
+ db.getSiblingDB("admin").aggregate([{$currentOp: {}}, {$match: matchExpr}]);
+ if (cursor.hasNext()) {
+ let op = cursor.next();
+ printjson(op);
+ return isBlockedFunc(op);
+ }
+ return false;
+ });
+ };
+
+ // This transaction will block conflicting non-transactional operations.
+ session.startTransaction();
+ assert.commandWorked(sessionColl.insert({_id: 2222}));
+
+ // This insert operation will encounter a WriteConflictException due to the unique key
+ // violation. It will block in an infinite write conflict loop until the transaction completes.
+ TestData.dbName = dbName;
+ TestData.collName = collName;
+ let awaitInsert = startParallelShell(function() {
+ let coll = db.getSiblingDB(TestData.dbName).getCollection(TestData.collName);
+ assert.commandWorked(coll.insert({_id: 2222, x: 0}));
+ });
+
+ // Wait for the counter to reach a high enough number to confirm the operation is retrying
+ // constantly.
+ waitForBlockedOp({"command.insert": collName}, function(op) {
+ return op.writeConflicts > 20;
+ });
+
+ assert.commandWorked(session.abortTransaction_forTesting());
+ awaitInsert();
+ assert.eq(1, testColl.find({_id: 2222, x: 0}).itcount());
+
+ // This prepared transaction will block conflicting non-transactional operations.
+ session.startTransaction();
+ assert.commandWorked(sessionColl.update({_id: 2222}, {$set: {x: 1}}));
+ PrepareHelpers.prepareTransaction(session);
+
+ // This update operation will encounter a prepare conflict due to the prepared transaction's
+ // modification to the same document. It will block without retrying until the prepared
+ // transaction completes.
+ TestData.dbName = dbName;
+ TestData.collName = collName;
+ let awaitUpdate = startParallelShell(function() {
+ let coll = db.getSiblingDB(TestData.dbName).getCollection(TestData.collName);
+ assert.commandWorked(coll.update({_id: 2222}, {$set: {x: 999}}));
+ });
+
+ // Expect at least one prepare conflict.
+ waitForBlockedOp({ns: testColl.getFullName(), op: "update"}, function(op) {
+ return op.prepareReadConflicts > 0;
+ });
+
+ assert.commandWorked(session.abortTransaction_forTesting());
+ awaitUpdate();
+ assert.eq(1, testColl.find({_id: 2222, x: 999}).itcount());
+})();
diff --git a/jstests/core/txns/write_conflicts_with_non_txns.js b/jstests/core/txns/write_conflicts_with_non_txns.js
index 5d7c1cdd589..c198c85084c 100644
--- a/jstests/core/txns/write_conflicts_with_non_txns.js
+++ b/jstests/core/txns/write_conflicts_with_non_txns.js
@@ -52,7 +52,8 @@
// Returns true if a single document insert has started running on the server.
function writeStarted() {
return testDB.currentOp().inprog.some(op => {
- return op.active && (op.ns === testColl.getFullName()) && (op.op === "insert");
+ return op.active && (op.ns === testColl.getFullName()) && (op.op === "insert") &&
+ (op.writeConflicts > 0);
});
}