diff options
Diffstat (limited to 'src/mongo/db/curop.h')
| -rw-r--r-- | src/mongo/db/curop.h | 212 |
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 |
