summaryrefslogtreecommitdiff
path: root/jstests/libs/profiler.js
blob: 9b95bc60e88f8f1f39e2668f5fe377a593cd7759 (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Provides convenience methods for confirming system.profile content.

// Given a command, build its expected shape in the system profiler.
function buildCommandProfile(command, sharded) {
    let commandProfile = {};

    if (command.mapReduce) {
        // MapReduce is rewritten to an aggregate pipeline.
        commandProfile["command.aggregate"] = command.mapReduce;
    } else if (command.update) {
        // Updates are batched, but only allow using buildCommandProfile() for an update batch that
        // contains a single update, since the profiler generates separate entries for each update
        // in the batch.
        assert(command.updates.length == 1);
        for (let key in command.updates[0]) {
            commandProfile["command." + key] = command.updates[0][key];
        }
        // Though 'upsert' and 'multi' are optional fields, they are written with the default value
        // in the profiler.
        commandProfile["command.upsert"] = commandProfile["command.upsert"] || false;
        commandProfile["command.multi"] = commandProfile["command.multi"] || false;
    } else if (command.delete) {
        // Deletes are batched, but only allow using buildCommandProfile() for a delete batch that
        // contains a single delete, since the profiler generates separate entries for each delete
        // in the batch.
        assert(command.deletes.length == 1);
        for (let key in command.deletes[0]) {
            commandProfile["command." + key] = command.deletes[0][key];
        }
    } else {
        for (let key in command) {
            commandProfile["command." + key] = command[key];
        }
    }
    return commandProfile;
}

// Retrieve N latest system.profile entries.
function getNLatestProfilerEntries(profileDB, count, filter) {
    if (filter === null) {
        filter = {};
    }
    var cursor = profileDB.system.profile.find(filter).sort({$natural: -1}).limit(count);
    assert(
        cursor.hasNext(),
        "could not find any entries in the profile collection matching filter: " + tojson(filter));
    return cursor.toArray();
}

// Retrieve latest system.profile entry.
function getLatestProfilerEntry(profileDB, filter) {
    return getNLatestProfilerEntries(profileDB, 1, filter)[0];
}

/**
 * Throws an assertion if the profiler contains more than 'maxExpectedMatches' entries matching
 * "filter", or if there are no matches. Optional arguments "errorMsgFilter" and "errorMsgProj"
 * limit profiler output if this asserts.
 */
function profilerHasAtLeastOneAtMostNumMatchingEntriesOrThrow(
    {profileDB, filter, maxExpectedMatches, errorMsgFilter, errorMsgProj}) {
    assert(typeof maxExpectedMatches === 'number' && maxExpectedMatches > 0,
           "'maxExpectedMatches' must be a number > 0");

    const numMatches = profileDB.system.profile.find(filter).itcount();

    assert.gt(numMatches,
              0,
              "Expected at least 1 op matching: " + tojson(filter) + " in profiler " +
                  tojson(profileDB.system.profile.find(errorMsgFilter, errorMsgProj).toArray()));

    assert.lte(numMatches,
               maxExpectedMatches,
               "Expected at most " + maxExpectedMatches + " op(s) matching: " + tojson(filter) +
                   " in profiler " +
                   tojson(profileDB.system.profile.find(errorMsgFilter, errorMsgProj).toArray()));
}

/**
 * Throws an assertion if the profiler does not contain exactly 'numExpectedMatches' entries
 * matching "filter". Optional arguments "errorMsgFilter" and "errorMsgProj" limit profiler output
 * if this asserts.
 */
function profilerHasNumMatchingEntriesOrThrow(
    {profileDB, filter, numExpectedMatches, errorMsgFilter, errorMsgProj}) {
    assert(typeof numExpectedMatches === 'number' && numExpectedMatches >= 0,
           "'numExpectedMatches' must be a number >= 0");

    assert.eq(profileDB.system.profile.find(filter).itcount(),
              numExpectedMatches,
              "Expected exactly " + numExpectedMatches + " op(s) matching: " + tojson(filter) +
                  " in profiler " +
                  tojson(profileDB.system.profile.find(errorMsgFilter, errorMsgProj).toArray()));
}

/**
 * Throws an assertion if the profiler does not contain any entries matching "filter". Optional
 * arguments "errorMsgFilter" and "errorMsgProj" limit profiler output if this asserts.
 */
function profilerHasAtLeastOneMatchingEntryOrThrow(
    {profileDB, filter, errorMsgFilter, errorMsgProj}) {
    assert.gte(profileDB.system.profile.find(filter).itcount(),
               1,
               "Expected at least 1 op matching: " + tojson(filter) + " in profiler " +
                   tojson(profileDB.system.profile.find(errorMsgFilter, errorMsgProj).toArray()));
}

/**
 * Throws an assertion if the profiler does not contain exactly one entry matching "filter".
 * Optional arguments "errorMsgFilter" and "errorMsgProj" limit profiler output if this asserts.
 */
function profilerHasSingleMatchingEntryOrThrow({profileDB, filter, errorMsgFilter, errorMsgProj}) {
    profilerHasNumMatchingEntriesOrThrow({
        profileDB: profileDB,
        filter: filter,
        numExpectedMatches: 1,
        errorMsgFilter: errorMsgFilter,
        errorMsgProj: errorMsgProj
    });
}

/**
 * Throws an assertion if the profiler contains any entries matching "filter". Optional arguments
 * "errorMsgFilter" and "errorMsgProj" limit profiler output if this asserts.
 */
function profilerHasZeroMatchingEntriesOrThrow({profileDB, filter, errorMsgFilter, errorMsgProj}) {
    profilerHasNumMatchingEntriesOrThrow({
        profileDB: profileDB,
        filter: filter,
        numExpectedMatches: 0,
        errorMsgFilter: errorMsgFilter,
        errorMsgProj: errorMsgProj
    });
}