summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/SConscript1
-rw-r--r--src/mongo/db/clientcursor.cpp4
-rw-r--r--src/mongo/db/clientcursor.h13
-rw-r--r--src/mongo/db/cursor_manager.cpp69
-rw-r--r--src/mongo/db/cursor_manager.h17
-rw-r--r--src/mongo/db/db_raii.cpp8
-rw-r--r--src/mongo/db/db_raii.h43
-rw-r--r--src/mongo/db/logical_session_id.h1
-rw-r--r--src/mongo/db/query/SConscript1
-rw-r--r--src/mongo/db/query/query_test_service_context.cpp9
-rw-r--r--src/mongo/db/query/query_test_service_context.h5
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;