diff options
author | Milena Ivanova <milena.ivanova@mongodb.com> | 2021-10-25 11:07:52 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-12-03 12:45:58 +0000 |
commit | 59aa9b7fd40e1a2c96c97b7dc214778e42039f27 (patch) | |
tree | 2641f4c0924e8b813ad37f04d1f90954cd217ab5 | |
parent | ae30e07629d8e9a34f4395783b0b5e96fcae9153 (diff) | |
download | mongo-59aa9b7fd40e1a2c96c97b7dc214778e42039f27.tar.gz |
SERVER-57037 Improve precision of operator counters
(cherry picked from commit a7d667da957305b1532fa07059f2bec6b2be97b4)
-rw-r--r-- | jstests/noPassthrough/operator_counters_expressions.js | 52 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_impl.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/ops/parsed_delete.cpp | 1 | ||||
-rw-r--r-- | src/mongo/db/ops/parsed_update.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/ops/parsed_update.h | 3 | ||||
-rw-r--r-- | src/mongo/db/ops/write_ops_exec.cpp | 31 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_lookup.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_context.cpp | 13 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_context.h | 23 | ||||
-rw-r--r-- | src/mongo/db/query/canonical_query.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/query/projection_ast.h | 15 | ||||
-rw-r--r-- | src/mongo/db/stats/counters.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/stats/counters.h | 25 | ||||
-rw-r--r-- | src/mongo/db/update/pipeline_executor.cpp | 2 |
15 files changed, 134 insertions, 55 deletions
diff --git a/jstests/noPassthrough/operator_counters_expressions.js b/jstests/noPassthrough/operator_counters_expressions.js index 8024c545f6b..87082bac534 100644 --- a/jstests/noPassthrough/operator_counters_expressions.js +++ b/jstests/noPassthrough/operator_counters_expressions.js @@ -67,14 +67,13 @@ function checkAggregationCounters(pipeline, expectedCounters, expectedCount) { } // Find. -checkFindCounters( - {$expr: {$eq: [{$getField: "a$b"}, "foo"]}}, {"$getField": 2, "$eq": 2, "$const": 2}, 3); +checkFindCounters({$expr: {$eq: [{$getField: "a$b"}, "foo"]}}, {"$getField": 1, "$eq": 1}, 3); // Update. checkCounters(() => assert.commandWorked(coll.update( {_id: 0, $expr: {$eq: [{$getField: {field: "a$b", input: "$$ROOT"}}, "foo"]}}, {$set: {y: 10}})), - {"$getField": 4, "$const": 6, "$eq": 4}); + {"$getField": 1, "$eq": 1}); checkCounters( () => assert.commandWorked(coll.update( @@ -96,23 +95,23 @@ checkCounters(() => assert.commandWorked(db.runCommand({ delete: coll.getName(), deletes: [{q: {"_id": {$gt: 1}, $expr: {$eq: [{$getField: "a$b"}, "foo"]}}, limit: 1}] })), - {"$getField": 4, "$eq": 4, "$const": 6}); + {"$getField": 1, "$eq": 1}); // In aggregation pipeline. let pipeline = [{$project: {_id: 1, test: {$getField: "a$b"}}}]; -checkAggregationCounters(pipeline, {"$getField": 5, "$const": 4}, 2); +checkAggregationCounters(pipeline, {"$getField": 1}, 2); pipeline = [{$match: {_id: 1, $expr: {$eq: [{$getField: "a$b"}, "foo"]}}}]; -checkAggregationCounters(pipeline, {"$getField": 5, "$eq": 5, "$const": 6}, 1); +checkAggregationCounters(pipeline, {"$getField": 1, "$eq": 1}, 1); pipeline = [{$match: {_id: 1, $expr: {$eq: [{$getField: {field: "a$b", input: {"a$b": "b"}}}, "b"]}}}]; -checkAggregationCounters(pipeline, {"$getField": 5, "$const": 9, "$eq": 5}, 1); +checkAggregationCounters(pipeline, {"$getField": 1, "$eq": 1}, 1); pipeline = [{ $project: {_id: 1, test: {$setField: {field: {$const: "a.b"}, input: "$$ROOT", value: "barrr"}}} }]; -checkAggregationCounters(pipeline, {"$setField": 5, "$const": 9}, 2); +checkAggregationCounters(pipeline, {"$setField": 1, "$const": 1}, 2); // With sub-pipeline. const testColl = db.operator_counters_expressions2; @@ -136,7 +135,7 @@ pipeline = [ } } ]; -checkAggregationCounters(pipeline, {"$getField": 10, "$const": 8}, 3); +checkAggregationCounters(pipeline, {"$getField": 1}, 3); initTestColl(5); pipeline = [ @@ -145,7 +144,7 @@ pipeline = [ pipeline: [{$project: {x: 1, _id: 0, test: {$getField: "a$b"}}}], as: "joinedField" }}]; -checkAggregationCounters(pipeline, {"$getField": 9, "$const": 6}, 2); +checkAggregationCounters(pipeline, {"$getField": 1}, 2); initTestColl(1); let mergePipeline = @@ -157,14 +156,14 @@ pipeline = [{ checkCounters(() => { coll.aggregate(pipeline).itcount(); assert.eq(2, testColl.find().itcount()); -}, {"$setField": 4, "$const": 4}); +}, {"$setField": 1}); // Expressions in view pipeline. db.view.drop(); let viewPipeline = [{$match: {$expr: {$eq: [{$getField: "a.b"}, "bar"]}}}]; assert.commandWorked( db.runCommand({create: "view", viewOn: coll.getName(), pipeline: viewPipeline})); -checkCounters(() => db.view.find().itcount(), {"$getField": 3, "$const": 2, "$eq": 3}); +checkCounters(() => db.view.find().itcount(), {"$getField": 1, "$eq": 1}); // Expressions in document validator. checkCounters(() => { @@ -190,11 +189,11 @@ checkCounters(() => { // $cond pipeline = [{$project: {item: 1, discount: {$cond: {if: {$gte: ["$x", 1]}, then: 10, else: 0}}}}]; -checkAggregationCounters(pipeline, {"$cond": 5, "$gte": 5, "$const": 12}, 2); +checkAggregationCounters(pipeline, {"$cond": 1, "$gte": 1}, 2); // $ifNull pipeline = [{$project: {description: {$ifNull: ["$description", "Unspecified"]}}}]; -checkAggregationCounters(pipeline, {"$ifNull": 5, "$const": 4}, 2); +checkAggregationCounters(pipeline, {"$ifNull": 1}, 2); // $divide, $switch let query = { @@ -210,8 +209,7 @@ let query = { ] } }; -checkFindCounters( - query, {"$const": 4, "$divide": 2, "$subtract": 2, "$eq": 2, "$gt": 2, "$switch": 2}, 1); +checkFindCounters(query, {"$divide": 1, "$subtract": 1, "$eq": 1, "$gt": 1, "$switch": 1}, 1); // $cmp, $exp, $abs, $range pipeline = [{ @@ -222,28 +220,38 @@ pipeline = [{ rangeField: {$range: [0, "$x", 25]} } }]; -checkAggregationCounters(pipeline, {"$abs": 5, "$cmp": 5, "$const": 12, "$exp": 5, "$range": 5}, 2); +checkAggregationCounters(pipeline, {"$abs": 1, "$cmp": 1, "$exp": 1, "$range": 1}, 2); // $or pipeline = [{$match: {$expr: {$or: [{$eq: ["$_id", 0]}, {$eq: ["$x", 1]}]}}}]; -checkAggregationCounters(pipeline, {"$const": 2, "$eq": 6, "$or": 3}, 2); +checkAggregationCounters(pipeline, {"$eq": 2, "$or": 1}, 2); // $dateFromParts pipeline = [{$project: {date: {$dateFromParts: {'year': 2021, 'month': 10, 'day': {$add: ['$x', 10]}}}}}]; -checkAggregationCounters(pipeline, {"$add": 5, "$const": 12, "$dateFromParts": 5}, 2); +checkAggregationCounters(pipeline, {"$add": 1, "$dateFromParts": 1}, 2); // $concat pipeline = [{$project: {mystring: {$concat: [{$getField: "a$b"}, {$getField: "a.b"}]}}}]; -checkAggregationCounters(pipeline, {"$concat": 5, "$const": 8, "$getField": 10}, 2); +checkAggregationCounters(pipeline, {"$concat": 1, "$getField": 2}, 2); // $toDouble pipeline = [{$project: {doubleval: {$toDouble: "$_id"}}}]; -checkAggregationCounters(pipeline, {"$const": 4, "$convert": 4, "$toDouble": 1}, 2); +checkAggregationCounters(pipeline, {"$toDouble": 1}, 2); // $setIntersection pipeline = [{$project: {intersection: {$setIntersection: [[1, 2, 3], [3, 2]]}}}]; -checkAggregationCounters(pipeline, {"$const": 8, "$setIntersection": 2}, 2); +checkAggregationCounters(pipeline, {"$setIntersection": 1}, 2); + +// Expressions in bulk operations. +const bulkColl = db.operator_counters_expressions3; +for (let i = 0; i < 3; i++) { + assert.commandWorked(bulkColl.insert({_id: i, x: i})); +} +const bulkOp = bulkColl.initializeUnorderedBulkOp(); +bulkOp.find({$expr: {$eq: ["$x", 2]}}).update({$set: {x: 10}}); +bulkOp.find({$expr: {$lt: ["$x", 1]}}).remove(); +checkCounters(() => assert.commandWorked(bulkOp.execute()), {"$eq": 1, "$lt": 1}); MongoRunner.stopMongod(mongod); })(); diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp index 98a2cb1591f..734e1c0577c 100644 --- a/src/mongo/db/catalog/collection_impl.cpp +++ b/src/mongo/db/catalog/collection_impl.cpp @@ -647,8 +647,10 @@ Collection::Validator CollectionImpl::parseValidator( ValidationLevelEnum::moderate) allowedFeatures &= ~MatchExpressionParser::AllowedFeatures::kEncryptKeywords; + expCtx->startExpressionCounters(); auto statusWithMatcher = MatchExpressionParser::parse(validator, expCtx, ExtensionsCallbackNoop(), allowedFeatures); + expCtx->stopExpressionCounters(); if (!statusWithMatcher.isOK()) { return { diff --git a/src/mongo/db/ops/parsed_delete.cpp b/src/mongo/db/ops/parsed_delete.cpp index 5028ccde159..6075a550e2f 100644 --- a/src/mongo/db/ops/parsed_delete.cpp +++ b/src/mongo/db/ops/parsed_delete.cpp @@ -80,6 +80,7 @@ Status ParsedDelete::parseRequest() { return Status::OK(); } + _expCtx->startExpressionCounters(); return parseQueryToCQ(); } diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp index 2d4df260b1a..ac281c89101 100644 --- a/src/mongo/db/ops/parsed_update.cpp +++ b/src/mongo/db/ops/parsed_update.cpp @@ -39,7 +39,8 @@ namespace mongo { ParsedUpdate::ParsedUpdate(OperationContext* opCtx, const UpdateRequest* request, - const ExtensionsCallback& extensionsCallback) + const ExtensionsCallback& extensionsCallback, + bool forgoOpCounterIncrements) : _opCtx(opCtx), _request(request), _expCtx(make_intrusive<ExpressionContext>( @@ -53,7 +54,11 @@ ParsedUpdate::ParsedUpdate(OperationContext* opCtx, request->explain())), _driver(_expCtx), _canonicalQuery(), - _extensionsCallback(extensionsCallback) {} + _extensionsCallback(extensionsCallback) { + if (forgoOpCounterIncrements) { + _expCtx->enabledCounters = false; + } +} Status ParsedUpdate::parseRequest() { // It is invalid to request that the UpdateStage return the prior or newly-updated version @@ -158,6 +163,7 @@ Status ParsedUpdate::parseQueryToCQ() { findCommand->setLet(*letParams); } + _expCtx->startExpressionCounters(); auto statusWithCQ = CanonicalQuery::canonicalize(_opCtx, std::move(findCommand), static_cast<bool>(_request->explain()), diff --git a/src/mongo/db/ops/parsed_update.h b/src/mongo/db/ops/parsed_update.h index 76440516ecb..40e3a279712 100644 --- a/src/mongo/db/ops/parsed_update.h +++ b/src/mongo/db/ops/parsed_update.h @@ -68,7 +68,8 @@ public: */ ParsedUpdate(OperationContext* opCtx, const UpdateRequest* request, - const ExtensionsCallback& extensionsCallback); + const ExtensionsCallback& extensionsCallback, + bool forgoOpCounterIncrements = false); /** * Parses the update request to a canonical query and an update driver. On success, the diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp index 81e7a32e264..a0f7359192e 100644 --- a/src/mongo/db/ops/write_ops_exec.cpp +++ b/src/mongo/db/ops/write_ops_exec.cpp @@ -721,7 +721,8 @@ static SingleWriteResult performSingleUpdateOp(OperationContext* opCtx, const NamespaceString& ns, UpdateRequest* updateRequest, OperationSource source, - bool* containsDotsAndDollarsField) { + bool* containsDotsAndDollarsField, + bool forgoOpCounterIncrements) { CurOpFailpointHelpers::waitWhileFailPointEnabled( &hangDuringBatchUpdate, opCtx, @@ -810,7 +811,7 @@ static SingleWriteResult performSingleUpdateOp(OperationContext* opCtx, } const ExtensionsCallbackReal extensionsCallback(opCtx, &updateRequest->getNamespaceString()); - ParsedUpdate parsedUpdate(opCtx, updateRequest, extensionsCallback); + ParsedUpdate parsedUpdate(opCtx, updateRequest, extensionsCallback, forgoOpCounterIncrements); uassertStatusOK(parsedUpdate.parseRequest()); CurOpFailpointHelpers::waitWhileFailPointEnabled( @@ -883,7 +884,8 @@ static SingleWriteResult performSingleUpdateOpWithDupKeyRetry( const write_ops::UpdateOpEntry& op, LegacyRuntimeConstants runtimeConstants, const boost::optional<BSONObj>& letParams, - OperationSource source) { + OperationSource source, + bool forgoOpCounterIncrements) { globalOpCounters.gotUpdate(); ServerWriteConcernMetrics::get(opCtx)->recordWriteConcernForUpdate(opCtx->getWriteConcern()); auto& curOp = *CurOp::get(opCtx); @@ -920,8 +922,12 @@ static SingleWriteResult performSingleUpdateOpWithDupKeyRetry( try { bool containsDotsAndDollarsField = false; - const auto ret = - performSingleUpdateOp(opCtx, ns, &request, source, &containsDotsAndDollarsField); + const auto ret = performSingleUpdateOp(opCtx, + ns, + &request, + source, + &containsDotsAndDollarsField, + forgoOpCounterIncrements); if (containsDotsAndDollarsField) { // If it's an upsert, increment 'inserts' metric, otherwise increment 'updates'. @@ -986,6 +992,9 @@ WriteResult performUpdates(OperationContext* opCtx, const auto& runtimeConstants = wholeOp.getLegacyRuntimeConstants().value_or(Variables::generateRuntimeConstants(opCtx)); + // Increment operator counters only during the fisrt single update operation in a batch of + // updates. + bool forgoOpCounterIncrements = false; for (auto&& singleOp : wholeOp.getUpdates()) { const auto stmtId = getStmtIdForWriteOp(opCtx, wholeOp, stmtIdIndex++); if (opCtx->getTxnNumber()) { @@ -1024,8 +1033,16 @@ WriteResult performUpdates(OperationContext* opCtx, ? *wholeOp.getStmtIds() : std::vector<StmtId>{stmtId}; - out.results.emplace_back(performSingleUpdateOpWithDupKeyRetry( - opCtx, ns, stmtIds, singleOp, runtimeConstants, wholeOp.getLet(), source)); + out.results.emplace_back( + performSingleUpdateOpWithDupKeyRetry(opCtx, + ns, + stmtIds, + singleOp, + runtimeConstants, + wholeOp.getLet(), + source, + forgoOpCounterIncrements)); + forgoOpCounterIncrements = true; lastOpFixer.finishedOpSuccessfully(); } catch (const DBException& ex) { out.canContinue = handleError( diff --git a/src/mongo/db/pipeline/document_source_lookup.cpp b/src/mongo/db/pipeline/document_source_lookup.cpp index 8debc4754a5..3155646b277 100644 --- a/src/mongo/db/pipeline/document_source_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_lookup.cpp @@ -977,8 +977,10 @@ void DocumentSourceLookUp::resolveLetVariables(const Document& localDoc, Variabl void DocumentSourceLookUp::initializeResolvedIntrospectionPipeline() { _variables.copyToExpCtx(_variablesParseState, _fromExpCtx.get()); + _fromExpCtx->startExpressionCounters(); _resolvedIntrospectionPipeline = Pipeline::parse(_resolvedPipeline, _fromExpCtx, lookupPipeValidator); + _fromExpCtx->stopExpressionCounters(); } void DocumentSourceLookUp::recordPlanSummaryStats(const Pipeline& pipeline) { diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp index 27319aed5cc..906515b658b 100644 --- a/src/mongo/db/pipeline/expression.cpp +++ b/src/mongo/db/pipeline/expression.cpp @@ -181,7 +181,7 @@ void Expression::registerExpression( parserMap[key] = ParserRegistration{parser, allowedWithApiStrict, allowedWithClientType, requiredMinVersion}; // Add this expression to the global map of operator counters for expressions. - operatorCountersExpressions.addExpressionCounter(key); + operatorCountersAggExpressions.addAggExpressionCounter(key); } intrusive_ptr<Expression> Expression::parseExpression(ExpressionContext* const expCtx, @@ -222,8 +222,8 @@ intrusive_ptr<Expression> Expression::parseExpression(ExpressionContext* const e expCtx->opCtx, opName, entry.allowedWithApiStrict, entry.allowedWithClientType); } - // Increment the global counter for this expression. - operatorCountersExpressions.incrementExpressionCounter(opName); + // Increment the counter for this expression in the current context. + expCtx->incrementAggExprCounter(opName); return entry.parser(expCtx, obj.firstElement(), vps); } diff --git a/src/mongo/db/pipeline/expression_context.cpp b/src/mongo/db/pipeline/expression_context.cpp index 89cc44bf094..cb92a6e9ef9 100644 --- a/src/mongo/db/pipeline/expression_context.cpp +++ b/src/mongo/db/pipeline/expression_context.cpp @@ -226,21 +226,28 @@ intrusive_ptr<ExpressionContext> ExpressionContext::copyWith( } void ExpressionContext::startExpressionCounters() { - if (!_expressionCounters) { + if (enabledCounters && !_expressionCounters) { _expressionCounters = boost::make_optional<ExpressionCounters>({}); } } void ExpressionContext::incrementMatchExprCounter(StringData name) { - if (_expressionCounters) { + if (enabledCounters && _expressionCounters) { ++_expressionCounters.get().matchExprCountersMap[name]; } } +void ExpressionContext::incrementAggExprCounter(StringData name) { + if (enabledCounters && _expressionCounters) { + ++_expressionCounters.get().aggExprCountersMap[name]; + } +} + void ExpressionContext::stopExpressionCounters() { - if (_expressionCounters) { + if (enabledCounters && _expressionCounters) { operatorCountersMatchExpressions.mergeCounters( _expressionCounters.get().matchExprCountersMap); + operatorCountersAggExpressions.mergeCounters(_expressionCounters.get().aggExprCountersMap); } _expressionCounters = boost::none; } diff --git a/src/mongo/db/pipeline/expression_context.h b/src/mongo/db/pipeline/expression_context.h index 88340b8b846..be915aa98f1 100644 --- a/src/mongo/db/pipeline/expression_context.h +++ b/src/mongo/db/pipeline/expression_context.h @@ -108,6 +108,15 @@ public: }; /** + * The structure ExpressionCounters encapsulates counters for match, aggregate, and other + * expression types as seen in end-user queries. + */ + struct ExpressionCounters { + StringMap<uint64_t> aggExprCountersMap; + StringMap<uint64_t> matchExprCountersMap; + }; + + /** * Constructs an ExpressionContext to be used for Pipeline parsing and evaluation. * 'resolvedNamespaces' maps collection names (not full namespaces) to ResolvedNamespaces. */ @@ -344,11 +353,20 @@ public: void incrementMatchExprCounter(StringData name); /** + * Increment the counter for the aggregate expression with a given name. + */ + void incrementAggExprCounter(StringData name); + + /** * Merge expression counters from the current expression context into the global maps * and stop counting. */ void stopExpressionCounters(); + bool expressionCountersAreActive() { + return _expressionCounters.is_initialized(); + } + // The explain verbosity requested by the user, or boost::none if no explain was requested. boost::optional<ExplainOptions::Verbosity> explain; @@ -429,6 +447,11 @@ public: // When non-empty, contains the unmodified user provided aggregation command. BSONObj originalAggregateCommand; + // True if the expression context is the original one for a given pipeline. + // False if another context is created for the same pipeline. Used to disable duplicate + // expression counting. + bool enabledCounters = true; + protected: static const int kInterruptCheckPeriod = 128; diff --git a/src/mongo/db/query/canonical_query.cpp b/src/mongo/db/query/canonical_query.cpp index e883263681b..2638830ded2 100644 --- a/src/mongo/db/query/canonical_query.cpp +++ b/src/mongo/db/query/canonical_query.cpp @@ -127,7 +127,7 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( return statusWithMatcher.getStatus(); } - // Stop counting match expressions after they have been parsed to exclude expressions created + // Stop counting expressions after they have been parsed to exclude expressions created // during optimization and other processing steps. newExpCtx->stopExpressionCounters(); diff --git a/src/mongo/db/query/projection_ast.h b/src/mongo/db/query/projection_ast.h index ca5d3145da9..247a91537f3 100644 --- a/src/mongo/db/query/projection_ast.h +++ b/src/mongo/db/query/projection_ast.h @@ -278,10 +278,17 @@ public: bob << "" << other._expr->serialize(false); // TODO SERVER-31003: add a clone() method to Expression. - boost::intrusive_ptr<Expression> clonedExpr = - Expression::parseOperand(other._expr->getExpressionContext(), - bob.obj().firstElement(), - other._expr->getExpressionContext()->variablesParseState); + // Temporary stop expression counters while processing the cloned expression. + auto otherCtx = other._expr->getExpressionContext(); + auto activeCounting = otherCtx->expressionCountersAreActive(); + if (activeCounting) { + otherCtx->enabledCounters = false; + } + boost::intrusive_ptr<Expression> clonedExpr = Expression::parseOperand( + otherCtx, bob.obj().firstElement(), otherCtx->variablesParseState); + if (activeCounting) { + otherCtx->enabledCounters = true; + } _expr = clonedExpr; } diff --git a/src/mongo/db/stats/counters.cpp b/src/mongo/db/stats/counters.cpp index e64b3f8bfac..b975ecc548c 100644 --- a/src/mongo/db/stats/counters.cpp +++ b/src/mongo/db/stats/counters.cpp @@ -337,6 +337,6 @@ NetworkCounter networkCounter; AuthCounter authCounter; AggStageCounters aggStageCounters; DotsAndDollarsFieldsCounters dotsAndDollarsFieldsCounters; -OperatorCountersExpressions operatorCountersExpressions; +OperatorCountersAggExpressions operatorCountersAggExpressions; OperatorCountersMatchExpressions operatorCountersMatchExpressions; } // namespace mongo diff --git a/src/mongo/db/stats/counters.h b/src/mongo/db/stats/counters.h index 18e39b1366a..732622f4ffe 100644 --- a/src/mongo/db/stats/counters.h +++ b/src/mongo/db/stats/counters.h @@ -336,33 +336,36 @@ public: extern DotsAndDollarsFieldsCounters dotsAndDollarsFieldsCounters; -class OperatorCountersExpressions { +class OperatorCountersAggExpressions { private: - struct ExprCounter { - ExprCounter(StringData name) : metric("operatorCounters.expressions." + name, &counter) {} + struct AggExprCounter { + AggExprCounter(StringData name) + : metric("operatorCounters.expressions." + name, &counter) {} Counter64 counter; ServerStatusMetricField<Counter64> metric; }; public: - void addExpressionCounter(StringData name) { - operatorCountersExpressionMap[name] = std::make_unique<ExprCounter>(name); + void addAggExpressionCounter(StringData name) { + operatorCountersAggExpressionMap[name] = std::make_unique<AggExprCounter>(name); } - void incrementExpressionCounter(StringData name) { - if (auto it = operatorCountersExpressionMap.find(name); - it != operatorCountersExpressionMap.end()) { - it->second->counter.increment(1); + void mergeCounters(StringMap<uint64_t>& toMerge) { + for (auto&& [name, cnt] : toMerge) { + if (auto it = operatorCountersAggExpressionMap.find(name); + it != operatorCountersAggExpressionMap.end()) { + it->second->counter.increment(cnt); + } } } private: // Map of aggregation expressions to the number of occurrences in aggregation pipelines. - StringMap<std::unique_ptr<ExprCounter>> operatorCountersExpressionMap = {}; + StringMap<std::unique_ptr<AggExprCounter>> operatorCountersAggExpressionMap = {}; }; -extern OperatorCountersExpressions operatorCountersExpressions; +extern OperatorCountersAggExpressions operatorCountersAggExpressions; /** * Global counters for match expressions. diff --git a/src/mongo/db/update/pipeline_executor.cpp b/src/mongo/db/update/pipeline_executor.cpp index ac6df9ca086..710803d6b04 100644 --- a/src/mongo/db/update/pipeline_executor.cpp +++ b/src/mongo/db/update/pipeline_executor.cpp @@ -72,7 +72,9 @@ PipelineExecutor::PipelineExecutor(const boost::intrusive_ptr<ExpressionContext> } _expCtx->setResolvedNamespaces(resolvedNamespaces); + _expCtx->startExpressionCounters(); _pipeline = Pipeline::parse(pipeline, _expCtx); + _expCtx->stopExpressionCounters(); // Validate the update pipeline. for (auto&& stage : _pipeline->getSources()) { |