summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilena Ivanova <milena.ivanova@mongodb.com>2021-10-25 11:07:52 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-12-03 12:45:58 +0000
commit59aa9b7fd40e1a2c96c97b7dc214778e42039f27 (patch)
tree2641f4c0924e8b813ad37f04d1f90954cd217ab5
parentae30e07629d8e9a34f4395783b0b5e96fcae9153 (diff)
downloadmongo-59aa9b7fd40e1a2c96c97b7dc214778e42039f27.tar.gz
SERVER-57037 Improve precision of operator counters
(cherry picked from commit a7d667da957305b1532fa07059f2bec6b2be97b4)
-rw-r--r--jstests/noPassthrough/operator_counters_expressions.js52
-rw-r--r--src/mongo/db/catalog/collection_impl.cpp2
-rw-r--r--src/mongo/db/ops/parsed_delete.cpp1
-rw-r--r--src/mongo/db/ops/parsed_update.cpp10
-rw-r--r--src/mongo/db/ops/parsed_update.h3
-rw-r--r--src/mongo/db/ops/write_ops_exec.cpp31
-rw-r--r--src/mongo/db/pipeline/document_source_lookup.cpp2
-rw-r--r--src/mongo/db/pipeline/expression.cpp6
-rw-r--r--src/mongo/db/pipeline/expression_context.cpp13
-rw-r--r--src/mongo/db/pipeline/expression_context.h23
-rw-r--r--src/mongo/db/query/canonical_query.cpp2
-rw-r--r--src/mongo/db/query/projection_ast.h15
-rw-r--r--src/mongo/db/stats/counters.cpp2
-rw-r--r--src/mongo/db/stats/counters.h25
-rw-r--r--src/mongo/db/update/pipeline_executor.cpp2
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()) {