summaryrefslogtreecommitdiff
path: root/src/mongo/db/clientcursor.cpp
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-18 17:02:53 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-18 17:02:53 -0300
commit959575a5ca598bf5f37fb5cebe7ed1d80d3d71f7 (patch)
treeacc8d60aedb12b70048e676e8a7349deb0010db8 /src/mongo/db/clientcursor.cpp
parent76588293975fc059cf076779e4283e6ffaf8afff (diff)
New upstream version 6.0.20upstream
Diffstat (limited to 'src/mongo/db/clientcursor.cpp')
-rw-r--r--src/mongo/db/clientcursor.cpp129
1 files changed, 106 insertions, 23 deletions
diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp
index 12aa1cedab0..ac60a6b14be 100644
--- a/src/mongo/db/clientcursor.cpp
+++ b/src/mongo/db/clientcursor.cpp
@@ -51,6 +51,7 @@
#include "mongo/db/cursor_server_params.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/query/explain.h"
+#include "mongo/db/query/query_stats/query_stats.h"
#include "mongo/db/repl/repl_client_info.h"
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/util/background.h"
@@ -81,6 +82,49 @@ static ServerStatusMetricField<Counter64> dCursorStatsTotalOpened("cursor.totalO
static ServerStatusMetricField<Counter64> dCursorStatsMoreThanOneBatch(
"cursor.moreThanOneBatch", &cursorStatsMoreThanOneBatch);
+static Counter64 cursorStatsLifespanLessThan1Second;
+static Counter64 cursorStatsLifespanLessThan5Seconds;
+static Counter64 cursorStatsLifespanLessThan15Seconds;
+static Counter64 cursorStatsLifespanLessThan30Seconds;
+static Counter64 cursorStatsLifespanLessThan1Minute;
+static Counter64 cursorStatsLifespanLessThan10Minutes;
+static Counter64 cursorStatsLifespanGreaterThanOrEqual10Minutes;
+
+static ServerStatusMetricField<Counter64> dCursorStatsLifespanLessThan1Second(
+ "cursor.lifespan.lessThan1Second", &cursorStatsLifespanLessThan1Second);
+static ServerStatusMetricField<Counter64> dCursorStatsLifespanLessThan5Seconds(
+ "cursor.lifespan.lessThan5Seconds", &cursorStatsLifespanLessThan5Seconds);
+static ServerStatusMetricField<Counter64> dCursorStatsLifespanLessThan15Seconds(
+ "cursor.lifespan.lessThan15Seconds", &cursorStatsLifespanLessThan15Seconds);
+static ServerStatusMetricField<Counter64> dCursorStatsLifespanLessThan30Seconds(
+ "cursor.lifespan.lessThan30Seconds", &cursorStatsLifespanLessThan30Seconds);
+static ServerStatusMetricField<Counter64> dCursorStatsLifespanLessThan1Minute(
+ "cursor.lifespan.lessThan1Minute", &cursorStatsLifespanLessThan1Minute);
+static ServerStatusMetricField<Counter64> dCursorStatsLifespanLessThan10Minutes(
+ "cursor.lifespan.lessThan10Minutes", &cursorStatsLifespanLessThan10Minutes);
+static ServerStatusMetricField<Counter64> dCursorStatsLifespanGreaterThanOrEqual10Minutes(
+ "cursor.lifespan.greaterThanOrEqual10Minutes", &cursorStatsLifespanGreaterThanOrEqual10Minutes);
+
+void incrementCursorLifespanMetric(Date_t birth, Date_t death) {
+ auto elapsed = death - birth;
+
+ if (elapsed < Seconds(1)) {
+ cursorStatsLifespanLessThan1Second.increment();
+ } else if (elapsed < Seconds(5)) {
+ cursorStatsLifespanLessThan5Seconds.increment();
+ } else if (elapsed < Seconds(15)) {
+ cursorStatsLifespanLessThan15Seconds.increment();
+ } else if (elapsed < Seconds(30)) {
+ cursorStatsLifespanLessThan30Seconds.increment();
+ } else if (elapsed < Minutes(1)) {
+ cursorStatsLifespanLessThan1Minute.increment();
+ } else if (elapsed < Minutes(10)) {
+ cursorStatsLifespanLessThan10Minutes.increment();
+ } else {
+ cursorStatsLifespanGreaterThanOrEqual10Minutes.increment();
+ }
+}
+
ClientCursor::ClientCursor(ClientCursorParams params,
CursorId cursorId,
OperationContext* operationUsingCursor,
@@ -105,6 +149,10 @@ ClientCursor::ClientCursor(ClientCursorParams params,
_planSummary(_exec->getPlanExplainer().getPlanSummary()),
_planCacheKey(CurOp::get(operationUsingCursor)->debug().planCacheKey),
_queryHash(CurOp::get(operationUsingCursor)->debug().queryHash),
+ _queryStatsKeyHash(CurOp::get(operationUsingCursor)->debug().queryStatsInfo.keyHash),
+ _queryStatsKey(std::move(CurOp::get(operationUsingCursor)->debug().queryStatsInfo.key)),
+ _queryStatsWillNeverExhaust(
+ CurOp::get(operationUsingCursor)->debug().queryStatsInfo.willNeverExhaust),
_opKey(operationUsingCursor->getOperationKey()) {
invariant(_exec);
invariant(_operationUsingCursor);
@@ -129,19 +177,33 @@ ClientCursor::~ClientCursor() {
// needs to keep data pinned.
_stashedRecoveryUnit->setAbandonSnapshotMode(RecoveryUnit::AbandonSnapshotMode::kAbort);
}
+}
+
+void ClientCursor::dispose(OperationContext* opCtx, boost::optional<Date_t> now) {
+ if (_disposed) {
+ return;
+ }
+
+ query_stats::writeQueryStatsOnCursorDisposeOrKill(
+ opCtx,
+ _queryStatsKeyHash,
+ std::move(_queryStatsKey),
+ _queryStatsWillNeverExhaust,
+ _metrics.executionTime.value_or(Microseconds{0}).count(),
+ _firstResponseExecutionTime.value_or(Microseconds{0}).count(),
+ _metrics.nreturned.value_or(0));
+
+ if (now) {
+ incrementCursorLifespanMetric(_createdDate, *now);
+ }
cursorStatsOpen.decrement();
if (isNoTimeout()) {
cursorStatsOpenNoTimeout.decrement();
}
- if (_nBatchesReturned > 1)
+ if (_metrics.nBatches && *_metrics.nBatches > 1) {
cursorStatsMoreThanOneBatch.increment();
-}
-
-void ClientCursor::dispose(OperationContext* opCtx) {
- if (_disposed) {
- return;
}
_exec->dispose(opCtx);
@@ -152,7 +214,7 @@ GenericCursor ClientCursor::toGenericCursor() const {
GenericCursor gc;
gc.setCursorId(cursorid());
gc.setNs(nss());
- gc.setNDocsReturned(_nReturnedSoFar);
+ gc.setNDocsReturned(_metrics.nreturned.value_or(0));
gc.setTailable(isTailable());
gc.setAwaitData(isAwaitData());
gc.setNoCursorTimeout(isNoTimeout());
@@ -265,24 +327,12 @@ void ClientCursorPin::deleteUnderlying() {
invariant(_cursor);
invariant(_cursor->_operationUsingCursor);
invariant(_cursorManager);
- // Note the following subtleties of this method's implementation:
- // - We must unpin the cursor (by clearing the '_operationUsingCursor' field) before
- // destruction, since it is an error to delete a pinned cursor.
- // - In addition, we must deregister the cursor before clearing the '_operationUsingCursor'
- // field, since it is an error to unpin a registered cursor without holding the appropriate
- // cursor manager mutex. By first deregistering the cursor, we ensure that no other thread can
- // access '_cursor', meaning that it is safe for us to write to '_operationUsingCursor'
- // without holding the CursorManager mutex.
-
- _cursorManager->deregisterCursor(_cursor);
-
- // Make sure the cursor is disposed and unpinned before being destroyed.
- _cursor->dispose(_opCtx);
- _cursor->_operationUsingCursor = nullptr;
- delete _cursor;
- cursorStatsOpenPinned.decrement();
+ std::unique_ptr<ClientCursor, ClientCursor::Deleter> ownedCursor(_cursor);
_cursor = nullptr;
+ _cursorManager->deregisterAndDestroyCursor(_opCtx, std::move(ownedCursor));
+
+ cursorStatsOpenPinned.decrement();
_shouldSaveRecoveryUnit = false;
}
@@ -354,4 +404,37 @@ void startClientCursorMonitor() {
getClientCursorMonitor(getGlobalServiceContext()).go();
}
+void collectQueryStatsMongod(OperationContext* opCtx, ClientCursorPin& pinnedCursor) {
+ pinnedCursor->incrementCursorMetrics(CurOp::get(opCtx)->debug().additiveMetrics);
+
+ // For a change stream query, we want to collect and update query stats on the initial query and
+ // for every getMore.
+ // TODO SERVER-89058 Modify comment to include tailable cursors.
+ if (pinnedCursor->getQueryStatsWillNeverExhaust()) {
+ auto& opDebug = CurOp::get(opCtx)->debug();
+
+ int64_t execTime = opDebug.additiveMetrics.executionTime.value_or(Microseconds{0}).count();
+ query_stats::writeQueryStats(opCtx,
+ opDebug.queryStatsInfo.keyHash,
+ pinnedCursor->takeKey(),
+ execTime,
+ execTime,
+ opDebug.additiveMetrics.nreturned.value_or(0),
+ pinnedCursor->getQueryStatsWillNeverExhaust());
+ }
+}
+
+void collectQueryStatsMongod(OperationContext* opCtx, std::unique_ptr<query_stats::Key> key) {
+ // If we haven't registered a cursor to prepare for getMore requests, we record
+ // query stats directly.
+ auto& opDebug = CurOp::get(opCtx)->debug();
+ int64_t execTime = opDebug.additiveMetrics.executionTime.value_or(Microseconds{0}).count();
+ query_stats::writeQueryStats(opCtx,
+ opDebug.queryStatsInfo.keyHash,
+ std::move(key),
+ execTime,
+ execTime,
+ opDebug.additiveMetrics.nreturned.value_or(0));
+}
+
} // namespace mongo