SERVER-115450 Update spill_to_disk_server_status.js to handle SBE generic scans (#45299)

GitOrigin-RevId: f247a29daa52cbc969aa5ffce39d18e450cb4454
This commit is contained in:
Catalin Sumanaru 2025-12-16 13:46:06 +00:00 committed by MongoDB Bot
parent 9c4b72367f
commit 874182abea
2 changed files with 34 additions and 13 deletions

View File

@ -7,7 +7,7 @@
import {configureFailPoint} from "jstests/libs/fail_point_util.js"; import {configureFailPoint} from "jstests/libs/fail_point_util.js";
import {FeatureFlagUtil} from "jstests/libs/feature_flag_util.js"; import {FeatureFlagUtil} from "jstests/libs/feature_flag_util.js";
import {funWithArgs} from "jstests/libs/parallel_shell_helpers.js"; import {funWithArgs} from "jstests/libs/parallel_shell_helpers.js";
import {getPlanStages, getQueryPlanner, getWinningPlanFromExplain} from "jstests/libs/query/analyze_plan.js"; import {getEngine, getWinningPlanFromExplain, isCollscan} from "jstests/libs/query/analyze_plan.js";
import {checkSbeFullyEnabled} from "jstests/libs/query/sbe_util.js"; import {checkSbeFullyEnabled} from "jstests/libs/query/sbe_util.js";
import {setParameter} from "jstests/noPassthrough/libs/server_parameter_helpers.js"; import {setParameter} from "jstests/noPassthrough/libs/server_parameter_helpers.js";
@ -145,6 +145,21 @@ function getServerStatusSpillingMetrics(serverStatus, stageName, getLegacy) {
} }
} }
function getClassicFailpointName(explain) {
const winningPlan = getWinningPlanFromExplain(explain);
return isCollscan(db, winningPlan) ? "hangCollScanDoWork" : "hangFetchDoWork";
}
function getSbeFailpointName(explain) {
const slotBasedPlan = getWinningPlanFromExplain(explain, true /* isSbePlan */);
const isScan = slotBasedPlan.stages.includes("scan");
if (isScan) {
const isGenericScan = slotBasedPlan.stages.includes("scan generic");
return isGenericScan ? "hangGenericScanGetNext" : "hangScanGetNext";
}
return "hangFetchGetNext";
}
function testSpillingMetrics({ function testSpillingMetrics({
stageName, stageName,
expectedSpillingMetrics, expectedSpillingMetrics,
@ -156,23 +171,14 @@ function testSpillingMetrics({
// Check whether the aggregation uses SBE. // Check whether the aggregation uses SBE.
const explain = db[collName].explain().aggregate(pipeline); const explain = db[collName].explain().aggregate(pipeline);
jsTestLog(explain); const isSbePlan = getEngine(explain) === "sbe";
const queryPlanner = getQueryPlanner(explain);
const isSbe = queryPlanner.winningPlan.hasOwnProperty("slotBasedPlan");
const isCollScan = getPlanStages(getWinningPlanFromExplain(explain), "COLLSCAN").length > 0;
// Collect the serverStatus metrics before the aggregation runs. // Collect the serverStatus metrics before the aggregation runs.
jsTestLog(stageName);
const spillingMetrics = []; const spillingMetrics = [];
spillingMetrics.push(getServerStatusSpillingMetrics(db.serverStatus(), stageName, getLegacy)); spillingMetrics.push(getServerStatusSpillingMetrics(db.serverStatus(), stageName, getLegacy));
// Run an aggregation and hang at the fail point in the middle of the processing. // Run an aggregation and hang at the fail point in the middle of the processing.
let failPointName; const failPointName = isSbePlan ? getSbeFailpointName(explain) : getClassicFailpointName(explain);
if (isSbe) {
failPointName = isCollScan ? "hangScanGetNext" : "hangFetchGetNext";
} else {
failPointName = isCollScan ? "hangCollScanDoWork" : "hangFetchDoWork";
}
const failPoint = configureFailPoint(db, failPointName, {} /* data */, {"skip": nDocs / 2}); const failPoint = configureFailPoint(db, failPointName, {} /* data */, {"skip": nDocs / 2});
const awaitShell = startParallelShell( const awaitShell = startParallelShell(
funWithArgs( funWithArgs(
@ -204,7 +210,13 @@ function testSpillingMetrics({
} }
// Assert the final spilling metrics are as expected. // Assert the final spilling metrics are as expected.
assert.docEq(isSbe ? expectedSbeSpillingMetrics : expectedSpillingMetrics, spillingMetrics[2], spillingMetrics); const expected = isSbePlan ? expectedSbeSpillingMetrics : expectedSpillingMetrics;
const actual = spillingMetrics[2];
assert.docEq(
expected,
actual,
`Expected ${expected} but found ${actual}. spillingMetrics=${tojson(spillingMetrics)}`,
);
} }
testSpillingMetrics({ testSpillingMetrics({

View File

@ -48,6 +48,7 @@
#include "mongo/platform/compiler.h" #include "mongo/platform/compiler.h"
#include "mongo/util/assert_util.h" #include "mongo/util/assert_util.h"
#include "mongo/util/concurrency/admission_context.h" #include "mongo/util/concurrency/admission_context.h"
#include "mongo/util/fail_point.h"
#include "mongo/util/overloaded_visitor.h" // IWYU pragma: keep #include "mongo/util/overloaded_visitor.h" // IWYU pragma: keep
#include "mongo/util/str.h" #include "mongo/util/str.h"
@ -58,6 +59,11 @@
#include <boost/optional/optional.hpp> #include <boost/optional/optional.hpp>
namespace mongo { namespace mongo {
namespace {
MONGO_FAIL_POINT_DEFINE(hangGenericScanGetNext);
} // namespace
namespace sbe { namespace sbe {
GenericScanStage::GenericScanStage(UUID collUuid, GenericScanStage::GenericScanStage(UUID collUuid,
DatabaseName dbName, DatabaseName dbName,
@ -108,6 +114,9 @@ std::unique_ptr<PlanStage> GenericScanStage::clone() const {
} }
PlanState GenericScanStage::getNext() { PlanState GenericScanStage::getNext() {
if (MONGO_unlikely(hangGenericScanGetNext.shouldFail())) {
hangGenericScanGetNext.pauseWhileSet();
}
auto optTimer(getOptTimer(_opCtx)); auto optTimer(getOptTimer(_opCtx));
handleInterruptAndSlotAccess(); handleInterruptAndSlotAccess();