summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/explain_sort_exec_stats.js
blob: f21e82c9d28e64656352c0ed06db73f8c83764d5 (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
/**
 * Tests that $sort stage reports the correct stats when explain is run with
 * different verbosities.
 */
(function() {
"use strict";

load("jstests/libs/analyze_plan.js");  // For getAggPlanStages().
load("jstests/libs/sbe_util.js");      // For checkSBEEnabled.

const conn = MongoRunner.runMongod();
const db = conn.getDB("test");
const coll = db.explain_sort_stage_exec_stats;
coll.drop();

const isSbeEnabled = checkSBEEnabled(db);
const bigStr = Array(1025).toString();  // 1KB of ','
const lowMaxMemoryLimit = 5000;
const nDocs = 1000;

const bulk = coll.initializeUnorderedBulkOp();
for (let i = 1; i <= nDocs; i++) {
    bulk.insert({_id: i, a: i, b: i, bigStr: bigStr});
}
assert.commandWorked(bulk.execute());

const pipelines = [
    {sortUsesDocumentSources: false, pipeline: [{$sort: {_id: 1, b: -1}}]},  // no limit
    {
        sortUsesDocumentSources: true,
        pipeline: [{$_internalInhibitOptimization: {}}, {$sort: {_id: 1, b: -1}}]
    },  // no limit document sources
    {
        sortUsesDocumentSources: false,
        pipeline: [{$sort: {_id: 1, b: -1}}, {$limit: nDocs / 10}]
    },  // top k sorter
    {
        sortUsesDocumentSources: true,
        pipeline:
            [{$_internalInhibitOptimization: {}}, {$sort: {_id: 1, b: -1}}, {$limit: nDocs / 10}]
    },  // top k sorter document sources
];

function checkSortSpillStats(explainOutput, shouldSpill, sortUsesDocumentSources) {
    let execStage = {};
    if (sortUsesDocumentSources) {
        execStage = getAggPlanStage(explainOutput, "$sort");
    } else if (isSbeEnabled) {
        execStage = getAggPlanStage(explainOutput, "sort");
    } else {
        execStage = getAggPlanStage(explainOutput, "SORT");
    }
    assert.neq(null, execStage, explainOutput);

    assert(execStage.hasOwnProperty("usedDisk"), execStage);
    assert(execStage.hasOwnProperty("spills"), execStage);
    assert(execStage.hasOwnProperty("spilledDataStorageSize"), execStage);

    const usedDisk = execStage.usedDisk;
    const spills = execStage.spills;
    const spilledDataStorageSize = execStage.spilledDataStorageSize;

    if (shouldSpill) {
        assert(usedDisk, explainOutput);
        assert.gt(spills, 0, explainOutput);
        assert.gt(spilledDataStorageSize, 0, explainOutput);
    } else {
        assert(!usedDisk, explainOutput);
        assert.eq(spills, 0, explainOutput);
        assert.eq(spilledDataStorageSize, 0, explainOutput);
    }
}

let explainOutput = {};

pipelines.forEach(function(pipeline) {
    // Set MaxMemory low to force spill to disk.
    const originalMemoryLimit = assert.commandWorked(db.adminCommand(
        {setParameter: 1, internalQueryMaxBlockingSortMemoryUsageBytes: lowMaxMemoryLimit}));

    explainOutput = coll.explain("executionStats").aggregate(pipeline.pipeline);
    checkSortSpillStats(explainOutput, true /*shouldSpill*/, pipeline.sortUsesDocumentSources);

    // Set MaxMemory to back to the original value.
    assert.commandWorked(db.adminCommand(
        {setParameter: 1, internalQueryMaxBlockingSortMemoryUsageBytes: originalMemoryLimit.was}));

    explainOutput = coll.explain("executionStats").aggregate(pipeline.pipeline);
    checkSortSpillStats(explainOutput, false /*shouldSpill*/, pipeline.sortUsesDocumentSources);
});

MongoRunner.stopMongod(conn);
}());