diff options
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/clientcursor.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/clientcursor.h | 13 | ||||
-rw-r--r-- | src/mongo/db/cursor_manager.cpp | 69 | ||||
-rw-r--r-- | src/mongo/db/cursor_manager.h | 17 | ||||
-rw-r--r-- | src/mongo/db/db_raii.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/db_raii.h | 43 | ||||
-rw-r--r-- | src/mongo/db/logical_session_id.h | 1 | ||||
-rw-r--r-- | src/mongo/db/query/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/query/query_test_service_context.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/query/query_test_service_context.h | 5 |
11 files changed, 167 insertions, 4 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 5d2149b9e55..c7649153f78 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -613,6 +613,7 @@ env.Library( ], LIBDEPS=[ "$BUILD_DIR/mongo/base", + "$BUILD_DIR/mongo/db/logical_session_id", "$BUILD_DIR/mongo/util/background_job", "query/query", "background", diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp index b6a686ba717..889d9961607 100644 --- a/src/mongo/db/clientcursor.cpp +++ b/src/mongo/db/clientcursor.cpp @@ -77,13 +77,15 @@ long long ClientCursor::totalOpen() { return cursorStatsOpen.get(); } -ClientCursor::ClientCursor(ClientCursorParams&& params, +ClientCursor::ClientCursor(ClientCursorParams params, CursorManager* cursorManager, CursorId cursorId, + boost::optional<LogicalSessionId> lsid, Date_t now) : _cursorid(cursorId), _nss(std::move(params.nss)), _authenticatedUsers(std::move(params.authenticatedUsers)), + _lsid(std::move(lsid)), _isReadCommitted(params.isReadCommitted), _cursorManager(cursorManager), _originatingCommand(params.originatingCommandObj), diff --git a/src/mongo/db/clientcursor.h b/src/mongo/db/clientcursor.h index d2f216b01e1..32fb018a8e1 100644 --- a/src/mongo/db/clientcursor.h +++ b/src/mongo/db/clientcursor.h @@ -28,10 +28,13 @@ #pragma once +#include <boost/optional.hpp> + #include "mongo/client/dbclientinterface.h" #include "mongo/db/auth/user_name.h" #include "mongo/db/cursor_id.h" #include "mongo/db/jsobj.h" +#include "mongo/db/logical_session_id.h" #include "mongo/db/query/plan_executor.h" #include "mongo/db/record_id.h" #include "mongo/stdx/functional.h" @@ -108,6 +111,10 @@ public: return makeUserNameIterator(_authenticatedUsers.begin(), _authenticatedUsers.end()); } + boost::optional<LogicalSessionId> getSessionId() const { + return _lsid; + } + bool isReadCommitted() const { return _isReadCommitted; } @@ -218,9 +225,10 @@ private: * Constructs a ClientCursor. Since cursors must come into being registered and pinned, this is * private. See cursor_manager.h for more details. */ - ClientCursor(ClientCursorParams&& params, + ClientCursor(ClientCursorParams params, CursorManager* cursorManager, CursorId cursorId, + boost::optional<LogicalSessionId> lsid, Date_t now); /** @@ -257,6 +265,9 @@ private: // The set of authenticated users when this cursor was created. std::vector<UserName> _authenticatedUsers; + // A logical session id for this cursor, if it is running inside of a session. + const boost::optional<LogicalSessionId> _lsid; + const bool _isReadCommitted = false; CursorManager* _cursorManager; diff --git a/src/mongo/db/cursor_manager.cpp b/src/mongo/db/cursor_manager.cpp index f1bdd8a9442..a2e9687f5b1 100644 --- a/src/mongo/db/cursor_manager.cpp +++ b/src/mongo/db/cursor_manager.cpp @@ -101,6 +101,8 @@ public: std::size_t timeoutCursors(OperationContext* opCtx, Date_t now); + void appendActiveSessions(OperationContext* opCtx, LogicalSessionIdSet* lsids); + int64_t nextSeed(); private: @@ -267,12 +269,47 @@ std::size_t GlobalCursorIdCache::timeoutCursors(OperationContext* opCtx, Date_t } } // namespace +void GlobalCursorIdCache::appendActiveSessions(OperationContext* opCtx, + LogicalSessionIdSet* lsids) { + // Get active session ids from the global cursor manager + globalCursorManager->appendActiveSessions(lsids); + + // 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) { + AutoGetCollectionOrView ctx(opCtx, NamespaceString(ns), MODE_IS); + if (!ctx.getDb()) { + continue; + } + + Collection* collection = ctx.getCollection(); + if (!collection) { + continue; + } + + collection->getCursorManager()->appendActiveSessions(lsids); + } +} + // --- CursorManager* CursorManager::getGlobalCursorManager() { return globalCursorManager.get(); } +void CursorManager::appendAllActiveSessions(OperationContext* opCtx, LogicalSessionIdSet* lsids) { + globalCursorIdCache->appendActiveSessions(opCtx, lsids); +} + std::size_t CursorManager::timeoutCursorsGlobal(OperationContext* opCtx, Date_t now) { return globalCursorIdCache->timeoutCursors(opCtx, now); } @@ -482,6 +519,34 @@ void CursorManager::getCursorIds(std::set<CursorId>* openCursors) const { } } +void CursorManager::appendActiveSessions(LogicalSessionIdSet* lsids) const { + auto allPartitions = _cursorMap->lockAllPartitions(); + for (auto&& partition : allPartitions) { + for (auto&& entry : partition) { + auto cursor = entry.second; + if (auto id = cursor->getSessionId()) { + lsids->insert(id.value()); + } + } + } +} + +stdx::unordered_set<CursorId> CursorManager::getCursorsForSession(LogicalSessionId lsid) const { + stdx::unordered_set<CursorId> cursors; + + auto allPartitions = _cursorMap->lockAllPartitions(); + for (auto&& partition : allPartitions) { + for (auto&& entry : partition) { + auto cursor = entry.second; + if (cursor->getSessionId() == lsid) { + cursors.insert(cursor->cursorid()); + } + } + } + + return cursors; +} + size_t CursorManager::numCursors() const { return _cursorMap->size(); } @@ -526,8 +591,8 @@ ClientCursorPin CursorManager::registerCursor(OperationContext* opCtx, // we don't insert two cursors with the same cursor id. stdx::lock_guard<SimpleMutex> lock(_registrationLock); CursorId cursorId = allocateCursorId_inlock(); - std::unique_ptr<ClientCursor, ClientCursor::Deleter> clientCursor( - new ClientCursor(std::move(cursorParams), this, cursorId, now)); + std::unique_ptr<ClientCursor, ClientCursor::Deleter> clientCursor(new ClientCursor( + std::move(cursorParams), this, cursorId, opCtx->getLogicalSessionId(), now)); // Transfer ownership of the cursor to '_cursorMap'. auto partition = _cursorMap->lockOnePartition(cursorId); diff --git a/src/mongo/db/cursor_manager.h b/src/mongo/db/cursor_manager.h index 40408c48830..0b243e21996 100644 --- a/src/mongo/db/cursor_manager.h +++ b/src/mongo/db/cursor_manager.h @@ -36,6 +36,7 @@ #include "mongo/db/record_id.h" #include "mongo/platform/unordered_map.h" #include "mongo/platform/unordered_set.h" +#include "mongo/stdx/unordered_set.h" #include "mongo/util/concurrency/mutex.h" #include "mongo/util/duration.h" @@ -78,6 +79,12 @@ public: static constexpr Minutes kDefaultCursorTimeoutMinutes{10}; using RegistrationToken = Partitioned<unordered_set<PlanExecutor*>>::PartitionId; + /** + * 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); + CursorManager(NamespaceString nss); /** @@ -159,6 +166,16 @@ public: void getCursorIds(std::set<CursorId>* openCursors) const; /** + * Appends sessions that have open cursors in this cursor manager to the given set of lsids. + */ + void appendActiveSessions(LogicalSessionIdSet* lsids) const; + + /* + * Returns a list of all open cursors for the given session. + */ + stdx::unordered_set<CursorId> getCursorsForSession(LogicalSessionId lsid) const; + + /** * Returns the number of ClientCursors currently registered. Excludes any registered bare * PlanExecutors. */ diff --git a/src/mongo/db/db_raii.cpp b/src/mongo/db/db_raii.cpp index 478047eb0cc..bff855fcc5b 100644 --- a/src/mongo/db/db_raii.cpp +++ b/src/mongo/db/db_raii.cpp @@ -72,6 +72,14 @@ AutoGetCollection::AutoGetCollection(OperationContext* opCtx, } } +AutoGetCollectionOrView::AutoGetCollectionOrView(OperationContext* opCtx, + const NamespaceString& nss, + LockMode modeAll) + : _autoColl(opCtx, nss, modeAll, modeAll, AutoGetCollection::ViewMode::kViewsPermitted), + _view(_autoColl.getDb() && !_autoColl.getCollection() + ? _autoColl.getDb()->getViewCatalog()->lookup(opCtx, nss.ns()) + : nullptr) {} + AutoGetOrCreateDb::AutoGetOrCreateDb(OperationContext* opCtx, StringData ns, LockMode mode) : _dbLock(opCtx, ns, mode), _db(dbHolder().get(opCtx, ns)) { invariant(mode == MODE_IX || mode == MODE_X); diff --git a/src/mongo/db/db_raii.h b/src/mongo/db/db_raii.h index 753909e3c6a..641b64e7988 100644 --- a/src/mongo/db/db_raii.h +++ b/src/mongo/db/db_raii.h @@ -128,12 +128,55 @@ private: const Lock::CollectionLock _collLock; Collection* const _coll; + friend class AutoGetCollectionOrView; friend class AutoGetCollectionForRead; friend class AutoGetCollectionForReadCommand; friend class AutoGetCollectionOrViewForReadCommand; }; /** + * RAII-style class which acquires the appropriate hierarchy of locks for a collection or + * view. The pointer to a view definition is nullptr if it does not exist. + * + * Use this when you have not yet determined if the namespace is a view or a collection. + * For example, you can use this to access a namespace's CursorManager. + * + * It is guaranteed that locks will be released when this object goes out of scope, therefore + * the view returned by this class should not be retained. + */ +class AutoGetCollectionOrView { + MONGO_DISALLOW_COPYING(AutoGetCollectionOrView); + +public: + AutoGetCollectionOrView(OperationContext* opCtx, const NamespaceString& nss, LockMode modeAll); + + /** + * Returns nullptr if the database didn't exist. + */ + Database* getDb() const { + return _autoColl.getDb(); + } + + /** + * Returns nullptr if the collection didn't exist. + */ + Collection* getCollection() const { + return _autoColl.getCollection(); + } + + /** + * Returns nullptr if the view didn't exist. + */ + ViewDefinition* getView() const { + return _view.get(); + } + +private: + const AutoGetCollection _autoColl; + std::shared_ptr<ViewDefinition> _view; +}; + +/** * RAII-style class, which acquires a lock on the specified database in the requested mode and * obtains a reference to the database, creating it was non-existing. Used as a shortcut for * calls to dbHolder().openDb(), taking care of locking details. The requested mode must be diff --git a/src/mongo/db/logical_session_id.h b/src/mongo/db/logical_session_id.h index eca1d8a33f5..f1fb85ce89e 100644 --- a/src/mongo/db/logical_session_id.h +++ b/src/mongo/db/logical_session_id.h @@ -32,6 +32,7 @@ #include "mongo/base/status_with.h" #include "mongo/db/logical_session_id_gen.h" +#include "mongo/stdx/unordered_set.h" #include "mongo/util/uuid.h" namespace mongo { diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript index 7c42568f7c0..854f3045506 100644 --- a/src/mongo/db/query/SConscript +++ b/src/mongo/db/query/SConscript @@ -255,6 +255,7 @@ env.Library( ], LIBDEPS=[ "collation/collator_factory_mock", + "$BUILD_DIR/mongo/db/logical_session_id", "$BUILD_DIR/mongo/db/service_context", ], ) diff --git a/src/mongo/db/query/query_test_service_context.cpp b/src/mongo/db/query/query_test_service_context.cpp index e2682fe44d4..4ad6ac8e857 100644 --- a/src/mongo/db/query/query_test_service_context.cpp +++ b/src/mongo/db/query/query_test_service_context.cpp @@ -44,4 +44,13 @@ ServiceContext::UniqueOperationContext QueryTestServiceContext::makeOperationCon return _uniqueClient->makeOperationContext(); } +ServiceContext::UniqueOperationContext QueryTestServiceContext::makeOperationContext( + LogicalSessionId lsid) { + return _uniqueClient->makeOperationContext(std::move(lsid)); +} + +Client* QueryTestServiceContext::getClient() const { + return _uniqueClient.get(); +} + } // namespace mongo diff --git a/src/mongo/db/query/query_test_service_context.h b/src/mongo/db/query/query_test_service_context.h index 7466116d354..658b73ef36a 100644 --- a/src/mongo/db/query/query_test_service_context.h +++ b/src/mongo/db/query/query_test_service_context.h @@ -29,6 +29,7 @@ #pragma once #include "mongo/db/client.h" +#include "mongo/db/logical_session_id.h" #include "mongo/db/service_context_noop.h" namespace mongo { @@ -44,6 +45,10 @@ public: ServiceContext::UniqueOperationContext makeOperationContext(); + ServiceContext::UniqueOperationContext makeOperationContext(LogicalSessionId lsid); + + Client* getClient() const; + private: ServiceContextNoop _serviceContext; ServiceContext::UniqueClient _uniqueClient; |