summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/sbe_stage_builder_index_scan.cpp
diff options
context:
space:
mode:
authorMihai Andrei <mihai.andrei@10gen.com>2021-04-28 13:31:52 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-04-28 14:08:27 +0000
commite3445d104be4422e841dbdbbd4272d696030ac2a (patch)
tree4944e9779d10a45c00d4456a6afaefc66b010445 /src/mongo/db/query/sbe_stage_builder_index_scan.cpp
parent45935cb14649071672bff515c70c72e43973ef4b (diff)
downloadmongo-e3445d104be4422e841dbdbbd4272d696030ac2a.tar.gz
SERVER-51137 [SBE] Add logging for index key found with reference to non-existent RID
Diffstat (limited to 'src/mongo/db/query/sbe_stage_builder_index_scan.cpp')
-rw-r--r--src/mongo/db/query/sbe_stage_builder_index_scan.cpp136
1 files changed, 110 insertions, 26 deletions
diff --git a/src/mongo/db/query/sbe_stage_builder_index_scan.cpp b/src/mongo/db/query/sbe_stage_builder_index_scan.cpp
index 4a002a73aaa..ac988f203b6 100644
--- a/src/mongo/db/query/sbe_stage_builder_index_scan.cpp
+++ b/src/mongo/db/query/sbe_stage_builder_index_scan.cpp
@@ -261,6 +261,7 @@ makeIntervalsFromIndexBounds(const IndexBounds& bounds,
* nlj [indexIdSlot] [lowKeySlot, highKeySlot]
* left
* project [indexIdSlot = <indexName>,
+ * indexKeyPatternSlot = <index key pattern>,
* lowKeySlot = getField (unwindSlot, "l"),
* highKeySlot = getField (unwindSlot, "h")]
* unwind unwindSlot indexSlot boundsSlot false
@@ -280,6 +281,7 @@ std::pair<sbe::value::SlotId, std::unique_ptr<sbe::PlanStage>>
generateOptimizedMultiIntervalIndexScan(
const CollectionPtr& collection,
const std::string& indexName,
+ const BSONObj& keyPattern,
bool forward,
std::vector<std::pair<std::unique_ptr<KeyString::Value>, std::unique_ptr<KeyString::Value>>>
intervals,
@@ -288,6 +290,7 @@ generateOptimizedMultiIntervalIndexScan(
boost::optional<sbe::value::SlotId> snapshotIdSlot,
boost::optional<sbe::value::SlotId> indexIdSlot,
boost::optional<sbe::value::SlotId> recordSlot,
+ boost::optional<sbe::value::SlotId> indexKeyPatternSlot,
sbe::value::SlotIdGenerator* slotIdGenerator,
PlanYieldPolicy* yieldPolicy,
PlanNodeId planNodeId,
@@ -343,6 +346,13 @@ generateOptimizedMultiIntervalIndexScan(
projects.emplace(*indexIdSlot, makeConstant(indexName));
}
+ if (indexKeyPatternSlot) {
+ auto [bsonObjTag, bsonObjVal] =
+ sbe::value::copyValue(sbe::value::TypeTags::bsonObject,
+ sbe::value::bitcastFrom<const char*>(keyPattern.objdata()));
+ projects.emplace(*indexKeyPatternSlot, makeConstant(bsonObjTag, bsonObjVal));
+ }
+
// Add another project stage to extract low and high keys from each value produced by unwind and
// bind the keys to the 'lowKeySlot' and 'highKeySlot'.
auto project =
@@ -367,6 +377,10 @@ generateOptimizedMultiIntervalIndexScan(
outerSv.push_back(*indexIdSlot);
}
+ if (indexKeyPatternSlot) {
+ outerSv.push_back(*indexKeyPatternSlot);
+ }
+
// Finally, get the keys from the outer side and feed them to the inner side (ixscan).
return {recordIdSlot,
sbe::makeS<sbe::LoopJoinStage>(std::move(project),
@@ -411,22 +425,24 @@ std::pair<sbe::value::SlotId, std::unique_ptr<sbe::PlanStage>> makeAnchorBranchF
std::pair<sbe::value::SlotId, std::unique_ptr<sbe::PlanStage>>
makeRecursiveBranchForGenericIndexScan(const CollectionPtr& collection,
const std::string& indexName,
+ const BSONObj& keyPattern,
const sbe::CheckBoundsParams& params,
sbe::SpoolId spoolId,
sbe::IndexKeysInclusionSet indexKeysToInclude,
sbe::value::SlotVector savedIndexKeySlots,
boost::optional<sbe::value::SlotId> snapshotIdSlot,
boost::optional<sbe::value::SlotId> indexIdSlot,
- boost::optional<sbe::value::SlotId> keyStringSlot,
+ boost::optional<sbe::value::SlotId> indexKeySlot,
+ boost::optional<sbe::value::SlotId> indexKeyPatternSlot,
sbe::value::SlotIdGenerator* slotIdGenerator,
PlanYieldPolicy* yieldPolicy,
PlanNodeId planNodeId,
sbe::LockAcquisitionCallback lockAcquisitionCallback) {
// The IndexScanStage in this branch will always produce a KeyString. As such, we use
- // 'keyStringSlot' if is defined and generate a new slot otherwise.
+ // 'indexKeySlot' if is defined and generate a new slot otherwise.
sbe::value::SlotId resultSlot;
- if (keyStringSlot) {
- resultSlot = *keyStringSlot;
+ if (indexKeySlot) {
+ resultSlot = *indexKeySlot;
} else {
resultSlot = slotIdGenerator->generate();
}
@@ -443,6 +459,14 @@ makeRecursiveBranchForGenericIndexScan(const CollectionPtr& collection,
// Construct a copy of 'indexName' to project for use in the index consistency check.
projects.emplace(*indexIdSlot, makeConstant(indexName));
}
+
+ if (indexKeyPatternSlot) {
+ auto [bsonObjTag, bsonObjVal] =
+ sbe::value::copyValue(sbe::value::TypeTags::bsonObject,
+ sbe::value::bitcastFrom<const char*>(keyPattern.objdata()));
+ projects.emplace(*indexKeyPatternSlot, makeConstant(bsonObjTag, bsonObjVal));
+ }
+
auto project = sbe::makeS<sbe::ProjectStage>(
sbe::makeS<sbe::LimitSkipStage>(
sbe::makeS<sbe::CoScanStage>(planNodeId), 1, boost::none, planNodeId),
@@ -464,9 +488,13 @@ makeRecursiveBranchForGenericIndexScan(const CollectionPtr& collection,
std::move(lockAcquisitionCallback));
// Get the low key from the outer side and feed it to the inner side (ixscan).
- sbe::value::SlotVector outerSv;
+ sbe::value::SlotVector outerSv = sbe::makeSV();
if (indexIdSlot) {
- outerSv = sbe::makeSV(*indexIdSlot);
+ outerSv.push_back(*indexIdSlot);
+ }
+
+ if (indexKeyPatternSlot) {
+ outerSv.push_back(*indexKeyPatternSlot);
}
auto nlj = sbe::makeS<sbe::LoopJoinStage>(std::move(project),
@@ -481,11 +509,19 @@ makeRecursiveBranchForGenericIndexScan(const CollectionPtr& collection,
correlatedSv.push_back(*indexIdSlot);
}
+ if (indexKeyPatternSlot) {
+ correlatedSv.push_back(*indexKeyPatternSlot);
+ }
+
auto spoolValsSV = sbe::makeSV(seekKeySlot);
if (indexIdSlot) {
spoolValsSV.push_back(*indexIdSlot);
}
+ if (indexKeyPatternSlot) {
+ spoolValsSV.push_back(*indexKeyPatternSlot);
+ }
+
// Inject another nested loop join with the outer branch being a stack spool, and the inner an
// index scan nljoin which just constructed above. The stack spool is populated from the values
// generated by the index scan above, and passed through the check bounds stage, which would
@@ -519,14 +555,16 @@ makeRecursiveBranchForGenericIndexScan(const CollectionPtr& collection,
* limit 1
* coscan
* [checkBoundsSlot, savedSlots...]
- * nlj [] [seekKeySlot, indexIdSlot]
+ * nlj [] [seekKeySlot, indexIdSlot, indexKeyPatternSlot]
* left
- * sspool [seekKeySlot, indexIdSlot]
+ * sspool [seekKeySlot, indexIdSlot, indexKeyPatternSlot]
* right
* chkbounds resultSlot recordIdSlot checkBoundsSlot
- * nlj [indexIdSlot] [lowKeySlot]
+ * nlj [indexIdSlot, indexKeyPatternSlot] [lowKeySlot]
* left
- * project [indexIdSlot = <indexName>, lowKeySlot = seekKeySlot]
+ * project [indexIdSlot = <indexName>,
+ * indexKeyPatternSlot = <index key pattern>,
+ * lowKeySlot = seekKeySlot]
* limit 1
* coscan
* right
@@ -574,12 +612,12 @@ generateGenericMultiIntervalIndexScan(const CollectionPtr& collection,
sbe::value::SlotVector indexKeySlots,
boost::optional<sbe::value::SlotId> snapshotIdSlot,
boost::optional<sbe::value::SlotId> indexIdSlot,
- boost::optional<sbe::value::SlotId> keyStringSlot,
+ boost::optional<sbe::value::SlotId> indexKeySlot,
+ boost::optional<sbe::value::SlotId> indexKeyPatternSlot,
sbe::value::SlotIdGenerator* slotIdGenerator,
sbe::value::SpoolIdGenerator* spoolIdGenerator,
PlanYieldPolicy* yieldPolicy,
sbe::LockAcquisitionCallback lockAcquisitionCallback) {
-
using namespace std::literals;
auto resultSlot = slotIdGenerator->generate();
@@ -606,8 +644,12 @@ generateGenericMultiIntervalIndexScan(const CollectionPtr& collection,
projects.emplace(*indexIdSlot, makeConstant(sbe::value::TypeTags::Nothing, 0));
}
- if (keyStringSlot) {
- projects.emplace(*keyStringSlot, makeConstant(sbe::value::TypeTags::Nothing, 0));
+ if (indexKeySlot) {
+ projects.emplace(*indexKeySlot, makeConstant(sbe::value::TypeTags::Nothing, 0));
+ }
+
+ if (indexKeyPatternSlot) {
+ projects.emplace(*indexKeyPatternSlot, makeConstant(sbe::value::TypeTags::Nothing, 0));
}
return {resultSlot,
@@ -631,8 +673,12 @@ generateGenericMultiIntervalIndexScan(const CollectionPtr& collection,
unionOutputSlots.push_back(*indexIdSlot);
}
- if (keyStringSlot) {
- unionOutputSlots.push_back(*keyStringSlot);
+ if (indexKeySlot) {
+ unionOutputSlots.push_back(*indexKeySlot);
+ }
+
+ if (indexKeyPatternSlot) {
+ unionOutputSlots.push_back(*indexKeyPatternSlot);
}
// Build the anchor branch of the union.
@@ -666,14 +712,21 @@ generateGenericMultiIntervalIndexScan(const CollectionPtr& collection,
}
boost::optional<sbe::value::SlotId> savedKeyString;
- if (keyStringSlot) {
+ if (indexKeySlot) {
savedKeyString = slotIdGenerator->generate();
savedSlots.push_back(*savedKeyString);
}
+ boost::optional<sbe::value::SlotId> savedKeyPattern;
+ if (indexKeyPatternSlot) {
+ savedKeyPattern = slotIdGenerator->generate();
+ savedSlots.push_back(*savedKeyPattern);
+ }
+
auto [recursiveSlot, recursiveBranch] = makeRecursiveBranchForGenericIndexScan(
collection,
ixn->index.identifier.catalogName,
+ ixn->index.keyPattern,
{ixn->bounds, ixn->index.keyPattern, ixn->direction, version, ordering},
spoolId,
indexKeysToInclude,
@@ -681,6 +734,7 @@ generateGenericMultiIntervalIndexScan(const CollectionPtr& collection,
savedSnapshot,
savedIndexId,
savedKeyString,
+ savedKeyPattern,
slotIdGenerator,
yieldPolicy,
ixn->nodeId(),
@@ -724,6 +778,7 @@ generateGenericMultiIntervalIndexScan(const CollectionPtr& collection,
std::pair<sbe::value::SlotId, std::unique_ptr<sbe::PlanStage>> generateSingleIntervalIndexScan(
const CollectionPtr& collection,
const std::string& indexName,
+ const BSONObj& keyPattern,
bool forward,
std::unique_ptr<KeyString::Value> lowKey,
std::unique_ptr<KeyString::Value> highKey,
@@ -732,6 +787,7 @@ std::pair<sbe::value::SlotId, std::unique_ptr<sbe::PlanStage>> generateSingleInt
boost::optional<sbe::value::SlotId> snapshotIdSlot,
boost::optional<sbe::value::SlotId> indexIdSlot,
boost::optional<sbe::value::SlotId> recordSlot,
+ boost::optional<sbe::value::SlotId> indexKeyPatternSlot,
sbe::value::SlotIdGenerator* slotIdGenerator,
PlanYieldPolicy* yieldPolicy,
PlanNodeId planNodeId,
@@ -754,6 +810,13 @@ std::pair<sbe::value::SlotId, std::unique_ptr<sbe::PlanStage>> generateSingleInt
projects.emplace(*indexIdSlot, makeConstant(indexName));
}
+ if (indexKeyPatternSlot) {
+ auto [bsonObjTag, bsonObjVal] =
+ sbe::value::copyValue(sbe::value::TypeTags::bsonObject,
+ sbe::value::bitcastFrom<const char*>(keyPattern.objdata()));
+ projects.emplace(*indexKeyPatternSlot, makeConstant(bsonObjTag, bsonObjVal));
+ }
+
auto project = sbe::makeS<sbe::ProjectStage>(
sbe::makeS<sbe::LimitSkipStage>(
sbe::makeS<sbe::CoScanStage>(planNodeId), 1, boost::none, planNodeId),
@@ -782,6 +845,10 @@ std::pair<sbe::value::SlotId, std::unique_ptr<sbe::PlanStage>> generateSingleInt
outerSv.push_back(*indexIdSlot);
}
+ if (indexKeyPatternSlot) {
+ outerSv.push_back(*indexKeyPatternSlot);
+ }
+
// Finally, get the keys from the outer side and feed them to the inner side.
return {recordIdSlot,
sbe::makeS<sbe::LoopJoinStage>(std::move(project),
@@ -803,7 +870,8 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan(
PlanYieldPolicy* yieldPolicy,
sbe::RuntimeEnvironment* env,
sbe::LockAcquisitionCallback lockAcquisitionCallback,
- StringMap<const IndexAccessMethod*>* iamMap) {
+ StringMap<const IndexAccessMethod*>* iamMap,
+ bool needsCorruptionCheck) {
auto indexName = ixn->index.identifier.catalogName;
auto descriptor = collection->getIndexCatalog()->findIndexByName(opCtx, indexName);
@@ -812,6 +880,8 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan(
<< ixn->index.identifier.catalogName,
descriptor);
+ auto keyPattern = descriptor->keyPattern();
+
// Find the IndexAccessMethod which corresponds to the 'indexName'.
auto accessMethod = collection->getIndexCatalog()->getEntry(descriptor)->accessMethod();
auto intervals =
@@ -841,7 +911,7 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan(
// 'iamMap' if a parent stage needs to execute a consistency check.
boost::optional<sbe::value::SlotId> snapshotIdSlot;
boost::optional<sbe::value::SlotId> indexIdSlot;
- boost::optional<sbe::value::SlotId> keyStringSlot;
+ boost::optional<sbe::value::SlotId> indexKeySlot;
if (iamMap) {
iamMap->insert({indexName, accessMethod});
@@ -854,9 +924,18 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan(
outputs.set(PlanStageSlots::kIndexId, *indexIdSlot);
relevantSlots.push_back(*indexIdSlot);
- keyStringSlot = slotIdGenerator->generate();
- outputs.set(PlanStageSlots::kIndexKey, *keyStringSlot);
- relevantSlots.push_back(*keyStringSlot);
+ indexKeySlot = slotIdGenerator->generate();
+ outputs.set(PlanStageSlots::kIndexKey, *indexKeySlot);
+ relevantSlots.push_back(*indexKeySlot);
+ }
+
+ // Generate a slot for an index key pattern if a parent stage needs to execute a corruption
+ // check.
+ boost::optional<sbe::value::SlotId> indexKeyPatternSlot;
+ if (needsCorruptionCheck) {
+ indexKeyPatternSlot = slotIdGenerator->generate();
+ outputs.set(PlanStageSlots::kIndexKeyPattern, *indexKeyPatternSlot);
+ relevantSlots.push_back(*indexKeyPatternSlot);
}
if (intervals.size() == 1) {
@@ -866,7 +945,8 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan(
std::tie(recordIdSlot, stage) =
generateSingleIntervalIndexScan(collection,
- ixn->index.identifier.catalogName,
+ indexName,
+ keyPattern,
ixn->direction == 1,
std::move(lowKey),
std::move(highKey),
@@ -874,7 +954,8 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan(
indexKeySlots,
snapshotIdSlot,
indexIdSlot,
- keyStringSlot,
+ indexKeySlot,
+ indexKeyPatternSlot,
slotIdGenerator,
yieldPolicy,
ixn->nodeId(),
@@ -888,13 +969,15 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan(
std::tie(recordIdSlot, stage) =
generateOptimizedMultiIntervalIndexScan(collection,
indexName,
+ keyPattern,
ixn->direction == 1,
std::move(intervals),
indexKeyBitset,
indexKeySlots,
snapshotIdSlot,
indexIdSlot,
- keyStringSlot,
+ indexKeySlot,
+ indexKeyPatternSlot,
slotIdGenerator,
yieldPolicy,
ixn->nodeId(),
@@ -913,7 +996,8 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan(
indexKeySlots,
snapshotIdSlot,
indexIdSlot,
- keyStringSlot,
+ indexKeySlot,
+ indexKeyPatternSlot,
slotIdGenerator,
spoolIdGenerator,
yieldPolicy,