summaryrefslogtreecommitdiff
path: root/jstests/core/currentop_waiting_for_latch.js
blob: c8a18d57d84f13d12caed768a61bf177702f0e58 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/**
 * Tests that a backtrace will appear in the $currentOp output if the backtrace option is
 * set to true and there is a latch timeout.
 *
 * @tags: [assumes_read_concern_unchanged, assumes_read_preference_unchanged, no_selinux]
 */
(function() {
"use strict";

const adminDB = db.getSiblingDB("admin");

// This test causes an extra thread with a self-contended lock to be created so that currentOp can
// observe its DiagnosticInfo. This mutex is test-only, and is at a lower level than the
// SessionCatalog's mutex, so we pass 'idleSessions: false' to avoid scanning idle sessions during
// currentOp and hitting a latch violation.
const getCurrentOp = function() {
    jsTestLog("Getting $currentOp");
    let result = adminDB
                     .aggregate(
                         [
                             {
                                 $currentOp: {
                                     allUsers: true,
                                     idleConnections: true,
                                     idleSessions: false,
                                     localOps: true,
                                     backtrace: true
                                 }
                             },
                         ],
                         {readConcern: {level: "local"}})
                     .toArray();
    assert(result);
    return result;
};

const blockedOpClients = {
    "DiagnosticCaptureTestLatch": {"seen": false},
    "DiagnosticCaptureTestInterruptible": {"seen": false},
};

const getClientName = function() {
    let myUri = adminDB.runCommand({whatsmyuri: 1}).you;
    return adminDB.aggregate([{$currentOp: {localOps: true}}, {$match: {client: myUri}}])
        .toArray()[0]
        .desc;
};

let clientName = getClientName();

try {
    assert.commandWorked(db.adminCommand({
        "configureFailPoint": 'currentOpSpawnsThreadWaitingForLatch',
        "mode": 'alwaysOn',
        "data": {
            'clientName': clientName,
        },
    }));

    const verifyResult = function(result) {
        jsTestLog("Verifying " + tojson(result));
        assert(result);
        assert(result.hasOwnProperty("waitingForLatch"));
        assert(result["waitingForLatch"].hasOwnProperty("timestamp"));
        assert(result["waitingForLatch"].hasOwnProperty("captureName"));

        /* Absent until we have efficient enough backtracing
        assert(result["waitingForLatch"].hasOwnProperty("backtrace"));
        result["waitingForLatch"]["backtrace"].forEach(function(frame) {
            assert(frame.hasOwnProperty("addr"));
            assert(typeof frame["addr"] === "string");
            assert(frame.hasOwnProperty("path"));
            assert(typeof frame["path"] === "string");
        });
        */
    };
    getCurrentOp().forEach(function(op) {
        const name = op["desc"];
        if (name in blockedOpClients) {
            jsTestLog("Verifying " + op["desc"]);
            verifyResult(op);
            blockedOpClients[name].seen = true;
        }
    });

    // Make sure we saw the ops we expected
    for (const name in blockedOpClients) {
        assert(blockedOpClients[name].seen);
    }
} finally {
    assert.commandWorked(db.adminCommand(
        {"configureFailPoint": 'currentOpSpawnsThreadWaitingForLatch', "mode": 'off'}));

    getCurrentOp().forEach(function(op) {
        const name = op["desc"];
        if (name in blockedOpClients) {
            assert(!op.hasOwnProperty("waitingForLatch"));
        }
    });
}
})();