summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/agg_configurable_memory_limits.js
blob: 6ccb3e1434eb37698a2134bf313d451cfd54a80c (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
// Tests that certain aggregation operators have configurable memory limits.
(function() {
"use strict";

const conn = MongoRunner.runMongod();
assert.neq(null, conn, "mongod was unable to start up");
const db = conn.getDB("test");
const coll = db.agg_configurable_memory_limit;

// The approximate size of the strings below is 22-25 bytes, so configure one memory limit such that
// 100 of these strings will surely exceed it but 24 of them won't, and another such that 24 will
// exceed as well.
const stringSize = 22;
const nSetBaseline = 20;
const memLimitArray = nSetBaseline * 5 * stringSize / 2;
const memLimitSet = (nSetBaseline + 4) * stringSize / 2;

const bulk = coll.initializeUnorderedBulkOp();
for (let i = 0; i < nSetBaseline; i++) {
    bulk.insert({_id: 5 * i + 0, y: "string 0"});
    bulk.insert({_id: 5 * i + 1, y: "string 1"});
    bulk.insert({_id: 5 * i + 2, y: "string 2"});
    bulk.insert({_id: 5 * i + 3, y: "string 3"});
    bulk.insert({_id: 5 * i + 4, y: "string " + 5 * i + 4});
}
assert.commandWorked(bulk.execute());

(function testInternalQueryMaxPushBytesSetting() {
    // Test that the default 100MB memory limit isn't reached with our data.
    assert.doesNotThrow(() => coll.aggregate([{$group: {_id: null, strings: {$push: "$y"}}}]));

    // Now lower the limit to test that it's configuration is obeyed.
    assert.commandWorked(
        db.adminCommand({setParameter: 1, internalQueryMaxPushBytes: memLimitArray}));
    assert.throwsWithCode(() => coll.aggregate([{$group: {_id: null, strings: {$push: "$y"}}}]),
                          ErrorCodes.ExceededMemoryLimit);
}());

(function testInternalQueryMaxAddToSetBytesSetting() {
    // Test that the default 100MB memory limit isn't reached with our data.
    assert.doesNotThrow(() => coll.aggregate([{$group: {_id: null, strings: {$addToSet: "$y"}}}]));

    // Test that $addToSet needs a tighter limit than $push (because some of the strings are the
    // same).
    assert.commandWorked(
        db.adminCommand({setParameter: 1, internalQueryMaxAddToSetBytes: memLimitArray}));
    assert.doesNotThrow(() => coll.aggregate([{$group: {_id: null, strings: {$addToSet: "$y"}}}]));

    assert.commandWorked(
        db.adminCommand({setParameter: 1, internalQueryMaxAddToSetBytes: memLimitSet}));
    assert.throwsWithCode(() => coll.aggregate([{$group: {_id: null, strings: {$addToSet: "$y"}}}]),
                          ErrorCodes.ExceededMemoryLimit);
}());

(function testInternalQueryTopNAccumulatorBytesSetting() {
    // Capture the default value of 'internalQueryTopNAccumulatorBytes' to reset in between runs.
    const res = assert.commandWorked(
        db.adminCommand({getParameter: 1, internalQueryTopNAccumulatorBytes: 1}));
    const topNDefault = res["internalQueryTopNAccumulatorBytes"];

    // Test that the 'n' family of accumulators behaves similarly.
    for (const op of ["$firstN", "$lastN", "$minN", "$maxN", "$topN", "$bottomN"]) {
        let spec = {n: 200};

        // $topN/$bottomN both require a sort specification.
        if (op === "$topN" || op === "$bottomN") {
            spec["sortBy"] = {y: 1};
            spec["output"] = "$y";
        } else {
            // $firstN/$lastN/$minN/$maxN accept 'input'.
            spec["input"] = "$y";
        }

        // First, verify that the accumulator doesn't throw.
        db.adminCommand({setParameter: 1, internalQueryTopNAccumulatorBytes: topNDefault});
        assert.doesNotThrow(() => coll.aggregate([{$group: {_id: null, strings: {[op]: spec}}}]));

        // Then, verify that the memory limit throws when lowered.
        db.adminCommand({setParameter: 1, internalQueryTopNAccumulatorBytes: 100});
        assert.throwsWithCode(() => coll.aggregate([{$group: {_id: null, strings: {[op]: spec}}}]),
                              ErrorCodes.ExceededMemoryLimit);
    }
}());

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