summaryrefslogtreecommitdiff
path: root/src/mongo/db/curop.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/curop.h')
-rw-r--r--src/mongo/db/curop.h212
1 files changed, 26 insertions, 186 deletions
diff --git a/src/mongo/db/curop.h b/src/mongo/db/curop.h
index ba1545130ff..cdc5e4f20d7 100644
--- a/src/mongo/db/curop.h
+++ b/src/mongo/db/curop.h
@@ -30,18 +30,18 @@
#pragma once
-#include "mongo/util/duration.h"
#include <memory>
#include "mongo/config.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/auth/user_acquisition_stats.h"
#include "mongo/db/catalog/collection_catalog.h"
+#include "mongo/db/clientcursor.h"
#include "mongo/db/commands.h"
#include "mongo/db/cursor_id.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/profile_filter.h"
-#include "mongo/db/query/query_stats/key.h"
+#include "mongo/db/server_options.h"
#include "mongo/db/stats/resource_consumption_metrics.h"
#include "mongo/db/write_concern_options.h"
#include "mongo/logv2/attribute_storage.h"
@@ -66,10 +66,8 @@ struct PlanSummaryStats;
class OpDebug {
public:
/**
- * Holds counters for execution statistics that can be accumulated by one or more operations.
- * They're accumulated as we go for a single operation, but are also extracted and stored
- * externally if they need to be accumulated across multiple operations (which have multiple
- * CurOps), including for cursors and multi-statement transactions.
+ * Holds counters for execution statistics that are meaningful both for multi-statement
+ * transactions and for individual operations outside of a transaction.
*/
class AdditiveMetrics {
public:
@@ -122,16 +120,6 @@ public:
void incrementKeysDeleted(long long n);
/**
- * Increments nreturned by n.
- */
- void incrementNreturned(long long n);
-
- /**
- * Increments nBatches by 1.
- */
- void incrementNBatches();
-
- /**
* Increments ninserted by n.
*/
void incrementNinserted(long long n);
@@ -147,11 +135,6 @@ public:
void incrementPrepareReadConflicts(long long n);
/**
- * Increments executionTime by n.
- */
- void incrementExecutionTime(Microseconds n);
-
- /**
* Generates a string showing all non-empty fields. For every non-empty field field1,
* field2, ..., with corresponding values value1, value2, ..., we will output a string in
* the format: "<field1>:<value1> <field2>:<value2> ...".
@@ -166,10 +149,6 @@ public:
// Number of records that match the query.
boost::optional<long long> nMatched;
- // Number of records returned so far.
- boost::optional<long long> nreturned;
- // Number of batches returned so far.
- boost::optional<long long> nBatches;
// Number of records written (no no-ops).
boost::optional<long long> nModified;
boost::optional<long long> ninserted;
@@ -190,9 +169,6 @@ public:
AtomicWord<long long> prepareReadConflicts{0};
AtomicWord<long long> writeConflicts{0};
AtomicWord<long long> temporarilyUnavailableErrors{0};
-
- // Amount of time spent executing a query.
- boost::optional<Microseconds> executionTime;
};
OpDebug() = default;
@@ -202,8 +178,6 @@ public:
const ResourceConsumption::OperationMetrics* operationMetrics,
logv2::DynamicAttributes* pAttrs) const;
- void reportStorageStats(logv2::DynamicAttributes* pAttrs) const;
-
/**
* Appends information about the current operation to "builder"
*
@@ -265,7 +239,6 @@ public:
boost::optional<long long> mongotCursorId{boost::none};
boost::optional<long long> msWaitingForMongot{boost::none};
long long mongotBatchNum = 0;
- BSONObj mongotCountVal = BSONObj();
bool hasSortStage{false}; // true if the query plan involves an in-memory sort
@@ -289,70 +262,20 @@ public:
// The hash of the query's "stable" key. This represents the query's shape.
boost::optional<uint32_t> queryHash;
- /* The QueryStatsInfo struct was created to bundle all the queryStats related fields of CurOp &
- * OpDebug together (SERVER-83280).
- *
- * ClusterClientCursorImpl and ClientCursor also contain _queryStatsKey and _queryStatsKeyHash
- * members but NOT a wasRateLimited member. Variable names & accesses would be more consistent
- * across the code if ClusterClientCursorImpl and ClientCursor each also had a QueryStatsInfo
- * struct, but we considered and rejected two different potential implementations of this:
- * - Option 1:
- * Declare a QueryStatsInfo struct in each .h file. Every struct would have key and keyHash
- * fields, and a wasRateLimited field would be added only to CurOp. But, it seemed confusing
- * to have slightly different structs with the same name declared three different times.
- * - Option 2:
- * Create a query_stats_info.h that declares QueryStatsInfo--identical to the version defined
- * in this file. CurOp/OpDebug, ClientCursor, and ClusterClientCursorImpl would then all
- * have their own QueryStatsInfo instances, potentially as a unique_ptr or boost::optional. A
- * benefit to this would be the ability to to just move the entire QueryStatsInfo struct from
- * Op to the Cursor, instead of copying it over field by field (the current method). But:
- * - The current code moves ownership of the key, but copies the keyHash. So, for workflows
- * that require multiple cursors, like sharding, one cursor would own the key, but all
- * cursors would have copies of the keyHash. The problem with trying to move around the
- * struct in its entirety is that access to the *entire* struct would be lost on the
- * move, meaning there's no way to retain the keyHash (that doesn't largely nullify the
- * benefits of having the struct).
- * - It seemed odd to have ClientCursor and ClusterClientCursorImpl using the struct but
- * never needing the wasRateLimited field.
- */
-
- // Note that the only case when the three fields of the below struct are null, none, and false
- // is if the query stats feature flag is turned off.
- struct QueryStatsInfo {
- // Uniquely identifies one query stats entry.
- // nullptr if `wasRateLimited` is true.
- std::unique_ptr<query_stats::Key> key;
- // A cached value of `absl::HashOf(key)`.
- // Always populated if `key` is non-null. boost::none if `wasRateLimited` is true.
- boost::optional<std::size_t> keyHash;
- // True if the request was rate limited and stats should not be collected.
- bool wasRateLimited = false;
- // True if the request was a change stream request.
- // TODO SERVER-89058 will make it true for all tailable cursors.
- bool willNeverExhaust = false;
- };
-
- QueryStatsInfo queryStatsInfo;
-
// Has a value if this operation is a query. True if the execution tree for the find part of the
- // query was built exclusively using the classic query engine, false if any part was built using
- // SBE.
+ // query was built using the classic query engine, false if it was built in SBE.
boost::optional<bool> classicEngineUsed;
// Has a value if this operation is an aggregation query. True if `DocumentSources` were
// involved in the execution tree for this query, false if they were not.
boost::optional<bool> documentSourceUsed;
- // Indicates whether this operation used the common query framework (CQF).
- bool cqfUsed{false};
-
// Details of any error (whether from an exception or a command returning failure).
Status errInfo = Status::OK();
- // Amount of time spent planning the query. Begins after parsing and ends
- // after optimizations.
- Microseconds planningTime{0};
-
+ // response info
+ Microseconds executionTime{0};
+ long long nreturned{-1};
int responseLength{-1};
// Shard targeting info.
@@ -361,15 +284,6 @@ public:
// Stores the duration of time spent blocked on prepare conflicts.
Milliseconds prepareConflictDurationMillis{0};
- // Stores the total time an operation spends with an uncommitted oplog slot held open. Indicator
- // that an operation is holding back replication by causing oplog holes to remain open for
- // unusual amounts of time.
- Microseconds totalOplogSlotDurationMicros{0};
-
- // Stores the duration of time spent waiting for the specified user write concern to
- // be fulfilled.
- Milliseconds waitForWriteConcernDurationMillis{0};
-
// Stores the amount of the data processed by the throttle cursors in MB/sec.
boost::optional<float> dataThroughputLastSecond;
boost::optional<float> dataThroughputAverage;
@@ -377,13 +291,11 @@ public:
// Used to track the amount of time spent waiting for a response from remote operations.
boost::optional<Microseconds> remoteOpWaitTime;
- // Stores the current operation's count of these metrics. If they are needed to be accumulated
- // elsewhere, they should be extracted by another aggregator (like the ClientCursor) to ensure
- // these only ever reflect just this CurOp's consumption.
+ // Stores additive metrics.
AdditiveMetrics additiveMetrics;
// Stores storage statistics.
- std::unique_ptr<StorageStats> storageStats;
+ std::shared_ptr<StorageStats> storageStats;
bool waitingForFlowControl{false};
@@ -469,13 +381,6 @@ public:
NetworkOp op);
/**
- * Sets metrics collected at the end of an operation onto curOp's OpDebug instance. Note that
- * this is used in tandem with OpDebug::setPlanSummaryMetrics so should not repeat any metrics
- * collected there.
- */
- void setEndOfOpMetrics(long long nreturned);
-
- /**
* Marks the operation end time, records the length of the client response if a valid response
* exists, and then - subject to the current values of slowMs and sampleRate - logs this CurOp
* to file under the given LogComponent. Returns 'true' if, in addition to being logged, this
@@ -675,12 +580,12 @@ public:
* This method is separate from startRemoteOpWait because operation types that do record
* remoteOpWait, such as a getMore of a sharded aggregation, should always include the
* remoteOpWait field even if its value is zero. An operation should call
- * ensureRecordRemoteOpWait() to declare that it wants to report remoteOpWait, and call
+ * enableRecordRemoteOpWait() to declare that it wants to report remoteOpWait, and call
* startRemoteOpWaitTimer()/stopRemoteOpWaitTimer() to measure the time.
*
* This timer uses the same clock source as elapsedTimeTotal().
*/
- void ensureRecordRemoteOpWait() {
+ void enableRecordRemoteOpWait() {
if (!_debug.remoteOpWaitTime) {
_debug.remoteOpWaitTime.emplace(0);
}
@@ -689,15 +594,10 @@ public:
/**
* Starts the remoteOpWait timer.
*
- * Does nothing if ensureRecordRemoteOpWait() was not called or the current operation was not
- * marked as started.
+ * Does nothing if enableRecordRemoteOpWait() was not called.
*/
void startRemoteOpWaitTimer() {
- // There are some commands that send remote operations but do not mark the current operation
- // as started. We do not record remote op wait time for those commands.
- if (!isStarted()) {
- return;
- }
+ invariant(isStarted());
invariant(!isDone());
invariant(!isPaused());
invariant(!_remoteOpStartTime);
@@ -709,15 +609,10 @@ public:
/**
* Stops the remoteOpWait timer.
*
- * Does nothing if ensureRecordRemoteOpWait() was not called or the current operation was not
- * marked as started.
+ * Does nothing if enableRecordRemoteOpWait() was not called.
*/
void stopRemoteOpWaitTimer() {
- // There are some commands that send remote operations but do not mark the current operation
- // as started. We do not record remote op wait time for those commands.
- if (!isStarted()) {
- return;
- }
+ invariant(isStarted());
invariant(!isDone());
invariant(!isPaused());
if (_debug.remoteOpWaitTime) {
@@ -769,63 +664,6 @@ public:
return computeElapsedTimeTotal(start, _end.load()) - _totalPausedDuration;
}
- /**
- * The planningTimeMicros metric, reported in the system profiler and in queryStats, is measured
- * using the Curop instance's _tickSource. Currently, _tickSource is only paused in places where
- logical work is being done. If this were to change, and _tickSource
- were to be paused during query planning for reasons unrelated to the work of
- planning/optimization, it would break the planning time measurement below.
- *
- */
- void beginQueryPlanningTimer() {
- // This is an inner executor/cursor, the metrics for which don't get tracked by
- // OpDebug::planningTime.
- if (_queryPlanningStart.load() != 0) {
- return;
- }
- _queryPlanningStart = _tickSource->getTicks();
- }
-
- void stopQueryPlanningTimer() {
- // The planningTime metric is defined as being done once PrepareExecutionHelper::prepare()
- // is hit, which calls this function to stop the timer. As certain queries like $lookup
- // require inner cursors/executors that will follow this same codepath, it is important to
- // make sure the metric exclusively captures the time associated with the outermost cursor.
- // This is done by making sure planningTime has not already been set and that start has been
- // marked (as inner executors are prepared outside of the codepath that begins the planning
- // timer).
- auto start = _queryPlanningStart.load();
- if (debug().planningTime == Microseconds{0} && start != 0) {
- _queryPlanningEnd = _tickSource->getTicks();
- debug().planningTime = computeElapsedTimeTotal(start, _queryPlanningEnd.load());
- }
- }
-
- /**
- * Starts the waitForWriteConcern timer.
- *
- * The timer must be ended before it can be started again.
- */
- void beginWaitForWriteConcernTimer() {
- invariant(_waitForWriteConcernStart.load() == 0);
- _waitForWriteConcernStart = _tickSource->getTicks();
- _waitForWriteConcernEnd = 0;
- }
-
- /**
- * Stops the waitForWriteConcern timer.
- *
- * Does nothing if the timer has not been started.
- */
- void stopWaitForWriteConcernTimer() {
- auto start = _waitForWriteConcernStart.load();
- if (start != 0) {
- _waitForWriteConcernEnd = _tickSource->getTicks();
- debug().waitForWriteConcernDurationMillis += duration_cast<Milliseconds>(
- computeElapsedTimeTotal(start, _waitForWriteConcernEnd.load()));
- _waitForWriteConcernStart = 0;
- }
- }
/**
* 'opDescription' must be either an owned BSONObj or guaranteed to outlive the OperationContext
@@ -951,6 +789,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;
@@ -1021,14 +869,6 @@ private:
UserAcquisitionStats _userAcquisitionStats;
TickSource* _tickSource = nullptr;
-
- // These values are used to calculate the amount of time spent waiting for write concern.
- std::atomic<TickSource::Tick> _waitForWriteConcernStart{0}; // NOLINT
- std::atomic<TickSource::Tick> _waitForWriteConcernEnd{0}; // NOLINT
-
- // These values are used to calculate the amount of time spent planning a query.
- std::atomic<TickSource::Tick> _queryPlanningStart{0}; // NOLINT
- std::atomic<TickSource::Tick> _queryPlanningEnd{0}; // NOLINT
};
} // namespace mongo