ClientCursor::~ClientCursor() { // Cursors must be unpinned and deregistered from their cursor manager before being deleted. invariant(!_operationUsingCursor); invariant(_disposed); cursorStatsOpen.decrement(); if (isNoTimeout()) { cursorStatsOpenNoTimeout.decrement(); } }
void CursorCache::removeRef(long long id) { verify(id); stdx::lock_guard<stdx::mutex> lk(_mutex); _refs.erase(id); _refsNS.erase(id); cursorStatsSingleTarget.decrement(); }
void ClientCursorPin::deleteUnderlying() { invariant(_cursor); invariant(_cursor->_operationUsingCursor); // Note the following subtleties of this method's implementation: // - We must unpin the cursor before destruction, since it is an error to delete a pinned // cursor. // - In addition, we must deregister the cursor before unpinning, since it is an // error to unpin a registered cursor without holding the cursor manager lock (note that // we can't simply unpin with the cursor manager lock here, since we need to guarantee // exclusive ownership of the cursor when we are deleting it). // Note it's not safe to dereference _cursor->_cursorManager unless we know we haven't been // killed. If we're not locked we assume we haven't been killed because we're working with the // global cursor manager which never kills cursors. dassert(_opCtx->lockState()->isCollectionLockedForMode(_cursor->_nss.ns(), MODE_IS) || _cursor->_cursorManager->isGlobalManager()); if (!_cursor->getExecutor()->isMarkedAsKilled()) { _cursor->_cursorManager->deregisterCursor(_cursor); } // Make sure the cursor is disposed and unpinned before being destroyed. _cursor->dispose(_opCtx); _cursor->_operationUsingCursor = nullptr; delete _cursor; cursorStatsOpenPinned.decrement(); _cursor = nullptr; }
void CursorCache::removeRef(long long id) { verify(id); scoped_lock lk(_mutex); _refs.erase(id); _refsNS.erase(id); cursorStatsSingleTarget.decrement(); }
void ClientCursorPin::release() { if (!_cursor) return; // Note it's not safe to dereference _cursor->_cursorManager unless we know we haven't been // killed. If we're not locked we assume we haven't been killed because we're working with the // global cursor manager which never kills cursors. dassert(_opCtx->lockState()->isCollectionLockedForMode(_cursor->_nss.ns(), MODE_IS) || _cursor->_cursorManager->isGlobalManager()); invariant(_cursor->_operationUsingCursor); if (_cursor->getExecutor()->isMarkedAsKilled()) { // The ClientCursor was killed while we had it. Therefore, it is our responsibility to // call dispose() and delete it. deleteUnderlying(); } else { // Unpin the cursor under the collection cursor manager lock. _cursor->_cursorManager->unpin(_opCtx, _cursor); cursorStatsOpenPinned.decrement(); } _cursor = nullptr; }
void CursorCache::gotKillCursors(Message& m) { LastError::get(cc()).disable(); DbMessage dbmessage(m); int n = dbmessage.pullInt(); if (n > 2000) { (n < 30000 ? warning() : error()) << "receivedKillCursors, n=" << n << endl; } uassert(13286, "sent 0 cursors to kill", n >= 1); uassert(13287, "too many cursors to kill", n < 30000); massert(18632, str::stream() << "bad kill cursors size: " << m.dataSize(), m.dataSize() == 8 + (8 * n)); ConstDataCursor cursors(dbmessage.getArray(n)); ClientBasic* client = ClientBasic::getCurrent(); AuthorizationSession* authSession = AuthorizationSession::get(client); for (int i = 0; i < n; i++) { long long id = cursors.readAndAdvance<LittleEndian<int64_t>>(); LOG(_myLogLevel) << "CursorCache::gotKillCursors id: " << id << endl; if (!id) { warning() << " got cursor id of 0 to kill" << endl; continue; } string server; { stdx::lock_guard<stdx::mutex> lk(_mutex); MapSharded::iterator i = _cursors.find(id); if (i != _cursors.end()) { Status authorizationStatus = authSession->checkAuthForKillCursors(NamespaceString(i->second->getNS()), id); audit::logKillCursorsAuthzCheck( client, NamespaceString(i->second->getNS()), id, authorizationStatus.isOK() ? ErrorCodes::OK : ErrorCodes::Unauthorized); if (authorizationStatus.isOK()) { _cursorsMaxTimeMS.erase(i->second->getId()); _cursors.erase(i); } continue; } MapNormal::iterator refsIt = _refs.find(id); MapNormal::iterator refsNSIt = _refsNS.find(id); if (refsIt == _refs.end()) { warning() << "can't find cursor: " << id << endl; continue; } verify(refsNSIt != _refsNS.end()); Status authorizationStatus = authSession->checkAuthForKillCursors(NamespaceString(refsNSIt->second), id); audit::logKillCursorsAuthzCheck(client, NamespaceString(refsNSIt->second), id, authorizationStatus.isOK() ? ErrorCodes::OK : ErrorCodes::Unauthorized); if (!authorizationStatus.isOK()) { continue; } server = refsIt->second; _refs.erase(refsIt); _refsNS.erase(refsNSIt); cursorStatsSingleTarget.decrement(); } LOG(_myLogLevel) << "CursorCache::found gotKillCursors id: " << id << " server: " << server << endl; verify(server.size()); ScopedDbConnection conn(server); conn->killCursor(id); conn.done(); } }
ShardedClientCursor::~ShardedClientCursor() { verify(_cursor); delete _cursor; _cursor = 0; cursorStatsMultiTarget.decrement(); }