diff options
author | David Storch <david.storch@10gen.com> | 2019-01-17 10:36:29 -0500 |
---|---|---|
committer | David Storch <david.storch@10gen.com> | 2019-01-23 21:18:45 -0500 |
commit | 84b142d5123c06212ce7a2e495ae8afe48eb65cb (patch) | |
tree | e267b75425b6b61c863d73276a7be137f4109fc9 | |
parent | 869b3b64a898076ff98405fa70403084417cb164 (diff) | |
download | mongo-84b142d5123c06212ce7a2e495ae8afe48eb65cb.tar.gz |
SERVER-37455 Delete per-collection cursor managers.
35 files changed, 143 insertions, 466 deletions
diff --git a/jstests/noPassthrough/cursor_timeout_interrupt.js b/jstests/noPassthrough/cursor_timeout_interrupt.js deleted file mode 100644 index a97142d4975..00000000000 --- a/jstests/noPassthrough/cursor_timeout_interrupt.js +++ /dev/null @@ -1,61 +0,0 @@ -// Tests the cursor timeout background thread is not subject to interrupt when acquiring locks. This -// test was designed to reproduce SERVER-33785. -(function() { - "use strict"; - - // We're testing the client cursor monitor thread, so make it run with a higher frequency. - const options = {setParameter: {clientCursorMonitorFrequencySecs: 0}}; - const conn = MongoRunner.runMongod(options); - assert.neq(conn, null, `Mongod failed to start up with options ${tojson(options)}`); - const db = conn.getDB("test"); - const coll = db.cursor_timeout_interrupt; - - // Create a collection and open a cursor on the collection. - const batchSize = 10; - for (var i = 1; i < 2 * batchSize; ++i) { - assert.writeOK(coll.insert({})); - } - const cursor = coll.find({}).batchSize(batchSize); - cursor.next(); - assert.eq(db.serverStatus().metrics.cursor.open.total, 1); - const originalTopTotal = db.adminCommand({top: 1}).totals[coll.getFullName()].total; - - // Start an operation which is holding the lock the timeout thread will need. At a minimum, we - // need someone to be holding the lock in order for the thread to ever bother checking for - // interrupt when acquiring locks. - const awaitConflictingLock = startParallelShell( - () => assert.commandFailedWithCode(db.adminCommand({sleep: 1, lock: "w", secs: 5 * 60}), - ErrorCodes.Interrupted), - conn.port); - - // Enable a failpoint that will cause a thread to always be interrupted. Test that the client - // cursor monitor thread ignores interrupts, including during lock acquisitions. - assert.commandWorked(db.adminCommand({ - configureFailPoint: "checkForInterruptFail", - mode: "alwaysOn", - data: {threadName: "clientcursormon", chance: 1} - })); - - // Lower the cursor timeout threshold to make the newly created cursor eligible for timeout. - assert.commandWorked(db.adminCommand({setParameter: 1, cursorTimeoutMillis: 1})); - - // Wait to verify that the client cursor is blocked waiting on the thread holding the lock. - assert.soon(() => db.currentOp({desc: "clientcursormon", active: true, waitingForLock: true}) - .inprog.length === 1); - - const sleepOps = db.getSiblingDB("admin").currentOp({"command.sleep": 1, active: true}).inprog; - assert.eq(sleepOps.length, 1); - const sleepOpId = sleepOps[0].opid; - assert.commandWorked(db.adminCommand({killOp: 1, op: sleepOpId})); - - assert.soon(() => db.serverStatus().metrics.cursor.open.total == 0); - assert.eq(db.serverStatus().metrics.cursor.timedOut, 1); - assert.commandWorked( - db.adminCommand({configureFailPoint: "checkForInterruptFail", mode: "off"})); - - // Test that the client cursor monitor does not increment any stats for top. - assert.eq(db.adminCommand({top: 1}).totals[coll.getFullName()].total, originalTopTotal); - awaitConflictingLock(); - - MongoRunner.stopMongod(conn); -}()); diff --git a/src/mongo/db/catalog/SConscript b/src/mongo/db/catalog/SConscript index 1d1a5868aae..6b8390933ee 100644 --- a/src/mongo/db/catalog/SConscript +++ b/src/mongo/db/catalog/SConscript @@ -364,7 +364,6 @@ env.Library( '$BUILD_DIR/mongo/db/index/index_access_method', '$BUILD_DIR/mongo/db/index_d', '$BUILD_DIR/mongo/db/op_observer', - '$BUILD_DIR/mongo/db/query_exec', '$BUILD_DIR/mongo/db/repl/drop_pending_collection_reaper', '$BUILD_DIR/mongo/db/repl/oplog', '$BUILD_DIR/mongo/db/server_options_core', diff --git a/src/mongo/db/catalog/catalog_control.cpp b/src/mongo/db/catalog/catalog_control.cpp index fa6ed43e9e5..151886c033c 100644 --- a/src/mongo/db/catalog/catalog_control.cpp +++ b/src/mongo/db/catalog/catalog_control.cpp @@ -80,8 +80,7 @@ MinVisibleTimestampMap closeCatalog(OperationContext* opCtx) { // Close all databases. log() << "closeCatalog: closing all databases"; - constexpr auto reason = "closing databases for closeCatalog"; - databaseHolder->closeAll(opCtx, reason); + databaseHolder->closeAll(opCtx); // Close the storage engine's catalog. log() << "closeCatalog: closing storage engine catalog"; diff --git a/src/mongo/db/catalog/collection.h b/src/mongo/db/catalog/collection.h index 41ce7a9fc74..b32c0e449b8 100644 --- a/src/mongo/db/catalog/collection.h +++ b/src/mongo/db/catalog/collection.h @@ -42,7 +42,6 @@ #include "mongo/db/catalog/collection_info_cache.h" #include "mongo/db/catalog/collection_options.h" #include "mongo/db/concurrency/d_concurrency.h" -#include "mongo/db/cursor_manager.h" #include "mongo/db/logical_session_id.h" #include "mongo/db/namespace_string.h" #include "mongo/db/query/collation/collator_interface.h" @@ -198,8 +197,6 @@ public: virtual const RecordStore* getRecordStore() const = 0; virtual RecordStore* getRecordStore() = 0; - virtual CursorManager* getCursorManager() const = 0; - virtual bool requiresIdIndex() const = 0; virtual Snapshotted<BSONObj> docFor(OperationContext* const opCtx, RecordId loc) const = 0; diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp index a1e0153720e..54c44632f46 100644 --- a/src/mongo/db/catalog/collection_impl.cpp +++ b/src/mongo/db/catalog/collection_impl.cpp @@ -218,7 +218,6 @@ CollectionImpl::CollectionImpl(OperationContext* opCtx, _parseValidationAction(_details->getCollectionOptions(opCtx).validationAction))), _validationLevel(uassertStatusOK( _parseValidationLevel(_details->getCollectionOptions(opCtx).validationLevel))), - _cursorManager(std::make_unique<CursorManager>(_ns)), _cappedNotifier(_recordStore->isCapped() ? stdx::make_unique<CappedInsertNotifier>() : nullptr) { @@ -799,7 +798,6 @@ Status CollectionImpl::truncate(OperationContext* opCtx) { // 2) drop indexes _indexCatalog->dropAllIndexes(opCtx, true); - _cursorManager->invalidateAll(opCtx, false, "collection truncated"); // 3) truncate record store auto status = _recordStore->truncate(opCtx); @@ -822,7 +820,6 @@ void CollectionImpl::cappedTruncateAfter(OperationContext* opCtx, RecordId end, BackgroundOperation::assertNoBgOpInProgForNs(ns()); invariant(_indexCatalog->numIndexesInProgress(opCtx) == 0); - _cursorManager->invalidateAll(opCtx, false, "capped collection truncated"); _recordStore->cappedTruncateAfter(opCtx, end, inclusive); } @@ -1329,14 +1326,6 @@ void CollectionImpl::setNs(NamespaceString nss) { _indexCatalog->setNs(_ns); _infoCache->setNs(_ns); _recordStore->setNs(_ns); - - // Until the query layer is prepared for cursors to survive renames, all cursors are killed when - // the name of a collection changes. Therefore, the CursorManager should be empty. This means it - // is safe to re-establish it with a new namespace by tearing down the old one and allocating a - // new manager associated with the new name. This is done in order to ensure that the - // 'globalCursorIdCache' maintains the correct mapping from cursor id "prefix" (the high order - // bits) to namespace. - _cursorManager = std::make_unique<CursorManager>(_ns); } void CollectionImpl::indexBuildSuccess(OperationContext* opCtx, IndexCatalogEntry* index) { diff --git a/src/mongo/db/catalog/collection_impl.h b/src/mongo/db/catalog/collection_impl.h index 149c77d75f6..1260150ca49 100644 --- a/src/mongo/db/catalog/collection_impl.h +++ b/src/mongo/db/catalog/collection_impl.h @@ -101,10 +101,6 @@ public: return _recordStore; } - CursorManager* getCursorManager() const final { - return _cursorManager.get(); - } - bool requiresIdIndex() const final; Snapshotted<BSONObj> docFor(OperationContext* opCtx, RecordId loc) const final { @@ -415,8 +411,6 @@ private: ValidationAction _validationAction; ValidationLevel _validationLevel; - std::unique_ptr<CursorManager> _cursorManager; - // Notifier object for awaitData. Threads polling a capped collection for new data can wait // on this object until notified of the arrival of new data. // diff --git a/src/mongo/db/catalog/collection_mock.h b/src/mongo/db/catalog/collection_mock.h index 30e2ee1fee6..9f294717914 100644 --- a/src/mongo/db/catalog/collection_mock.h +++ b/src/mongo/db/catalog/collection_mock.h @@ -87,10 +87,6 @@ public: std::abort(); } - CursorManager* getCursorManager() const { - std::abort(); - } - bool requiresIdIndex() const { std::abort(); } diff --git a/src/mongo/db/catalog/database.h b/src/mongo/db/catalog/database.h index 74ff3b6f42b..66d40285b6c 100644 --- a/src/mongo/db/catalog/database.h +++ b/src/mongo/db/catalog/database.h @@ -132,7 +132,7 @@ public: virtual void init(OperationContext* opCtx) = 0; // closes files and other cleanup see below. - virtual void close(OperationContext* const opCtx, const std::string& reason) = 0; + virtual void close(OperationContext* const opCtx) = 0; virtual const std::string& name() const = 0; diff --git a/src/mongo/db/catalog/database_holder.h b/src/mongo/db/catalog/database_holder.h index 825d413e6d9..07fe4a5dfd8 100644 --- a/src/mongo/db/catalog/database_holder.h +++ b/src/mongo/db/catalog/database_holder.h @@ -90,17 +90,13 @@ public: * Closes the specified database. Must be called with the database locked in X-mode. * No background jobs must be in progress on the database when this function is called. */ - virtual void close(OperationContext* const opCtx, - const StringData ns, - const std::string& reason) = 0; + virtual void close(OperationContext* opCtx, const StringData ns) = 0; /** * Closes all opened databases. Must be called with the global lock acquired in X-mode. * Will uassert if any background jobs are running when this function is called. - * - * @param reason The reason for close. */ - virtual void closeAll(OperationContext* const opCtx, const std::string& reason) = 0; + virtual void closeAll(OperationContext* opCtx) = 0; /** * Returns the set of existing database names that differ only in casing. diff --git a/src/mongo/db/catalog/database_holder_impl.cpp b/src/mongo/db/catalog/database_holder_impl.cpp index 483e96e4f17..f72e495875c 100644 --- a/src/mongo/db/catalog/database_holder_impl.cpp +++ b/src/mongo/db/catalog/database_holder_impl.cpp @@ -181,7 +181,7 @@ void DatabaseHolderImpl::dropDb(OperationContext* opCtx, Database* db) { Top::get(serviceContext).collectionDropped(coll->ns().ns(), true); } - close(opCtx, name, "database dropped"); + close(opCtx, name); auto const storageEngine = serviceContext->getStorageEngine(); writeConflictRetry(opCtx, "dropDatabase", name, [&] { @@ -198,7 +198,7 @@ void evictDatabaseFromUUIDCatalog(OperationContext* opCtx, Database* db) { } } // namespace -void DatabaseHolderImpl::close(OperationContext* opCtx, StringData ns, const std::string& reason) { +void DatabaseHolderImpl::close(OperationContext* opCtx, StringData ns) { invariant(opCtx->lockState()->isW()); const StringData dbName = _todb(ns); @@ -214,7 +214,7 @@ void DatabaseHolderImpl::close(OperationContext* opCtx, StringData ns, const std repl::oplogCheckCloseDatabase(opCtx, db); evictDatabaseFromUUIDCatalog(opCtx, db); - db->close(opCtx, reason); + db->close(opCtx); delete db; db = nullptr; @@ -226,7 +226,7 @@ void DatabaseHolderImpl::close(OperationContext* opCtx, StringData ns, const std .transitional_ignore(); } -void DatabaseHolderImpl::closeAll(OperationContext* opCtx, const std::string& reason) { +void DatabaseHolderImpl::closeAll(OperationContext* opCtx) { invariant(opCtx->lockState()->isW()); stdx::lock_guard<SimpleMutex> lk(_m); @@ -243,7 +243,7 @@ void DatabaseHolderImpl::closeAll(OperationContext* opCtx, const std::string& re Database* db = _dbs[name]; repl::oplogCheckCloseDatabase(opCtx, db); evictDatabaseFromUUIDCatalog(opCtx, db); - db->close(opCtx, reason); + db->close(opCtx); delete db; _dbs.erase(name); diff --git a/src/mongo/db/catalog/database_holder_impl.h b/src/mongo/db/catalog/database_holder_impl.h index 29b63a8e8ef..cf5f3c290bc 100644 --- a/src/mongo/db/catalog/database_holder_impl.h +++ b/src/mongo/db/catalog/database_holder_impl.h @@ -47,9 +47,9 @@ public: void dropDb(OperationContext* opCtx, Database* db) override; - void close(OperationContext* opCtx, StringData ns, const std::string& reason) override; + void close(OperationContext* opCtx, StringData ns) override; - void closeAll(OperationContext* opCtx, const std::string& reason) override; + void closeAll(OperationContext* opCtx) override; std::set<std::string> getNamesWithConflictingCasing(StringData name) override; diff --git a/src/mongo/db/catalog/database_holder_mock.h b/src/mongo/db/catalog/database_holder_mock.h index dc04fffdf3d..4e50b1a768b 100644 --- a/src/mongo/db/catalog/database_holder_mock.h +++ b/src/mongo/db/catalog/database_holder_mock.h @@ -48,9 +48,9 @@ public: void dropDb(OperationContext* opCtx, Database* db) override {} - void close(OperationContext* opCtx, StringData ns, const std::string& reason) override {} + void close(OperationContext* opCtx, StringData ns) override {} - void closeAll(OperationContext* opCtx, const std::string& reason) override {} + void closeAll(OperationContext* opCtx) override {} std::set<std::string> getNamesWithConflictingCasing(StringData name) override { return std::set<std::string>(); diff --git a/src/mongo/db/catalog/database_impl.cpp b/src/mongo/db/catalog/database_impl.cpp index 3945f6b8e93..688f2adc935 100644 --- a/src/mongo/db/catalog/database_impl.cpp +++ b/src/mongo/db/catalog/database_impl.cpp @@ -184,16 +184,11 @@ DatabaseImpl::~DatabaseImpl() { delete i->second; } -void DatabaseImpl::close(OperationContext* opCtx, const std::string& reason) { +void DatabaseImpl::close(OperationContext* opCtx) { invariant(opCtx->lockState()->isW()); // Clear cache of oplog Collection pointer. repl::oplogCheckCloseDatabase(opCtx, this); - - for (auto&& pair : _collections) { - auto* coll = pair.second; - coll->getCursorManager()->invalidateAll(opCtx, true, reason); - } } Status DatabaseImpl::validateDBName(StringData dbname) { @@ -656,8 +651,14 @@ Status DatabaseImpl::_finishDropCollection(OperationContext* opCtx, // We want to destroy the Collection object before telling the StorageEngine to destroy the // RecordStore. - _clearCollectionCache( - opCtx, fullns.toString(), "collection dropped", /*collectionGoingAway*/ true); + invariant(_name == fullns.db()); + auto it = _collections.find(fullns.toString()); + + if (it != _collections.end()) { + // Takes ownership of the collection + opCtx->recoveryUnit()->registerChange(new RemoveCollectionChange(this, it->second)); + _collections.erase(it); + } auto uuid = collection->uuid(); auto uuidString = uuid ? uuid.get().toString() : "no UUID"; @@ -666,23 +667,6 @@ Status DatabaseImpl::_finishDropCollection(OperationContext* opCtx, return _dbEntry->dropCollection(opCtx, fullns.toString()); } -void DatabaseImpl::_clearCollectionCache(OperationContext* opCtx, - StringData fullns, - const std::string& reason, - bool collectionGoingAway) { - verify(_name == nsToDatabaseSubstring(fullns)); - CollectionMap::const_iterator it = _collections.find(fullns.toString()); - - if (it == _collections.end()) - return; - - // Takes ownership of the collection - opCtx->recoveryUnit()->registerChange(new RemoveCollectionChange(this, it->second)); - - it->second->getCursorManager()->invalidateAll(opCtx, collectionGoingAway, reason); - _collections.erase(it); -} - Collection* DatabaseImpl::getCollection(OperationContext* opCtx, StringData ns) const { NamespaceString nss(ns); invariant(_name == nss.db()); @@ -729,16 +713,6 @@ Status DatabaseImpl::renameCollection(OperationContext* opCtx, return Status(ErrorCodes::NamespaceNotFound, "collection not found to rename"); } - string clearCacheReason = str::stream() << "renamed collection '" << fromNS << "' to '" << toNS - << "'"; - - // Notify the cursor manager that it should kill all the cursors in the source and target - // collections. This is currently necessary since the query layer is not prepared for cursors to - // survive collection renames. - auto sourceManager = collToRename->getCursorManager(); - invariant(sourceManager); - sourceManager->invalidateAll(opCtx, /*collectionGoingAway*/ true, clearCacheReason); - log() << "renameCollection: renaming collection " << collToRename->uuid()->toString() << " from " << fromNS << " to " << toNS; diff --git a/src/mongo/db/catalog/database_impl.h b/src/mongo/db/catalog/database_impl.h index 2130cdd9ce5..57af3693296 100644 --- a/src/mongo/db/catalog/database_impl.h +++ b/src/mongo/db/catalog/database_impl.h @@ -47,7 +47,7 @@ public: // closes files and other cleanup see below. - void close(OperationContext* opCtx, const std::string& reason) final; + void close(OperationContext* opCtx) final; const std::string& name() const final { return _name; @@ -187,16 +187,6 @@ private: const CollectionOptions& options); /** - * Deregisters and invalidates all cursors on collection 'fullns'. Callers must specify - * 'reason' for why the cache is being cleared. If 'collectionGoingAway' is false, - * unpinned cursors will not be killed. - */ - void _clearCollectionCache(OperationContext* opCtx, - StringData fullns, - const std::string& reason, - bool collectionGoingAway); - - /** * Completes a collection drop by removing all the indexes and removing the collection itself * from the storage engine. * diff --git a/src/mongo/db/catalog/index_catalog_impl.cpp b/src/mongo/db/catalog/index_catalog_impl.cpp index 08498dd3d8b..dabaee65ed0 100644 --- a/src/mongo/db/catalog/index_catalog_impl.cpp +++ b/src/mongo/db/catalog/index_catalog_impl.cpp @@ -742,11 +742,6 @@ void IndexCatalogImpl::dropAllIndexes(OperationContext* opCtx, BackgroundOperation::assertNoBgOpInProgForNs(_collection->ns().ns()); - // there may be pointers pointing at keys in the btree(s). kill them. - // TODO: can this can only clear cursors on this index? - _collection->getCursorManager()->invalidateAll( - opCtx, false, "all indexes on collection dropped"); - // make sure nothing in progress massert(17348, "cannot dropAllIndexes when index builds in progress", @@ -880,17 +875,6 @@ Status IndexCatalogImpl::_dropIndex(OperationContext* opCtx, IndexCatalogEntry* string indexName = entry->descriptor()->indexName(); string indexNamespace = entry->descriptor()->indexNamespace(); - // If any cursors could be using this index, invalidate them. Note that we do not use indexes - // until they are ready, so we do not need to invalidate anything if the index fails while it - // is being built. - // - // TODO only kill cursors that are actually using the index rather than everything on this - // collection. - if (entry->isReady(opCtx)) { - _collection->getCursorManager()->invalidateAll( - opCtx, false, str::stream() << "index '" << indexName << "' dropped"); - } - // --------- START REAL WORK ---------- audit::logDropIndex(&cc(), indexName, _collection->ns().ns()); @@ -1137,13 +1121,6 @@ const IndexDescriptor* IndexCatalogImpl::refreshEntry(OperationContext* opCtx, const std::string indexName = oldDesc->indexName(); invariant(_collection->getCatalogEntry()->isIndexReady(opCtx, indexName)); - // Notify other users of the IndexCatalog that we're about to invalidate 'oldDesc'. - const bool collectionGoingAway = false; - _collection->getCursorManager()->invalidateAll( - opCtx, - collectionGoingAway, - str::stream() << "definition of index '" << indexName << "' changed"); - // Delete the IndexCatalogEntry that owns this descriptor. After deletion, 'oldDesc' is // invalid and should not be dereferenced. auto oldEntry = _readyIndexes.release(oldDesc); diff --git a/src/mongo/db/catalog/index_catalog_impl.h b/src/mongo/db/catalog/index_catalog_impl.h index 36d9e8c41e4..57a59bd6e33 100644 --- a/src/mongo/db/catalog/index_catalog_impl.h +++ b/src/mongo/db/catalog/index_catalog_impl.h @@ -153,9 +153,7 @@ public: * * Use this method to notify the IndexCatalog that the spec for this index has changed. * - * It is invalid to dereference 'oldDesc' after calling this method. This method broadcasts - * an invalidateAll() on the cursor manager to notify other users of the IndexCatalog that - * this descriptor is now invalid. + * It is invalid to dereference 'oldDesc' after calling this method. */ const IndexDescriptor* refreshEntry(OperationContext* opCtx, const IndexDescriptor* oldDesc) override; diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp index ec988a1ce32..c7412752356 100644 --- a/src/mongo/db/clientcursor.cpp +++ b/src/mongo/db/clientcursor.cpp @@ -47,6 +47,7 @@ #include "mongo/db/commands.h" #include "mongo/db/commands/server_status.h" #include "mongo/db/commands/server_status_metric.h" +#include "mongo/db/cursor_manager.h" #include "mongo/db/cursor_server_params.h" #include "mongo/db/jsobj.h" #include "mongo/db/query/explain.h" @@ -79,7 +80,6 @@ long long ClientCursor::totalOpen() { } ClientCursor::ClientCursor(ClientCursorParams params, - CursorManager* cursorManager, CursorId cursorId, OperationContext* operationUsingCursor, Date_t now) @@ -89,7 +89,6 @@ ClientCursor::ClientCursor(ClientCursorParams params, _lsid(operationUsingCursor->getLogicalSessionId()), _txnNumber(operationUsingCursor->getTxnNumber()), _readConcernArgs(params.readConcernArgs), - _cursorManager(cursorManager), _originatingCommand(params.originatingCommandObj), _queryOptions(params.queryOptions), _lockPolicy(params.lockPolicy), @@ -98,7 +97,6 @@ ClientCursor::ClientCursor(ClientCursorParams params, _lastUseDate(now), _createdDate(now), _planSummary(Explain::getPlanSummary(_exec.get())) { - invariant(_cursorManager); invariant(_exec); invariant(_operationUsingCursor); @@ -131,7 +129,7 @@ void ClientCursor::dispose(OperationContext* opCtx) { return; } - _exec->dispose(opCtx, _cursorManager); + _exec->dispose(opCtx); _disposed = true; } @@ -163,7 +161,6 @@ ClientCursorPin::ClientCursorPin(OperationContext* opCtx, ClientCursor* cursor) : _opCtx(opCtx), _cursor(cursor) { invariant(_cursor); invariant(_cursor->_operationUsingCursor); - invariant(_cursor->_cursorManager); invariant(!_cursor->_disposed); // We keep track of the number of cursors currently pinned. The cursor can become unpinned @@ -216,24 +213,13 @@ 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, std::unique_ptr<ClientCursor, ClientCursor::Deleter>(_cursor)); - cursorStatsOpenPinned.decrement(); - } + // Unpin the cursor. This must be done by calling into the cursor manager, since the cursor + // manager must acquire the appropriate mutex in order to safely perform the unpin operation. + CursorManager::getGlobalCursorManager()->unpin( + _opCtx, std::unique_ptr<ClientCursor, ClientCursor::Deleter>(_cursor)); + cursorStatsOpenPinned.decrement(); _cursor = nullptr; } @@ -242,22 +228,15 @@ 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); - } + // - 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::getGlobalCursorManager()->deregisterCursor(_cursor); // Make sure the cursor is disposed and unpinned before being destroyed. _cursor->dispose(_opCtx); diff --git a/src/mongo/db/clientcursor.h b/src/mongo/db/clientcursor.h index 8e17f0e0bec..45eb548e495 100644 --- a/src/mongo/db/clientcursor.h +++ b/src/mongo/db/clientcursor.h @@ -44,7 +44,6 @@ namespace mongo { class Collection; -class CursorManager; class RecoveryUnit; /** @@ -305,7 +304,6 @@ private: * private. See cursor_manager.h for more details. */ ClientCursor(ClientCursorParams params, - CursorManager* cursorManager, CursorId cursorId, OperationContext* operationUsingCursor, Date_t now); @@ -357,8 +355,6 @@ private: const repl::ReadConcernArgs _readConcernArgs; - CursorManager* _cursorManager; - // Tracks whether dispose() has been called, to make sure it happens before destruction. It is // an error to use a ClientCursor once it has been disposed. bool _disposed = false; @@ -383,28 +379,17 @@ private: // The underlying query execution machinery. Must be non-null. std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> _exec; - // - // The following fields are used by the CursorManager and the ClientCursorPin. In most - // conditions, they can only be used while holding the CursorManager's mutex. Exceptions - // include: - // - If the ClientCursor is pinned, the CursorManager will never change '_isPinned' until - // asked to by the ClientCursorPin. - // - It is safe to read '_killed' while holding a collection lock, which must be held when - // interacting with a ClientCursorPin. - // - A ClientCursorPin can access these members after deregistering the cursor from the - // CursorManager, at which point it has sole ownership of the ClientCursor. - // - // While a cursor is being used by a client, it is marked as "pinned" by setting // _operationUsingCursor to the current OperationContext. // - // Cursors always come into existence in a pinned state (this must be non-null at construction). + // Cursors always come into existence in a pinned state ('_operationUsingCursor' must be + // non-null at construction). // // To write to this field one of the following must be true: // 1) You have a lock on the appropriate partition in CursorManager and the cursor is unpinned // (the field is null). - // 2) You own the cursor and the cursor manager it was associated with is gone (this can only - // happen in ClientCursorPin). In this case, nobody else will try to pin the cursor. + // 2) The cursor has already been deregistered from the CursorManager. In this case, nobody else + // will try to pin the cursor. // // To read this field one of the following must be true: // 1) You have a lock on the appropriate partition in CursorManager. @@ -431,9 +416,7 @@ private: * * A pin extends the lifetime of a ClientCursor object until the pin's release. Pinned ClientCursor * objects cannot not be killed due to inactivity, and cannot be immediately erased by user kill - * requests (though they can be marked as interrupted). When a CursorManager is destroyed (e.g. by - * a collection drop), ownership of any still-pinned ClientCursor objects is transferred to their - * managing ClientCursorPin objects. + * requests (though they can be marked as interrupted). * * Example usage: * { @@ -448,14 +431,10 @@ private: * // Use cursor. Pin automatically released on block exit. * } * - * Clients that wish to access ClientCursor objects owned by collection cursor managers must hold - * the collection lock while calling any pin method, including pin acquisition by the RAII - * constructor and pin release by the RAII destructor. This guards from a collection drop (which - * requires an exclusive lock on the collection) occurring concurrently with the pin request or - * unpin request. - * - * Clients that wish to access ClientCursor objects owned by the global cursor manager need not - * hold any locks; the global cursor manager can only be destroyed by a process exit. + * Callers need not hold any lock manager locks in order to obtain or release a client cursor pin. + * However, in order to use the ClientCursor itself, locks may need to be acquired. Whether locks + * are needed to use the ClientCursor can be determined by consulting the ClientCursor's lock + * policy. */ class ClientCursorPin { MONGO_DISALLOW_COPYING(ClientCursorPin); @@ -479,9 +458,8 @@ public: ~ClientCursorPin(); /** - * Releases the pin. It does not delete the underlying cursor unless ownership has passed - * to us after kill. Turns into a no-op if release() or deleteUnderlying() have already - * been called on this pin. + * Releases the pin without deleting the underlying cursor. Turns into a no-op if release() or + * deleteUnderlying() have already been called on this pin. */ void release(); diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index 0febcfc38c3..ad5b9c4d1fd 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -38,6 +38,7 @@ #include "mongo/db/commands.h" #include "mongo/db/commands/run_aggregate.h" #include "mongo/db/curop_failpoint_helpers.h" +#include "mongo/db/cursor_manager.h" #include "mongo/db/db_raii.h" #include "mongo/db/exec/working_set_common.h" #include "mongo/db/matcher/extensions_callback_real.h" diff --git a/src/mongo/db/commands/repair_cursor.cpp b/src/mongo/db/commands/repair_cursor.cpp index a02645209d0..b21d2c2e23c 100644 --- a/src/mongo/db/commands/repair_cursor.cpp +++ b/src/mongo/db/commands/repair_cursor.cpp @@ -38,6 +38,7 @@ #include "mongo/db/catalog/collection.h" #include "mongo/db/client.h" #include "mongo/db/commands.h" +#include "mongo/db/cursor_manager.h" #include "mongo/db/db_raii.h" #include "mongo/db/exec/multi_iterator.h" #include "mongo/db/namespace_string.h" diff --git a/src/mongo/db/commands/run_aggregate.cpp b/src/mongo/db/commands/run_aggregate.cpp index bafb689df8f..78463d65c63 100644 --- a/src/mongo/db/commands/run_aggregate.cpp +++ b/src/mongo/db/commands/run_aggregate.cpp @@ -40,6 +40,7 @@ #include "mongo/db/auth/authorization_session.h" #include "mongo/db/catalog/database.h" #include "mongo/db/curop.h" +#include "mongo/db/cursor_manager.h" #include "mongo/db/db_raii.h" #include "mongo/db/exec/change_stream_proxy.h" #include "mongo/db/exec/working_set_common.h" diff --git a/src/mongo/db/cursor_manager.cpp b/src/mongo/db/cursor_manager.cpp index 071983c65b4..6c8fcf0c29a 100644 --- a/src/mongo/db/cursor_manager.cpp +++ b/src/mongo/db/cursor_manager.cpp @@ -135,7 +135,7 @@ MONGO_INITIALIZER(GlobalCursorIdCache)(InitializerContext* context) { MONGO_INITIALIZER_WITH_PREREQUISITES(GlobalCursorManager, ("GlobalCursorIdCache")) (InitializerContext* context) { - globalCursorManager.reset(new CursorManager({})); + globalCursorManager.reset(new CursorManager()); return Status::OK(); } @@ -228,51 +228,7 @@ bool GlobalCursorIdCache::killCursor(OperationContext* opCtx, CursorId id, bool } std::size_t GlobalCursorIdCache::timeoutCursors(OperationContext* opCtx, Date_t now) { - size_t totalTimedOut = 0; - - // Time out the cursors from the global cursor manager. - totalTimedOut += globalCursorManager->timeoutCursors(opCtx, now); - - // Compute the set of collection names that we have to time out cursors for. - vector<NamespaceString> todo; - { - stdx::lock_guard<SimpleMutex> lk(_mutex); - for (auto&& entry : _idToNss) { - todo.push_back(entry.second); - } - } - - // For each collection, time out its cursors under the collection lock (to prevent the - // collection from going away during the erase). - for (const auto& nsTodo : todo) { - // We need to be careful to not use an AutoGet* helper, since we only need the lock to - // protect potential access to the Collection's CursorManager, and those helpers may - // do things we don't want here, like check the shard version or throw an exception if this - // namespace has since turned into a view. Using Database::getCollection() will simply - // return nullptr if the collection has since turned into a view. In this case, the cursors - // will already have been cleaned up when the collection was dropped, so there will be none - // left to time out. - // - // Additionally, we need to use the UninterruptibleLockGuard to ensure the lock acquisition - // will not throw due to an interrupt. This method can be called from a background thread so - // we do not want to throw any exceptions. - UninterruptibleLockGuard noInterrupt(opCtx->lockState()); - AutoGetDb dbLock(opCtx, nsTodo.db(), MODE_IS); - Lock::CollectionLock collLock(opCtx->lockState(), nsTodo.ns(), MODE_IS); - if (!dbLock.getDb()) { - continue; - } - - Collection* const collection = dbLock.getDb()->getCollection(opCtx, nsTodo); - if (!collection) { - // The 'nsTodo' collection has been dropped since we held _mutex. We can safely skip it. - continue; - } - - totalTimedOut += collection->getCursorManager()->timeoutCursors(opCtx, now); - } - - return totalTimedOut; + return globalCursorManager->timeoutCursors(opCtx, now); } } // namespace @@ -280,31 +236,6 @@ std::size_t GlobalCursorIdCache::timeoutCursors(OperationContext* opCtx, Date_t template <typename Visitor> void GlobalCursorIdCache::visitAllCursorManagers(OperationContext* opCtx, Visitor* visitor) { (*visitor)(*globalCursorManager); - - // Compute the set of collection names that we have to get sessions for - vector<NamespaceString> namespaces; - { - stdx::lock_guard<SimpleMutex> lk(_mutex); - for (auto&& entry : _idToNss) { - namespaces.push_back(entry.second); - } - } - - // For each collection, get its sessions under the collection lock (to prevent the - // collection from going away during the erase). - for (auto&& ns : namespaces) { - AutoGetCollection ctx(opCtx, ns, MODE_IS); - if (!ctx.getDb()) { - continue; - } - - Collection* collection = ctx.getCollection(); - if (!collection) { - continue; - } - - (*visitor)(*(collection->getCursorManager())); - } } // --- @@ -366,32 +297,14 @@ Status CursorManager::withCursorManager(OperationContext* opCtx, CursorId id, const NamespaceString& nss, stdx::function<Status(CursorManager*)> callback) { - boost::optional<AutoGetCollectionForReadCommand> readLock; - CursorManager* cursorManager = nullptr; - - if (CursorManager::isGloballyManagedCursor(id)) { - cursorManager = CursorManager::getGlobalCursorManager(); - } else { - readLock.emplace(opCtx, nss); - Collection* collection = readLock->getCollection(); - if (!collection) { - return {ErrorCodes::CursorNotFound, - str::stream() << "collection does not exist: " << nss.ns()}; - } - cursorManager = collection->getCursorManager(); - } - invariant(cursorManager); - + auto cursorManager = CursorManager::getGlobalCursorManager(); return callback(cursorManager); } // -------------------------- -CursorManager::CursorManager(NamespaceString nss) - : _nss(std::move(nss)), - _collectionCacheRuntimeId(_nss.isEmpty() ? 0 - : globalCursorIdCache->registerCursorManager(_nss)), - _random(stdx::make_unique<PseudoRandom>(globalCursorIdCache->nextSeed())), +CursorManager::CursorManager() + : _random(stdx::make_unique<PseudoRandom>(globalCursorIdCache->nextSeed())), _cursorMap(stdx::make_unique<Partitioned<stdx::unordered_map<CursorId, ClientCursor*>>>()) {} CursorManager::~CursorManager() { @@ -652,7 +565,7 @@ ClientCursorPin CursorManager::registerCursor(OperationContext* opCtx, stdx::lock_guard<SimpleMutex> lock(_registrationLock); CursorId cursorId = allocateCursorId_inlock(); std::unique_ptr<ClientCursor, ClientCursor::Deleter> clientCursor( - new ClientCursor(std::move(cursorParams), this, cursorId, opCtx, now)); + new ClientCursor(std::move(cursorParams), cursorId, opCtx, now)); // Register this cursor for lookup by transaction. if (opCtx->getLogicalSessionId() && opCtx->getTxnNumber()) { diff --git a/src/mongo/db/cursor_manager.h b/src/mongo/db/cursor_manager.h index b1b8beb1fe6..d0e89e1e6de 100644 --- a/src/mongo/db/cursor_manager.h +++ b/src/mongo/db/cursor_manager.h @@ -57,68 +57,92 @@ class PlanExecutor; * ClientCursors. It is also responsible for allocating the cursor ids that are passed back to * clients. * - * There is a CursorManager per-collection and a global CursorManager. The global CursorManager owns - * cursors whose lifetime is not tied to that of the collection and which do not need to receive - * notifications about writes for a particular collection. In contrast, cursors owned by a - * collection's CursorManager, unless pinned, are destroyed when the collection is destroyed. - * - * Callers must hold the collection lock in at least MODE_IS in order to access a collection's - * CursorManager, which guards against the CursorManager being concurrently deleted due to a - * catalog-level operation such as a collection drop. No locks are required to access the global - * cursor manager. - * - * The CursorManager is internally synchronized; operations on a given collection may call methods - * concurrently on that collection's CursorManager. + * There is a process-global CursorManager on every mongod which is responsible for managing all + * open cursors on the node. No lock manager locks are required to access this global cursor + * manager. The CursorManager is internally synchronized, and unless otherwise noted its public + * methods are thread-safe. For scalability in circumstances where many threads may be concurrently + * accessing the CursorManager (i.e. a workload which runs many concurrent queries), the cursor + * manager's underlying data structure is partitioned. Each partition is protected by its own latch. * * See clientcursor.h for more information. */ class CursorManager { public: /** + * Returns a pointer to the process-global cursor manager. + */ + static CursorManager* getGlobalCursorManager(); + + /** * Appends the sessions that have open cursors on the global cursor manager and across * all collection-level cursor managers to the given set of lsids. */ static void appendAllActiveSessions(OperationContext* opCtx, LogicalSessionIdSet* lsids); /** - * Returns a list of GenericCursors for all idle cursors on the global cursor manager and across - * all collection-level cursor managers. Does not include currently pinned cursors. - * 'userMode': If auth is on, calling with userMode as kExcludeOthers will cause this function - * to only return cursors owned by the caller. If auth is off, this argument does not matter. + * Returns a list of GenericCursors for all idle cursors on global cursor manager. Does not + * include currently pinned cursors. 'userMode': If auth is on, calling with userMode as + * kExcludeOthers will cause this function to only return cursors owned by the caller. If auth + * is off, this argument does not matter. + * + * TODO SERVER-37454: This method should become non-static now that there are no more + * per-collection cursor managers. */ static std::vector<GenericCursor> getIdleCursors( OperationContext* opCtx, MongoProcessInterface::CurrentOpUserMode userMode); /** - * Kills cursors with matching logical sessions. Returns a pair with the overall - * Status of the operation and the number of cursors successfully killed. + * Kills cursors with matching logical sessions. Returns a pair with the overall Status of the + * operation and the number of cursors successfully killed. */ static std::pair<Status, int> killCursorsWithMatchingSessions( OperationContext* opCtx, const SessionKiller::Matcher& matcher); - CursorManager(NamespaceString nss); - /** - * Destroys the CursorManager. All cursors must be cleaned up via invalidateAll() before - * destruction. + * This method is deprecated. Do not add new call sites. + * + * TODO SERVER-37452: Delete this method. */ - ~CursorManager(); + static bool isGloballyManagedCursor(CursorId cursorId) { + // The first two bits are 01 for globally managed cursors, and 00 for cursors owned by a + // collection. The leading bit is always 0 so that CursorIds do not appear as negative. + const long long mask = static_cast<long long>(0b11) << 62; + return (cursorId & mask) == (static_cast<long long>(0b01) << 62); + } + + static int killCursorGlobalIfAuthorized(OperationContext* opCtx, int n, const char* ids); + + static bool killCursorGlobalIfAuthorized(OperationContext* opCtx, CursorId id); + + static bool killCursorGlobal(OperationContext* opCtx, CursorId id); /** - * Kills all managed ClientCursors. Callers must have exclusive access to the collection (i.e. - * must have the collection, database, or global resource locked in MODE_X). + * Deletes inactive cursors from the global cursor manager. Returns the number of cursors that + * were timed out. * - * Must be called before the CursorManger is destroyed. - * - * 'collectionGoingAway' indicates whether the Collection instance is being deleted. This could - * be because the db is being closed, or the collection/db is being dropped. + * TODO SERVER-37454: This method can become non-static now that there are no per-collection + * cursor managers. + */ + static std::size_t timeoutCursorsGlobal(OperationContext* opCtx, Date_t now); + + /** + * This method is deprecated. Do not add new call sites. * - * For any cursors that are in use by an active operation, ownership is transferred to the - * respective cursor pin objects. + * TODO SERVER-39065: Delete this method. + */ + static Status withCursorManager(OperationContext* opCtx, + CursorId id, + const NamespaceString& nss, + stdx::function<Status(CursorManager*)> callback); + + CursorManager(); + + ~CursorManager(); + + /** + * This method is deprecated. Do not add new call sites. * - * The 'reason' is the motivation for invalidating all cursors. This will be used for error - * reporting and logging when an operation finds that the cursor it was operating on has been - * killed. + * TODO SERVER-38288: Delete this method. */ void invalidateAll(OperationContext* opCtx, bool collectionGoingAway, @@ -196,40 +220,6 @@ public: */ std::size_t numCursors() const; - static CursorManager* getGlobalCursorManager(); - - /** - * Returns true if this CursorId would be registered with the global CursorManager. Note that if - * this method returns true it does not imply the cursor exists. - */ - static bool isGloballyManagedCursor(CursorId cursorId) { - // The first two bits are 01 for globally managed cursors, and 00 for cursors owned by a - // collection. The leading bit is always 0 so that CursorIds do not appear as negative. - const long long mask = static_cast<long long>(0b11) << 62; - return (cursorId & mask) == (static_cast<long long>(0b01) << 62); - } - - static int killCursorGlobalIfAuthorized(OperationContext* opCtx, int n, const char* ids); - - static bool killCursorGlobalIfAuthorized(OperationContext* opCtx, CursorId id); - - static bool killCursorGlobal(OperationContext* opCtx, CursorId id); - - /** - * Deletes inactive cursors from the global cursor manager and from all per-collection cursor - * managers. Returns the number of cursors that were timed out. - */ - static std::size_t timeoutCursorsGlobal(OperationContext* opCtx, Date_t now); - - /** - * Locate the correct cursor manager for a given cursorId and execute the provided callback. - * Returns ErrorCodes::CursorNotFound if cursorId does not exist. - */ - static Status withCursorManager(OperationContext* opCtx, - CursorId id, - const NamespaceString& nss, - stdx::function<Status(CursorManager*)> callback); - private: static constexpr int kNumPartitions = 16; friend class ClientCursorPin; @@ -255,8 +245,10 @@ private: } // No locks are needed to consult these data members. + // + // TODO SERVER-37452: Delete these data members. const NamespaceString _nss; - const uint32_t _collectionCacheRuntimeId; + const uint32_t _collectionCacheRuntimeId = 0; // A CursorManager holds a pointer to all open ClientCursors. ClientCursors are owned by the // CursorManager, except when they are in use by a ClientCursorPin. When in use by a pin, an diff --git a/src/mongo/db/pipeline/document_source_cursor.cpp b/src/mongo/db/pipeline/document_source_cursor.cpp index b019bbf8e35..978f62e4f2b 100644 --- a/src/mongo/db/pipeline/document_source_cursor.cpp +++ b/src/mongo/db/pipeline/document_source_cursor.cpp @@ -140,7 +140,7 @@ void DocumentSourceCursor::loadBatch() { // still held if '_exec' did not end in an error. If '_exec' encountered an error during a // yield, the locks might be yielded. if (state != PlanExecutor::DEAD && state != PlanExecutor::FAILURE) { - cleanupExecutor(autoColl); + cleanupExecutor(); } } @@ -266,33 +266,7 @@ void DocumentSourceCursor::doDispose() { void DocumentSourceCursor::cleanupExecutor() { invariant(_exec); - auto* opCtx = pExpCtx->opCtx; - // We need to be careful to not use AutoGetCollection here, since we only need the lock to - // protect potential access to the Collection's CursorManager, and AutoGetCollection may throw - // if this namespace has since turned into a view. Using Database::getCollection() will simply - // return nullptr if the collection has since turned into a view. In this case, '_exec' will - // already have been marked as killed when the collection was dropped, and we won't need to - // access the CursorManager to properly dispose of it. - UninterruptibleLockGuard noInterrupt(opCtx->lockState()); - auto lockMode = getLockModeForQuery(opCtx); - AutoGetDb dbLock(opCtx, _exec->nss().db(), lockMode); - Lock::CollectionLock collLock(opCtx->lockState(), _exec->nss().ns(), lockMode); - auto collection = dbLock.getDb() ? dbLock.getDb()->getCollection(opCtx, _exec->nss()) : nullptr; - auto cursorManager = collection ? collection->getCursorManager() : nullptr; - _exec->dispose(opCtx, cursorManager); - - // Not freeing _exec if we're in explain mode since it will be used in serialize() to gather - // execution stats. - if (!pExpCtx->explain) { - _exec.reset(); - } -} - -void DocumentSourceCursor::cleanupExecutor(const AutoGetCollectionForRead& readLock) { - invariant(_exec); - auto cursorManager = - readLock.getCollection() ? readLock.getCollection()->getCursorManager() : nullptr; - _exec->dispose(pExpCtx->opCtx, cursorManager); + _exec->dispose(pExpCtx->opCtx); // Not freeing _exec if we're in explain mode since it will be used in serialize() to gather // execution stats. diff --git a/src/mongo/db/pipeline/document_source_cursor.h b/src/mongo/db/pipeline/document_source_cursor.h index d15c23c2849..90f3c6d4f1c 100644 --- a/src/mongo/db/pipeline/document_source_cursor.h +++ b/src/mongo/db/pipeline/document_source_cursor.h @@ -189,11 +189,6 @@ private: void cleanupExecutor(); /** - * Destroys and de-registers '_exec'. '_exec' must be non-null. - */ - void cleanupExecutor(const AutoGetCollectionForRead& readLock); - - /** * Reads a batch of data from '_exec'. Subclasses can specify custom behavior to be performed on * each document by overloading transformBSONObjToDocument(). */ diff --git a/src/mongo/db/pipeline/process_interface_standalone.cpp b/src/mongo/db/pipeline/process_interface_standalone.cpp index 4c247333272..f7736cd41b1 100644 --- a/src/mongo/db/pipeline/process_interface_standalone.cpp +++ b/src/mongo/db/pipeline/process_interface_standalone.cpp @@ -41,6 +41,7 @@ #include "mongo/db/catalog/uuid_catalog.h" #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/curop.h" +#include "mongo/db/cursor_manager.h" #include "mongo/db/db_raii.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/pipeline/document_source_cursor.h" diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp index 765e79a7183..d6e4ce7a1e0 100644 --- a/src/mongo/db/query/find.cpp +++ b/src/mongo/db/query/find.cpp @@ -42,6 +42,7 @@ #include "mongo/db/commands.h" #include "mongo/db/curop.h" #include "mongo/db/curop_failpoint_helpers.h" +#include "mongo/db/cursor_manager.h" #include "mongo/db/db_raii.h" #include "mongo/db/exec/filter.h" #include "mongo/db/exec/working_set_common.h" diff --git a/src/mongo/db/query/plan_executor.h b/src/mongo/db/query/plan_executor.h index 6c8d5defe74..3ecee6edb5a 100644 --- a/src/mongo/db/query/plan_executor.h +++ b/src/mongo/db/query/plan_executor.h @@ -44,7 +44,6 @@ class BSONObj; class CappedInsertNotifier; struct CappedInsertNotifierData; class Collection; -class CursorManager; class PlanExecutor; class PlanStage; class PlanYieldPolicy; @@ -164,8 +163,7 @@ public: */ Deleter() = default; - inline Deleter(OperationContext* opCtx, CursorManager* cursorManager) - : _opCtx(opCtx), _cursorManager(cursorManager) {} + inline Deleter(OperationContext* opCtx) : _opCtx(opCtx) {} /** * If an owner of a std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> wants to assume @@ -185,7 +183,7 @@ public: // It is illegal to invoke operator() on a default constructed Deleter. invariant(_opCtx); if (!_dismissed) { - execPtr->dispose(_opCtx, _cursorManager); + execPtr->dispose(_opCtx); } delete execPtr; } catch (...) { @@ -196,7 +194,6 @@ public: private: OperationContext* _opCtx = nullptr; - CursorManager* _cursorManager = nullptr; bool _dismissed = false; }; @@ -404,8 +401,7 @@ public: /** * Cleans up any state associated with this PlanExecutor. Must be called before deleting this - * PlanExecutor. It is illegal to use a PlanExecutor after calling dispose(). 'cursorManager' - * may be null. + * PlanExecutor. It is illegal to use a PlanExecutor after calling dispose(). * * There are multiple cleanup scenarios: * - This PlanExecutor will only ever use one OperationContext. In this case the @@ -415,7 +411,7 @@ public: * is the owner's responsibility to call dispose() with a valid OperationContext before * deleting the PlanExecutor. */ - virtual void dispose(OperationContext* opCtx, CursorManager* cursorManager) = 0; + virtual void dispose(OperationContext* opCtx) = 0; /** * Helper method to aid in displaying an ExecState for debug or other recreational purposes. diff --git a/src/mongo/db/query/plan_executor_impl.cpp b/src/mongo/db/query/plan_executor_impl.cpp index 53d00097fd1..2b5aad16259 100644 --- a/src/mongo/db/query/plan_executor_impl.cpp +++ b/src/mongo/db/query/plan_executor_impl.cpp @@ -1,4 +1,3 @@ - /** * Copyright (C) 2018-present MongoDB, Inc. * @@ -204,7 +203,7 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PlanExecutorImpl::ma collection, std::move(nss), yieldPolicy); - PlanExecutor::Deleter planDeleter(opCtx, collection ? collection->getCursorManager() : nullptr); + PlanExecutor::Deleter planDeleter(opCtx); std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> exec(execImpl, std::move(planDeleter)); // Perform plan selection, if necessary. @@ -654,7 +653,7 @@ void PlanExecutorImpl::markAsKilled(Status killStatus) { } } -void PlanExecutorImpl::dispose(OperationContext* opCtx, CursorManager* cursorManager) { +void PlanExecutorImpl::dispose(OperationContext* opCtx) { if (_currentState == kDisposed) { return; } diff --git a/src/mongo/db/query/plan_executor_impl.h b/src/mongo/db/query/plan_executor_impl.h index 79a13f1086d..1fc8e52f94d 100644 --- a/src/mongo/db/query/plan_executor_impl.h +++ b/src/mongo/db/query/plan_executor_impl.h @@ -71,7 +71,7 @@ public: bool isEOF() final; Status executePlan() final; void markAsKilled(Status killStatus) final; - void dispose(OperationContext* opCtx, CursorManager* cursorManager) final; + void dispose(OperationContext* opCtx) final; void enqueue(const BSONObj& obj) final; BSONObjSet getOutputSorts() const final; bool isMarkedAsKilled() const final; diff --git a/src/mongo/db/repair_database.cpp b/src/mongo/db/repair_database.cpp index 56f7dd433d2..2e4007b90e1 100644 --- a/src/mongo/db/repair_database.cpp +++ b/src/mongo/db/repair_database.cpp @@ -282,7 +282,7 @@ Status repairDatabase(OperationContext* opCtx, StorageEngine* engine, const std: // Close the db and invalidate all current users and caches. auto databaseHolder = DatabaseHolder::get(opCtx); - databaseHolder->close(opCtx, dbName, "database closed for repair"); + databaseHolder->close(opCtx, dbName); ON_BLOCK_EXIT([databaseHolder, &dbName, &opCtx] { try { // Ensure that we don't trigger an exception when attempting to take locks. diff --git a/src/mongo/db/service_context_d_test_fixture.cpp b/src/mongo/db/service_context_d_test_fixture.cpp index 6a51301cdeb..ce78b540797 100644 --- a/src/mongo/db/service_context_d_test_fixture.cpp +++ b/src/mongo/db/service_context_d_test_fixture.cpp @@ -98,7 +98,7 @@ ServiceContextMongoDTest::~ServiceContextMongoDTest() { auto opCtx = getClient()->makeOperationContext(); Lock::GlobalLock glk(opCtx.get(), MODE_X); auto databaseHolder = DatabaseHolder::get(opCtx.get()); - databaseHolder->closeAll(opCtx.get(), "all databases dropped"); + databaseHolder->closeAll(opCtx.get()); } IndexBuildsCoordinator::get(getServiceContext())->shutdown(); diff --git a/src/mongo/dbtests/cursor_manager_test.cpp b/src/mongo/dbtests/cursor_manager_test.cpp index 08c072dcde0..dd734401e9d 100644 --- a/src/mongo/dbtests/cursor_manager_test.cpp +++ b/src/mongo/dbtests/cursor_manager_test.cpp @@ -50,6 +50,7 @@ #include "mongo/dbtests/dbtests.h" #include "mongo/unittest/unittest.h" #include "mongo/util/clock_source_mock.h" +#include "mongo/util/scopeguard.h" namespace mongo { namespace { @@ -91,7 +92,7 @@ public: } virtual ~CursorManagerTest() { - _cursorManager.invalidateAll(_opCtx.get(), true, "end of test"); + useCursorManager()->invalidateAll(_opCtx.get(), true, "end of test"); } std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> makeFakePlanExecutor() { @@ -119,7 +120,7 @@ public: } ClientCursorPin makeCursor(OperationContext* opCtx) { - return _cursorManager.registerCursor(opCtx, makeParams(opCtx)); + return useCursorManager()->registerCursor(opCtx, makeParams(opCtx)); } ClockSourceMock* useClock() { @@ -127,7 +128,7 @@ public: } CursorManager* useCursorManager() { - return &_cursorManager; + return CursorManager::getGlobalCursorManager(); } protected: @@ -136,7 +137,6 @@ protected: private: ClockSourceMock* _clock; - CursorManager _cursorManager{NamespaceString{}}; }; class CursorManagerTestCustomOpCtx : public CursorManagerTest { @@ -240,6 +240,7 @@ TEST_F(CursorManagerTest, InvalidatePinnedCursor) { repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern), BSONObj(), ClientCursorParams::LockPolicy::kLocksInternally}); + auto cursorFreer = makeGuard([&] { cursorPin.deleteUnderlying(); }); // If the cursor is pinned, it sticks around, even after invalidation. ASSERT_EQUALS(1U, cursorManager->numCursors()); @@ -254,7 +255,6 @@ TEST_F(CursorManagerTest, InvalidatePinnedCursor) { const Status status = WorkingSetCommon::getMemberObjectStatus(objOut); ASSERT(status.reason().find(invalidateReason) != std::string::npos); - cursorPin.release(); ASSERT_EQUALS(0U, cursorManager->numCursors()); } @@ -417,6 +417,7 @@ TEST_F(CursorManagerTest, InactiveKilledCursorsThatAreStillPinnedShouldNotTimeou repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern), BSONObj(), ClientCursorParams::LockPolicy::kLocksInternally}); + auto cursorFreer = makeGuard([&] { cursorPin.deleteUnderlying(); }); const bool collectionGoingAway = false; cursorManager->invalidateAll( _opCtx.get(), collectionGoingAway, "KilledCursorsShouldTimeoutTest"); diff --git a/src/mongo/dbtests/querytests.cpp b/src/mongo/dbtests/querytests.cpp index 5c7441c13fc..1c74a747090 100644 --- a/src/mongo/dbtests/querytests.cpp +++ b/src/mongo/dbtests/querytests.cpp @@ -37,6 +37,7 @@ #include "mongo/db/catalog/collection.h" #include "mongo/db/client.h" #include "mongo/db/clientcursor.h" +#include "mongo/db/cursor_manager.h" #include "mongo/db/db_raii.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/dbhelpers.h" @@ -1261,11 +1262,7 @@ public: } size_t numCursorsOpen() { - AutoGetCollectionForReadCommand ctx(&_opCtx, NamespaceString(_ns)); - Collection* collection = ctx.getCollection(); - if (!collection) - return 0; - return collection->getCursorManager()->numCursors(); + return CursorManager::getGlobalCursorManager()->numCursors(); } const char* ns() { diff --git a/src/mongo/embedded/embedded.cpp b/src/mongo/embedded/embedded.cpp index c190620a0ae..712dac1b8de 100644 --- a/src/mongo/embedded/embedded.cpp +++ b/src/mongo/embedded/embedded.cpp @@ -160,7 +160,7 @@ void shutdown(ServiceContext* srvContext) { UninterruptibleLockGuard noInterrupt(shutdownOpCtx->lockState()); Lock::GlobalLock lk(shutdownOpCtx.get(), MODE_X); auto databaseHolder = DatabaseHolder::get(shutdownOpCtx.get()); - databaseHolder->closeAll(shutdownOpCtx.get(), "shutdown"); + databaseHolder->closeAll(shutdownOpCtx.get()); LogicalSessionCache::set(serviceContext, nullptr); |