diff options
author | Ian Boros <ian.boros@mongodb.com> | 2019-10-04 15:38:42 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-10-04 15:38:42 +0000 |
commit | 1f0ae1c45604798888f8b2425475a473d7265bd5 (patch) | |
tree | c331eebf5795422507c4826c4219c303a20edced /src/mongo/db/pipeline | |
parent | 2d671ab90e0282773ea89f1860705503dd5bf74d (diff) | |
download | mongo-1f0ae1c45604798888f8b2425475a473d7265bd5.tar.gz |
SERVER-43202 propagate errors from interrupts during yielding
Diffstat (limited to 'src/mongo/db/pipeline')
-rw-r--r-- | src/mongo/db/pipeline/dependencies.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/pipeline/pipeline_d.cpp | 85 |
2 files changed, 60 insertions, 30 deletions
diff --git a/src/mongo/db/pipeline/dependencies.cpp b/src/mongo/db/pipeline/dependencies.cpp index 1586a68f96b..8c92cd5c751 100644 --- a/src/mongo/db/pipeline/dependencies.cpp +++ b/src/mongo/db/pipeline/dependencies.cpp @@ -102,6 +102,11 @@ BSONObj DepsTracker::toProjection() const { } last = field + '.'; + + // We should only have dependencies on fields that are valid in aggregation. Create a + // FieldPath to check this. + FieldPath fieldPath(field); + bb.append(field, 1); } diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp index 4a4f4b7ea14..69540a8b8bd 100644 --- a/src/mongo/db/pipeline/pipeline_d.cpp +++ b/src/mongo/db/pipeline/pipeline_d.cpp @@ -96,6 +96,39 @@ using std::unique_ptr; using write_ops::Insert; namespace { + +/** + * Return whether the given sort spec can be used in a find() sort. + */ +bool canSortBePushedDown(const BSONObj& sortSpec) { + // Return whether or not a sort stage can be pushed into the query layer. + for (auto&& elem : sortSpec) { + if (BSONType::Object != elem.type()) { + continue; + } + + BSONObj subObj = elem.embeddedObject(); + if (subObj.nFields() != 1) { + continue; + } + + BSONElement firstElem = subObj.firstElement(); + if (firstElem.fieldNameStringData() == "$meta" && firstElem.type() == BSONType::String) { + // Indeed it's a $meta. + + // Technically sorting by {$meta: "textScore"} can be done in find() but requires a + // corresponding projection, so for simplicity we don't support it. + if (firstElem.valueStringData() == "textScore" || + firstElem.valueStringData() == "randVal") { + return false; + } + } + } + + return true; +} + + /** * Returns a PlanExecutor which uses a random cursor to sample documents if successful. Returns {} * if the storage engine doesn't support random cursors, or if 'sampleSize' is a large enough @@ -233,7 +266,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> attemptToGetExe return distinctExecutor.getStatus().withContext( "Unable to use distinct scan to optimize $group stage"); } else if (!distinctExecutor.getValue()) { - return {ErrorCodes::OperationFailed, + return {ErrorCodes::NoQueryExecutionPlans, "Unable to use distinct scan to optimize $group stage"}; } else { return distinctExecutor; @@ -680,17 +713,16 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep pipeline->addInitialSource(groupTransform); return swExecutorGrouped; - } else if (swExecutorGrouped == ErrorCodes::QueryPlanKilled) { - return {ErrorCodes::OperationFailed, - str::stream() << "Failed to determine whether query system can provide a " - "DISTINCT_SCAN grouping: " - << swExecutorGrouped.getStatus().toString()}; + } else if (swExecutorGrouped != ErrorCodes::NoQueryExecutionPlans) { + return swExecutorGrouped.getStatus().withContext( + "Failed to determine whether query system can provide a " + "DISTINCT_SCAN grouping"); } } const BSONObj emptyProjection; - const BSONObj metaSortProjection = BSON("$meta" - << "sortKey"); + const BSONObj metaSortProjection = BSON("$sortKey" << BSON("$meta" + << "sortKey")); // The only way to get meta information (e.g. the text score) is to let the query system handle // the projection. In all other cases, unless the query system can do an index-covered @@ -700,7 +732,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep plannerOpts |= QueryPlannerParams::NO_UNCOVERED_PROJECTIONS; } - if (sortStage) { + if (sortStage && canSortBePushedDown(*sortObj)) { // See if the query system can provide a non-blocking sort. auto swExecutorSort = attemptToGetExecutor(opCtx, @@ -736,11 +768,11 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep if (swExecutorSortAndProj.isOK()) { // Success! We have a non-blocking sort and a covered projection. exec = std::move(swExecutorSortAndProj.getValue()); - } else if (swExecutorSortAndProj == ErrorCodes::QueryPlanKilled) { - return {ErrorCodes::OperationFailed, - str::stream() << "Failed to determine whether query system can provide a " - "covered projection in addition to a non-blocking sort: " - << swExecutorSortAndProj.getStatus().toString()}; + } else if (swExecutorSortAndProj != ErrorCodes::NoQueryExecutionPlans) { + + return swExecutorSortAndProj.getStatus().withContext( + "Failed to determine whether query system can provide a " + "covered projection in addition to a non-blocking sort"); } else { // The query system couldn't cover the projection. *projectionObj = BSONObj(); @@ -755,20 +787,15 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep pipeline->_sources.push_front(sortStage->getLimitSrc()); } return std::move(exec); - } else if (swExecutorSort == ErrorCodes::QueryPlanKilled) { - return { - ErrorCodes::OperationFailed, - str::stream() - << "Failed to determine whether query system can provide a non-blocking sort: " - << swExecutorSort.getStatus().toString()}; + } else if (swExecutorSort != ErrorCodes::NoQueryExecutionPlans) { + return swExecutorSort.getStatus().withContext( + "Failed to determine whether query system can provide a non-blocking sort"); } - // The query system can't provide a non-blocking sort. - *sortObj = BSONObj(); } - // Either there was no $sort stage, or the query system could not provide a non-blocking - // sort. - dassert(sortObj->isEmpty()); + // Either there's no sort or the query system can't provide a non-blocking sort. + *sortObj = BSONObj(); + *projectionObj = removeSortKeyMetaProjection(*projectionObj); const auto metadataRequired = deps.getAllRequiredMetadataTypes(); if (metadataRequired.size() == 1 && @@ -796,11 +823,9 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep if (swExecutorProj.isOK()) { // Success! We have a covered projection. return std::move(swExecutorProj.getValue()); - } else if (swExecutorProj == ErrorCodes::QueryPlanKilled) { - return {ErrorCodes::OperationFailed, - str::stream() - << "Failed to determine whether query system can provide a covered projection: " - << swExecutorProj.getStatus().toString()}; + } else if (swExecutorProj != ErrorCodes::NoQueryExecutionPlans) { + return swExecutorProj.getStatus().withContext( + "Failed to determine whether query system can provide a covered projection"); } // The query system couldn't provide a covered or simple uncovered projection. |