Skip to content

Commit 906cfb1

Browse files
committed
SERVER-14123 prevent the explain BSONObj from growing too large
1 parent 18ee068 commit 906cfb1

File tree

3 files changed

+34
-3
lines changed

3 files changed

+34
-3
lines changed

src/mongo/db/query/explain_plan.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,18 @@ namespace mongo {
455455
}
456456
}
457457

458-
void statsToBSON(const PlanStageStats& stats, BSONObjBuilder* bob) {
458+
void statsToBSON(const PlanStageStats& stats,
459+
BSONObjBuilder* bob,
460+
BSONObjBuilder* topLevelBob) {
459461
invariant(bob);
462+
invariant(topLevelBob);
463+
464+
// Stop as soon as the BSON object we're building exceeds 10 MB.
465+
static const int kMaxStatsBSONSize = 10 * 1024 * 1024;
466+
if (topLevelBob->len() > kMaxStatsBSONSize) {
467+
bob->append("warning", "stats tree exceeded 10 MB");
468+
return;
469+
}
460470

461471
// Common details.
462472
bob->append("type", stageTypeString(stats.stageType));
@@ -521,9 +531,12 @@ namespace mongo {
521531
// TODO: how much do we really want here? we should separate runtime stats vs. tree
522532
// structure (soln tostring).
523533
bob->append("keyPattern", spec->keyPattern.toString());
524-
bob->append("boundsVerbose", spec->indexBoundsVerbose);
525534
bob->appendNumber("isMultiKey", spec->isMultiKey);
526535

536+
// The verbose bounds can get large. Truncate to 1 MB.
537+
static const int kMaxVerboseBoundsSize = 1024 * 1024;
538+
bob->append("boundsVerbose", spec->indexBoundsVerbose.substr(0, kMaxVerboseBoundsSize));
539+
527540
bob->appendNumber("yieldMovedCursor", spec->yieldMovedCursor);
528541
bob->appendNumber("dupsTested", spec->dupsTested);
529542
bob->appendNumber("dupsDropped", spec->dupsDropped);
@@ -566,11 +579,15 @@ namespace mongo {
566579
BSONArrayBuilder childrenBob(bob->subarrayStart("children"));
567580
for (size_t i = 0; i < stats.children.size(); ++i) {
568581
BSONObjBuilder childBob(childrenBob.subobjStart());
569-
statsToBSON(*stats.children[i], &childBob);
582+
statsToBSON(*stats.children[i], &childBob, topLevelBob);
570583
}
571584
childrenBob.doneFast();
572585
}
573586

587+
void statsToBSON(const PlanStageStats& stats, BSONObjBuilder* bob) {
588+
statsToBSON(stats, bob, bob);
589+
}
590+
574591
BSONObj statsToBSON(const PlanStageStats& stats) {
575592
BSONObjBuilder bob;
576593
statsToBSON(stats, &bob);

src/mongo/db/query/explain_plan.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ namespace mongo {
8585
*/
8686
void getPlanInfo(const QuerySolution& soln, PlanInfo** infoOut);
8787

88+
void statsToBSON(const PlanStageStats& stats,
89+
BSONObjBuilder* bob,
90+
BSONObjBuilder* topLevelBob);
91+
8892
void statsToBSON(const PlanStageStats& stats, BSONObjBuilder* bob);
8993

9094
BSONObj statsToBSON(const PlanStageStats& stats);

src/mongo/db/query/index_bounds.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,19 @@ namespace mongo {
222222

223223
fieldBuilder.append(
224224
static_cast<BSONArray>(intervalBuilder.arr().clientReadable()));
225+
226+
// If the bounds object gets too large, truncate it.
227+
static const int kMaxBoundsSize = 1024 * 1024;
228+
if (builder.len() > kMaxBoundsSize) {
229+
intervalBuilder.doneFast();
230+
fieldBuilder.append(BSON("warning" << "bounds obj exceeds 1 MB"));
231+
fieldBuilder.doneFast();
232+
return builder.obj();
233+
}
225234
}
226235
}
227236
}
237+
228238
return builder.obj();
229239
}
230240

0 commit comments

Comments
 (0)