diff options
author | Milena Ivanova <milena.ivanova@mongodb.com> | 2021-05-28 09:24:11 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-08-05 08:24:59 +0000 |
commit | 98b4a0a2b2c4a230efe1c2ddc3da487a575d670d (patch) | |
tree | 7269ee48a69bfaea61b77a8d3f78bc072735b3b0 /src/mongo | |
parent | 85976973ce08a8d7dedbcc108d4ace00c25c9b04 (diff) | |
download | mongo-98b4a0a2b2c4a230efe1c2ddc3da487a575d670d.tar.gz |
SERVER-56602 Track usage of match expressions in serverStatus
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/commands/find_cmd.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/commands/run_aggregate.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/curop.h | 11 | ||||
-rw-r--r-- | src/mongo/db/matcher/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf.cpp | 28 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf.h | 2 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser.cpp | 39 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_context.cpp | 21 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_context.h | 28 | ||||
-rw-r--r-- | src/mongo/db/query/canonical_query.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/stats/counters.cpp | 1 | ||||
-rw-r--r-- | src/mongo/db/stats/counters.h | 33 |
12 files changed, 156 insertions, 17 deletions
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index 9dd3393360e..31faa7c7bb3 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -158,6 +158,8 @@ boost::intrusive_ptr<ExpressionContext> makeExpressionContext( CurOp::get(opCtx)->dbProfileLevel() > 0 // mayDbProfile ); expCtx->tempDir = storageGlobalParams.dbpath + "/_tmp"; + expCtx->startExpressionCounters(); + return expCtx; } diff --git a/src/mongo/db/commands/run_aggregate.cpp b/src/mongo/db/commands/run_aggregate.cpp index 789581c7337..a25075c2839 100644 --- a/src/mongo/db/commands/run_aggregate.cpp +++ b/src/mongo/db/commands/run_aggregate.cpp @@ -764,7 +764,9 @@ Status runAggregate(OperationContext* opCtx, expCtx = makeExpressionContext( opCtx, request, std::move(*collatorToUse), uuid, collatorToUseMatchesDefault); + expCtx->startExpressionCounters(); auto pipeline = Pipeline::parse(request.getPipeline(), expCtx); + expCtx->stopExpressionCounters(); // Check that the view's collation matches the collation of any views involved in the // pipeline. diff --git a/src/mongo/db/curop.h b/src/mongo/db/curop.h index 8c3adec3a91..afb48de2440 100644 --- a/src/mongo/db/curop.h +++ b/src/mongo/db/curop.h @@ -775,6 +775,16 @@ public: _tickSource = tickSource; } + /** + * Merge match counters from the current operation into the global map and stop counting. + */ + void stopMatchExprCounter(); + + /** + * Increment the counter for the match expression with given name in the current operation. + */ + void incrementMatchExprCounter(StringData name); + private: class CurOpStack; @@ -846,4 +856,5 @@ private: TickSource* _tickSource = nullptr; }; + } // namespace mongo diff --git a/src/mongo/db/matcher/SConscript b/src/mongo/db/matcher/SConscript index aa1badd3cb7..f7b42816cb8 100644 --- a/src/mongo/db/matcher/SConscript +++ b/src/mongo/db/matcher/SConscript @@ -70,6 +70,7 @@ env.Library( '$BUILD_DIR/mongo/db/pipeline/expression_context', '$BUILD_DIR/mongo/db/query/collation/collator_interface', '$BUILD_DIR/mongo/db/query/query_knobs', + '$BUILD_DIR/mongo/db/stats/counters', '$BUILD_DIR/mongo/idl/idl_parser', '$BUILD_DIR/mongo/util/regex_util', '$BUILD_DIR/third_party/shim_pcrecpp', diff --git a/src/mongo/db/matcher/expression_leaf.cpp b/src/mongo/db/matcher/expression_leaf.cpp index c1f9a9ebb44..8f000b52728 100644 --- a/src/mongo/db/matcher/expression_leaf.cpp +++ b/src/mongo/db/matcher/expression_leaf.cpp @@ -778,29 +778,29 @@ bool BitTestMatchExpression::matchesSingleElement(const BSONElement& e, return performBitTest(eValue); } -void BitTestMatchExpression::debugString(StringBuilder& debug, int indentationLevel) const { - _debugAddSpace(debug, indentationLevel); - - debug << path() << " "; - +std::string BitTestMatchExpression::name() const { switch (matchType()) { case BITS_ALL_SET: - debug << "$bitsAllSet:"; - break; + return "$bitsAllSet"; + case BITS_ALL_CLEAR: - debug << "$bitsAllClear:"; - break; + return "$bitsAllClear"; + case BITS_ANY_SET: - debug << "$bitsAnySet:"; - break; + return "$bitsAnySet"; + case BITS_ANY_CLEAR: - debug << "$bitsAnyClear:"; - break; + return "$bitsAnyClear"; + default: MONGO_UNREACHABLE; } +} + +void BitTestMatchExpression::debugString(StringBuilder& debug, int indentationLevel) const { + _debugAddSpace(debug, indentationLevel); - debug << " ["; + debug << path() << " " << name() << ": ["; for (size_t i = 0; i < _bitPositions.size(); i++) { debug << _bitPositions[i]; if (i != _bitPositions.size() - 1) { diff --git a/src/mongo/db/matcher/expression_leaf.h b/src/mongo/db/matcher/expression_leaf.h index 248e68f1f44..f2c3a5f13a3 100644 --- a/src/mongo/db/matcher/expression_leaf.h +++ b/src/mongo/db/matcher/expression_leaf.h @@ -693,6 +693,8 @@ public: return _bitMask; } + std::string name() const; + private: ExpressionOptimizerFunc getOptimizer() const final { return [](std::unique_ptr<MatchExpression> expression) { return expression; }; diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index 8839b537f4c..06016d8c3a4 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -69,6 +69,7 @@ #include "mongo/db/namespace_string.h" #include "mongo/db/query/dbref.h" #include "mongo/db/query/query_knobs_gen.h" +#include "mongo/db/stats/counters.h" #include "mongo/util/str.h" #include "mongo/util/string_map.h" @@ -173,6 +174,7 @@ StatusWithMatchExpression parseRegexElement(StringData name, if (e.type() != BSONType::RegEx) return {Status(ErrorCodes::BadValue, "not a regex")}; + expCtx->incrementMatchExprCounter("$regex"); return {std::make_unique<RegexMatchExpression>( name, e.regex(), @@ -319,6 +321,7 @@ StatusWithMatchExpression parse(const BSONObj& obj, if (auto&& expr = parsedExpression.getValue()) root->add(std::move(expr)); + expCtx->incrementMatchExprCounter(e.fieldNameStringData()); continue; } @@ -345,7 +348,6 @@ StatusWithMatchExpression parse(const BSONObj& obj, auto result = parseRegexElement(e.fieldNameStringData(), e, expCtx); if (!result.isOK()) return result; - addExpressionToRoot(expCtx, root.get(), std::move(result.getValue())); continue; } @@ -361,7 +363,7 @@ StatusWithMatchExpression parse(const BSONObj& obj, allowedFeatures); if (!eq.isOK()) return eq; - + expCtx->incrementMatchExprCounter("$eq"); addExpressionToRoot(expCtx, root.get(), std::move(eq.getValue())); } @@ -423,7 +425,9 @@ StatusWithMatchExpression parseSampleRate(StringData name, // DeMorgan's law here you will be suprised that $sampleRate will accept NaN as a valid // argument. return {Status(ErrorCodes::BadValue, "numeric argument to $sampleRate must be in [0, 1]")}; - } else if (x == kRandomMinValue) { + } + + if (x == kRandomMinValue) { return std::make_unique<ExprMatchExpression>( ExpressionConstant::create(expCtx.get(), Value(false)), expCtx, @@ -1202,6 +1206,7 @@ StatusWithMatchExpression parseGeo(StringData name, return status; } expCtx->sbeCompatible = false; + expCtx->incrementMatchExprCounter(section.firstElementFieldName()); return {std::make_unique<GeoNearMatchExpression>(name, nq.release(), section)}; } } @@ -2017,6 +2022,7 @@ Status parseSub(StringData name, if (!s.isOK()) return s.getStatus(); + expCtx->incrementMatchExprCounter(deep.fieldNameStringData()); if (s.getValue()) { addExpressionToRoot(expCtx, root, std::move(s.getValue())); } @@ -2179,6 +2185,33 @@ retrievePathlessParser(StringData name) { } return func->second; } + +MONGO_INITIALIZER_WITH_PREREQUISITES(MatchExpressionCounters, + ("PathlessOperatorMap", "MatchExpressionParser")) +(InitializerContext* context) { + static const std::set<std::string> exceptionsSet{"within", // deprecated + "geoNear", // aggregation stage + "db", // $-prefixed field names + "id", + "ref", + "options"}; + + for (auto&& [name, keyword] : *queryOperatorMap) { + if (name[0] == '_' || exceptionsSet.count(name) > 0) { + continue; + } + operatorCountersMatchExpressions.addMatchExprCounter("$" + name); + } + for (auto&& [name, fn] : *pathlessOperatorMap) { + if (name[0] == '_' || exceptionsSet.count(name) > 0) { + continue; + } + operatorCountersMatchExpressions.addMatchExprCounter("$" + name); + } + operatorCountersMatchExpressions.addMatchExprCounter("$not"); +} + + } // namespace boost::optional<PathAcceptingKeyword> MatchExpressionParser::parsePathAcceptingKeyword( diff --git a/src/mongo/db/pipeline/expression_context.cpp b/src/mongo/db/pipeline/expression_context.cpp index c4cb0f6e411..69698ab0289 100644 --- a/src/mongo/db/pipeline/expression_context.cpp +++ b/src/mongo/db/pipeline/expression_context.cpp @@ -36,6 +36,7 @@ #include "mongo/db/pipeline/process_interface/stub_mongo_process_interface.h" #include "mongo/db/query/collation/collation_spec.h" #include "mongo/db/query/collation/collator_factory_interface.h" +#include "mongo/db/stats/counters.h" #include "mongo/util/intrusive_counter.h" namespace mongo { @@ -223,4 +224,24 @@ intrusive_ptr<ExpressionContext> ExpressionContext::copyWith( return expCtx; } +void ExpressionContext::startExpressionCounters() { + if (!_expressionCounters) { + _expressionCounters = boost::make_optional<ExpressionCounters>({}); + } +} + +void ExpressionContext::incrementMatchExprCounter(StringData name) { + if (_expressionCounters) { + ++_expressionCounters.get().matchExprCountersMap[name]; + } +} + +void ExpressionContext::stopExpressionCounters() { + if (_expressionCounters) { + operatorCountersMatchExpressions.mergeCounters( + _expressionCounters.get().matchExprCountersMap); + } + _expressionCounters = boost::none; +} + } // namespace mongo diff --git a/src/mongo/db/pipeline/expression_context.h b/src/mongo/db/pipeline/expression_context.h index b40028dc30a..398a162b283 100644 --- a/src/mongo/db/pipeline/expression_context.h +++ b/src/mongo/db/pipeline/expression_context.h @@ -58,6 +58,15 @@ namespace mongo { class AggregateCommandRequest; +/** + * The structure ExpressionCounters encapsulates counters for match, aggregate, and other + * expression types as seen in the end-user queries. + */ +struct ExpressionCounters { + StringMap<uint64_t> aggExprCountersMap; + StringMap<uint64_t> matchExprCountersMap; +}; + class ExpressionContext : public RefCountable { public: static constexpr size_t kMaxSubPipelineViewDepth = 20; @@ -316,6 +325,22 @@ public: return JsExecution::get(opCtx, scopeObj, ns.db(), loadStoredProcedures, jsHeapLimitMB); } + /** + * Create optional internal expression counters and start counting. + */ + void startExpressionCounters(); + + /** + * Increment the counter for the match expression with a given name. + */ + void incrementMatchExprCounter(StringData name); + + /** + * Merge expression counters from the current expression context into the global maps + * and stop counting. + */ + void stopExpressionCounters(); + // The explain verbosity requested by the user, or boost::none if no explain was requested. boost::optional<ExplainOptions::Verbosity> explain; @@ -413,6 +438,9 @@ protected: StringMap<ResolvedNamespace> _resolvedNamespaces; int _interruptCounter = kInterruptCheckPeriod; + +private: + boost::optional<ExpressionCounters> _expressionCounters = boost::none; }; } // namespace mongo diff --git a/src/mongo/db/query/canonical_query.cpp b/src/mongo/db/query/canonical_query.cpp index de2e39895ff..87efc4cc259 100644 --- a/src/mongo/db/query/canonical_query.cpp +++ b/src/mongo/db/query/canonical_query.cpp @@ -126,6 +126,11 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( if (!statusWithMatcher.isOK()) { return statusWithMatcher.getStatus(); } + + // Stop counting match expressions after they have been parsed to exclude expressions created + // during optimization and other processing steps. + newExpCtx->stopExpressionCounters(); + std::unique_ptr<MatchExpression> me = std::move(statusWithMatcher.getValue()); Status initStatus = diff --git a/src/mongo/db/stats/counters.cpp b/src/mongo/db/stats/counters.cpp index 1cf3e4f4f72..2f9b070b888 100644 --- a/src/mongo/db/stats/counters.cpp +++ b/src/mongo/db/stats/counters.cpp @@ -314,4 +314,5 @@ AuthCounter authCounter; AggStageCounters aggStageCounters; DotsAndDollarsFieldsCounters dotsAndDollarsFieldsCounters; OperatorCountersExpressions operatorCountersExpressions; +OperatorCountersMatchExpressions operatorCountersMatchExpressions; } // namespace mongo diff --git a/src/mongo/db/stats/counters.h b/src/mongo/db/stats/counters.h index 397951bdd7b..18e39b1366a 100644 --- a/src/mongo/db/stats/counters.h +++ b/src/mongo/db/stats/counters.h @@ -363,4 +363,37 @@ private: }; extern OperatorCountersExpressions operatorCountersExpressions; + +/** + * Global counters for match expressions. + */ +class OperatorCountersMatchExpressions { +private: + struct MatchExprCounter { + MatchExprCounter(StringData name) : metric("operatorCounters.match." + name, &counter) {} + + Counter64 counter; + ServerStatusMetricField<Counter64> metric; + }; + +public: + void addMatchExprCounter(StringData name) { + operatorCountersMatchExprMap[name] = std::make_unique<MatchExprCounter>(name); + } + + void mergeCounters(StringMap<uint64_t>& toMerge) { + for (auto&& [name, cnt] : toMerge) { + if (auto it = operatorCountersMatchExprMap.find(name); + it != operatorCountersMatchExprMap.end()) { + it->second->counter.increment(cnt); + } + } + } + +private: + // Map of match expressions to the number of occurrences in queries. + StringMap<std::unique_ptr<MatchExprCounter>> operatorCountersMatchExprMap = {}; +}; + +extern OperatorCountersMatchExpressions operatorCountersMatchExpressions; } // namespace mongo |