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
|
/**
* Loading this file overrides Mongo.prototype.runCommand() with a function that wraps any
* aggregate command's pipeline inside a $facet stage, then appends an $unwind stage. This will
* yield the same results, but stress the logic of the $facet stage.
*/
(function() {
'use strict';
// Set the batch size of the $facet stage's buffer to be lower. This will further stress the
// batching logic, since most pipelines will fall below the default size of 100MB.
assert.commandWorked(
db.adminCommand({setParameter: 1, internalQueryFacetBufferSizeBytes: 1000}));
// Save a reference to the original runCommand method in the IIFE's scope.
// This scoping allows the original method to be called by the override below.
var originalRunCommand = Mongo.prototype.runCommand;
Mongo.prototype.runCommand = function(dbName, cmdObj, options) {
// Skip wrapping the pipeline in a $facet stage if it's not an aggregation, or if it's
// possibly an invalid one without a pipeline.
if (typeof cmdObj !== 'object' || cmdObj === null || !cmdObj.hasOwnProperty('aggregate') ||
!cmdObj.hasOwnProperty('pipeline') || !Array.isArray(cmdObj.pipeline)) {
return originalRunCommand.apply(this, arguments);
}
var originalPipeline = cmdObj.pipeline;
if (originalPipeline.length === 0) {
// Empty pipelines are disallowed within a $facet stage.
print('Not wrapping empty pipeline in a $facet stage');
return originalRunCommand.apply(this, arguments);
}
const stagesDisallowedInsideFacet =
['$changeStream', '$collStats', '$facet', '$geoNear', '$indexStats', '$merge', '$out'];
for (let stageSpec of originalPipeline) {
// Skip wrapping the pipeline in a $facet stage if it has an invalid stage
// specification.
if (typeof stageSpec !== 'object' || stageSpec === null) {
print('Not wrapping invalid pipeline in a $facet stage');
return originalRunCommand.apply(this, arguments);
}
if (stageSpec.hasOwnProperty('$match') && typeof stageSpec.$match === 'object' &&
stageSpec.$match !== null) {
if (stageSpec.$match.hasOwnProperty('$text')) {
// A $text search is disallowed within a $facet stage.
print('Not wrapping $text in a $facet stage');
return originalRunCommand.apply(this, arguments);
}
if (Object.keys(stageSpec.$match).length === 0) {
// Skip wrapping an empty $match stage, since it can be optimized out, resulting
// in an empty pipeline which is disallowed within a $facet stage.
print('Not wrapping empty $match in a $facet stage');
return originalRunCommand.apply(this, arguments);
}
}
// Skip wrapping the pipeline in a $facet stage if it contains a stage disallowed inside
// a $facet.
for (let disallowedStage of stagesDisallowedInsideFacet) {
if (stageSpec.hasOwnProperty(disallowedStage)) {
print('Not wrapping ' + disallowedStage + ' in a $facet stage');
return originalRunCommand.apply(this, arguments);
}
}
}
cmdObj.pipeline = [
{$facet: {originalPipeline: originalPipeline}},
{$unwind: '$originalPipeline'},
{$replaceRoot: {newRoot: '$originalPipeline'}},
];
return originalRunCommand.apply(this, arguments);
};
}());
|