diff options
author | Ian Boros <ian.boros@mongodb.com> | 2022-05-26 20:45:45 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-06-07 22:42:07 +0000 |
commit | 6385b8fe69e121ab2bf50297fdeab5e4f2729d5a (patch) | |
tree | c4989057c5cb94fb87a3417253b6b68f3c33b8c6 /src/mongo/db/exec | |
parent | be3cfbd6d6c195f0179066b111a39291f0f15df7 (diff) | |
download | mongo-6385b8fe69e121ab2bf50297fdeab5e4f2729d5a.tar.gz |
SERVER-66814 Use classic MatchExpression for applying filters in SBE
Co-authored-by: Eric Cox <eric.cox@mongodb.com>
Diffstat (limited to 'src/mongo/db/exec')
-rw-r--r-- | src/mongo/db/exec/sbe/expressions/expression.cpp | 17 | ||||
-rw-r--r-- | src/mongo/db/exec/sbe/values/value.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/exec/sbe/values/value.h | 13 | ||||
-rw-r--r-- | src/mongo/db/exec/sbe/values/value_printer.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/exec/sbe/vm/vm.cpp | 44 | ||||
-rw-r--r-- | src/mongo/db/exec/sbe/vm/vm.h | 5 |
6 files changed, 88 insertions, 0 deletions
diff --git a/src/mongo/db/exec/sbe/expressions/expression.cpp b/src/mongo/db/exec/sbe/expressions/expression.cpp index 61812667316..970543b706a 100644 --- a/src/mongo/db/exec/sbe/expressions/expression.cpp +++ b/src/mongo/db/exec/sbe/expressions/expression.cpp @@ -582,6 +582,11 @@ static stdx::unordered_map<std::string, InstrFn> kInstrFunctions = { {"collMin", InstrFn{[](size_t n) { return n == 2; }, &vm::CodeFragment::appendCollMin, true}}, {"collMax", InstrFn{[](size_t n) { return n == 2; }, &vm::CodeFragment::appendCollMax, true}}, {"mod", InstrFn{[](size_t n) { return n == 2; }, &vm::CodeFragment::appendMod, false}}, + // Note that we do not provide a pointer to a function for appending the 'applyClassicMatcher' + // instruction, because it's required that the first argument to applyClassicMatcher be a + // constant MatchExpression. This constant is stored as part of the bytecode itself, to avoid + // the stack manipulation overhead. + {"applyClassicMatcher", InstrFn{[](size_t n) { return n == 2; }, nullptr, false}}, }; } // namespace @@ -689,6 +694,18 @@ vm::CodeFragment EFunction::compileDirect(CompileCtx& ctx) const { code.appendTraverseP(bodyPosition); return code; + } else if (_name == "applyClassicMatcher") { + tassert(6681400, + "First argument to applyClassicMatcher must be constant", + _nodes[0]->as<EConstant>()); + auto [matcherTag, matcherVal] = _nodes[0]->as<EConstant>()->getConstant(); + tassert(6681409, + "First argument to applyClassicMatcher must be a classic matcher", + matcherTag == value::TypeTags::classicMatchExpresion); + + code.append(_nodes[1]->compileDirect(ctx)); + code.appendApplyClassicMatcher(value::getClassicMatchExpressionView(matcherVal)); + return code; } // The order of evaluation is flipped for instruction functions. We may want to change the diff --git a/src/mongo/db/exec/sbe/values/value.cpp b/src/mongo/db/exec/sbe/values/value.cpp index cde56e31ba2..5bbdc40170e 100644 --- a/src/mongo/db/exec/sbe/values/value.cpp +++ b/src/mongo/db/exec/sbe/values/value.cpp @@ -326,6 +326,9 @@ void releaseValue(TypeTags tag, Value val) noexcept { case TypeTags::indexBounds: delete getIndexBoundsView(val); break; + case TypeTags::classicMatchExpresion: + delete getClassicMatchExpressionView(val); + break; default: break; } diff --git a/src/mongo/db/exec/sbe/values/value.h b/src/mongo/db/exec/sbe/values/value.h index 728a0c16634..d0202b0f1c0 100644 --- a/src/mongo/db/exec/sbe/values/value.h +++ b/src/mongo/db/exec/sbe/values/value.h @@ -154,6 +154,9 @@ enum class TypeTags : uint8_t { // Pointer to a IndexBounds object. indexBounds, + + // Pointer to a classic engine match expression. + classicMatchExpresion, }; inline constexpr bool isNumber(TypeTags tag) noexcept { @@ -1249,6 +1252,10 @@ inline IndexBounds* getIndexBoundsView(Value val) noexcept { return reinterpret_cast<IndexBounds*>(val); } +inline MatchExpression* getClassicMatchExpressionView(Value val) noexcept { + return reinterpret_cast<MatchExpression*>(val); +} + /** * Pattern and flags of Regex are stored in BSON as two C strings written one after another. * @@ -1450,6 +1457,12 @@ inline std::pair<TypeTags, Value> copyValue(TypeTags tag, Value val) { return makeCopyCollator(*getCollatorView(val)); case TypeTags::indexBounds: return makeCopyIndexBounds(*getIndexBoundsView(val)); + case TypeTags::classicMatchExpresion: + // Beware: "shallow cloning" a match expression does not copy the underlying BSON. The + // original BSON must remain alive for both the original MatchExpression and the clone. + return {TypeTags::classicMatchExpresion, + bitcastFrom<const MatchExpression*>( + getClassicMatchExpressionView(val)->shallowClone().release())}; default: break; } diff --git a/src/mongo/db/exec/sbe/values/value_printer.cpp b/src/mongo/db/exec/sbe/values/value_printer.cpp index 78e655114a3..90a43442329 100644 --- a/src/mongo/db/exec/sbe/values/value_printer.cpp +++ b/src/mongo/db/exec/sbe/values/value_printer.cpp @@ -156,6 +156,9 @@ void ValuePrinter<T>::writeTagToStream(TypeTags tag) { case TypeTags::indexBounds: stream << "indexBounds"; break; + case TypeTags::classicMatchExpresion: + stream << "classicMatchExpression"; + break; default: stream << "unknown tag"; break; @@ -472,6 +475,9 @@ void ValuePrinter<T>::writeValueToStream(TypeTags tag, Value val, size_t depth) getIndexBoundsView(val)->toString(true /* hasNonSimpleCollation */)); stream << ")"; break; + case TypeTags::classicMatchExpresion: + stream << "ClassicMatcher(" << getClassicMatchExpressionView(val)->toString() << ")"; + break; default: MONGO_UNREACHABLE; } diff --git a/src/mongo/db/exec/sbe/vm/vm.cpp b/src/mongo/db/exec/sbe/vm/vm.cpp index f6a6b35970e..3aae133219f 100644 --- a/src/mongo/db/exec/sbe/vm/vm.cpp +++ b/src/mongo/db/exec/sbe/vm/vm.cpp @@ -153,6 +153,8 @@ int Instruction::stackOffset[Instruction::Tags::lastInstruction] = { 0, // ret -1, // fail + + 0, // applyClassicMatcher }; namespace { @@ -281,6 +283,12 @@ std::string CodeFragment::toString() const { ss << "accessor: " << static_cast<void*>(accessor); break; } + case Instruction::applyClassicMatcher: { + const auto* matcher = readFromMemory<const MatchExpression*>(pcPointer); + pcPointer += sizeof(matcher); + ss << "matcher: " << static_cast<const void*>(matcher); + break; + } case Instruction::numConvert: { auto tag = readFromMemory<value::TypeTags>(pcPointer); pcPointer += sizeof(tag); @@ -446,6 +454,17 @@ void CodeFragment::appendNumericConvert(value::TypeTags targetTag) { offset += writeToMemory(offset, targetTag); } +void CodeFragment::appendApplyClassicMatcher(const MatchExpression* matcher) { + Instruction i; + i.tag = Instruction::applyClassicMatcher; + adjustStackSimple(i); + + auto offset = allocateSpace(sizeof(Instruction) + sizeof(matcher)); + + offset += writeToMemory(offset, i); + offset += writeToMemory(offset, matcher); +} + void CodeFragment::appendSub() { appendSimpleInstruction(Instruction::sub); } @@ -5848,6 +5867,31 @@ void ByteCode::runInternal(const CodeFragment* code, int64_t position) { break; } + case Instruction::applyClassicMatcher: { + const auto* matcher = readFromMemory<const MatchExpression*>(pcPointer); + pcPointer += sizeof(matcher); + + auto [ownedObj, tagObj, valObj] = getFromStack(0); + + BSONObj bsonObjForMatching; + if (tagObj == value::TypeTags::Object) { + BSONObjBuilder builder; + sbe::bson::convertToBsonObj(builder, sbe::value::getObjectView(valObj)); + bsonObjForMatching = builder.obj(); + } else if (tagObj == value::TypeTags::bsonObject) { + auto bson = value::getRawPointerView(valObj); + bsonObjForMatching = BSONObj(bson); + } else { + MONGO_UNREACHABLE_TASSERT(6681402); + } + + bool res = matcher->matchesBSON(bsonObjForMatching); + if (ownedObj) { + value::releaseValue(tagObj, valObj); + } + topStack(false, value::TypeTags::Boolean, value::bitcastFrom<bool>(res)); + break; + } default: MONGO_UNREACHABLE; } diff --git a/src/mongo/db/exec/sbe/vm/vm.h b/src/mongo/db/exec/sbe/vm/vm.h index 56d708fe1a1..801a139e5b8 100644 --- a/src/mongo/db/exec/sbe/vm/vm.h +++ b/src/mongo/db/exec/sbe/vm/vm.h @@ -321,6 +321,8 @@ struct Instruction { fail, + applyClassicMatcher, // Instruction which calls into the classic engine MatchExpression. + lastInstruction // this is just a marker used to calculate number of instructions }; @@ -481,6 +483,8 @@ struct Instruction { return "ret"; case fail: return "fail"; + case applyClassicMatcher: + return "applyClassicMatcher"; default: return "unrecognized"; } @@ -769,6 +773,7 @@ public: appendSimpleInstruction(Instruction::fail); } void appendNumericConvert(value::TypeTags targetTag); + void appendApplyClassicMatcher(const MatchExpression*); void fixup(int offset); |