diff options
Diffstat (limited to 'src/mongo/db/cursor_manager.cpp')
| -rw-r--r-- | src/mongo/db/cursor_manager.cpp | 118 |
1 files changed, 55 insertions, 63 deletions
diff --git a/src/mongo/db/cursor_manager.cpp b/src/mongo/db/cursor_manager.cpp index f57c67a6c75..d80a33e62ae 100644 --- a/src/mongo/db/cursor_manager.cpp +++ b/src/mongo/db/cursor_manager.cpp @@ -53,7 +53,6 @@ #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context.h" #include "mongo/db/query/plan_executor.h" -#include "mongo/db/query/query_feature_flags_gen.h" #include "mongo/db/query/query_knobs_gen.h" #include "mongo/db/service_context.h" #include "mongo/logv2/log.h" @@ -62,6 +61,29 @@ namespace mongo { +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); + constexpr int CursorManager::kNumPartitions; namespace { @@ -74,6 +96,26 @@ ServiceContext::ConstructorActionRegisterer cursorManagerRegisterer{ auto cursorManager = std::make_unique<CursorManager>(svcCtx->getPreciseClockSource()); CursorManager::set(svcCtx, std::move(cursorManager)); }}; + +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(); + } +} } // namespace CursorManager* CursorManager::get(ServiceContext* svcCtx) { @@ -119,7 +161,7 @@ CursorManager::~CursorManager() { for (auto&& cursor : *partition) { // Callers must ensure that no cursors are in use. invariant(!cursor.second->_operationUsingCursor); - cursor.second->dispose(nullptr, boost::none); + cursor.second->dispose(nullptr); delete cursor.second; } } @@ -159,29 +201,11 @@ std::size_t CursorManager::timeoutCursors(OperationContext* opCtx, Date_t now) { "Cursor timed out", "cursorId"_attr = cursor->cursorid(), "idleSince"_attr = cursor->getLastUseDate()); - cursor->dispose(opCtx, boost::none); + cursor->dispose(opCtx); } return toDisposeWithoutMutex.size(); } -std::vector<CursorId> CursorManager::getCursorIdsForNamespace(const NamespaceString& nss) { - std::vector<CursorId> cursorIds; - - // Lock and inspect one partition at a time in order to avoid contention. It is acceptable for - // the output not to include info about cursors opened/closed while iterating. - for (size_t partitionId = 0; partitionId < kNumPartitions; ++partitionId) { - auto lockedPartition = _cursorMap->lockOnePartitionById(partitionId); - for (auto it = lockedPartition->begin(); it != lockedPartition->end(); ++it) { - auto* cursor = it->second; - if (cursor->nss() == nss) { - cursorIds.push_back(cursor->cursorid()); - } - } - } - - return cursorIds; -} - StatusWith<ClientCursorPin> CursorManager::pinCursor( OperationContext* opCtx, CursorId id, @@ -221,11 +245,6 @@ StatusWith<ClientCursorPin> CursorManager::pinCursor( CurOp::get(opCtx)->debug().queryHash = cursor->_queryHash; CurOp::get(opCtx)->debug().planCacheKey = cursor->_planCacheKey; - // Pass along queryStats context so it is retrievable after query execution for storing metrics. - CurOp::get(opCtx)->debug().queryStatsInfo.keyHash = cursor->_queryStatsKeyHash; - CurOp::get(opCtx)->debug().queryStatsInfo.willNeverExhaust = - cursor->_queryStatsWillNeverExhaust; - cursor->_operationUsingCursor = opCtx; // We use pinning of a cursor as a proxy for active, user-initiated use of a cursor. Therefore, @@ -262,7 +281,7 @@ void CursorManager::unpin(OperationContext* opCtx, // interesting in proactively cleaning up that cursor's resources. In these cases, we // proactively delete the cursor. In other cases we preserve the error code so that the client // will see the reason the cursor was killed when asking for the next batch. - if (interruptStatus == ErrorCodes::Interrupted || cursor->isKillPending()) { + if (interruptStatus == ErrorCodes::Interrupted || interruptStatus == ErrorCodes::CursorKilled) { LOGV2(20530, "removing cursor {cursor_cursorid} after completing batch: {error}", "Removing cursor after completing batch", @@ -270,7 +289,7 @@ void CursorManager::unpin(OperationContext* opCtx, "error"_attr = interruptStatus); return deregisterAndDestroyCursor(std::move(partition), opCtx, std::move(cursor)); } else if (!interruptStatus.isOK()) { - cursor->getExecutor()->markAsKilled(interruptStatus); + cursor->markAsKilled(interruptStatus); } // The cursor will stay around in '_cursorMap', so release the unique pointer to avoid deleting @@ -339,11 +358,8 @@ stdx::unordered_set<CursorId> CursorManager::getCursorsForOpKeys( stdx::lock_guard<Latch> lk(_opKeyMutex); for (auto opKey : opKeys) { - if (auto it = _opKeyMap.find(opKey); it != _opKeyMap.end()) { - for (auto cursor : it->second) { - cursors.insert(cursor); - } - } + if (auto it = _opKeyMap.find(opKey); it != _opKeyMap.end()) + cursors.insert(it->second); } return cursors; } @@ -390,12 +406,7 @@ ClientCursorPin CursorManager::registerCursor(OperationContext* opCtx, // If set, store the mapping of OperationKey to the generated CursorID. if (auto opKey = opCtx->getOperationKey()) { stdx::lock_guard<Latch> lk(_opKeyMutex); - auto it = _opKeyMap.find(*opKey); - if (it != _opKeyMap.end()) { - it->second.insert(cursorId); - } else { - _opKeyMap.emplace(*opKey, std::set<CursorId>{cursorId}); - } + _opKeyMap.emplace(*opKey, cursorId); } // Restores the maxTimeMS provided in the cursor generating command in the case it used @@ -406,41 +417,26 @@ ClientCursorPin CursorManager::registerCursor(OperationContext* opCtx, return ClientCursorPin(opCtx, unownedCursor, this); } -// Note the following subleties of the implementations of deregisterAndDestroyCursor: -// - We must make sure the cursor is unpinned (by clearing the '_operationUsingCursor' field) before -// destruction, since it is an error to delete a pinned cursor. -// - In addition, we must deregister the cursor from the manager's map before clearing the -// '_operationUsingCursor' field, since it is an error to unpin a registered cursor without -// holidng 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. -void CursorManager::deregisterAndDestroyCursor( - OperationContext* opCtx, std::unique_ptr<ClientCursor, ClientCursor::Deleter> cursor) { - removeCursorFromMap(_cursorMap, cursor.get()); - _destroyCursor(opCtx, std::move(cursor)); +void CursorManager::deregisterCursor(ClientCursor* cursor) { + removeCursorFromMap(_cursorMap, cursor); + incrementCursorLifespanMetric(cursor->_createdDate, _preciseClockSource->now()); } void CursorManager::deregisterAndDestroyCursor( Partitioned<stdx::unordered_map<CursorId, ClientCursor*>>::OnePartition&& lk, OperationContext* opCtx, std::unique_ptr<ClientCursor, ClientCursor::Deleter> cursor) { - // Restrict the scope of the lock so we can destroy the cursor without holding any cursor - // manager mutexes. { auto lockWithRestrictedScope = std::move(lk); removeCursorFromMap(lockWithRestrictedScope, cursor.get()); } - _destroyCursor(opCtx, std::move(cursor)); -} -void CursorManager::_destroyCursor(OperationContext* opCtx, - std::unique_ptr<ClientCursor, ClientCursor::Deleter> cursor) { + incrementCursorLifespanMetric(cursor->_createdDate, _preciseClockSource->now()); // Dispose of the cursor without holding any cursor manager mutexes. Disposal of a cursor can // require taking lock manager locks, which we want to avoid while holding a mutex. If we did // so, any caller of a CursorManager method which already held a lock manager lock could induce // a deadlock when trying to acquire a CursorManager lock. - cursor->dispose(opCtx, _preciseClockSource->now()); - cursor->_operationUsingCursor = nullptr; + cursor->dispose(opCtx); } Status CursorManager::killCursor(OperationContext* opCtx, CursorId id) { @@ -460,10 +456,6 @@ Status CursorManager::killCursor(OperationContext* opCtx, CursorId id) { cursor->_operationUsingCursor->getServiceContext()->killOperation( lk, cursor->_operationUsingCursor, ErrorCodes::CursorKilled); } - - // Mark that the cursor has been killed on the cursor object itself as well, as other errors - // e.g. MaxTimeMSExpired may override the CursorKilled status. - cursor->setKillPending(true); return Status::OK(); } std::unique_ptr<ClientCursor, ClientCursor::Deleter> ownedCursor(cursor); |
