summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2019-02-04 10:45:12 -0500
committerDavid Storch <david.storch@10gen.com>2019-02-05 08:34:35 -0500
commitcb1aabbba7093b6c42b6986a9ad0aea31528929a (patch)
treeacd49931110ac57d13e70f870528929b1b2dd631 /src/mongo/db
parent9a90dfc2fbe769d3caf02a3550f00bc9fa9df483 (diff)
downloadmongo-cb1aabbba7093b6c42b6986a9ad0aea31528929a.tar.gz
SERVER-37454 Delete GlobalCursorIdCache.
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/SConscript1
-rw-r--r--src/mongo/db/clientcursor.cpp2
-rw-r--r--src/mongo/db/cursor_manager.cpp136
-rw-r--r--src/mongo/db/cursor_manager.h15
-rw-r--r--src/mongo/db/run_op_kill_cursors.cpp106
-rw-r--r--src/mongo/db/run_op_kill_cursors.h48
-rw-r--r--src/mongo/db/service_entry_point_common.cpp18
7 files changed, 170 insertions, 156 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index ed2e69d5a79..b135cb559a2 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -1175,6 +1175,7 @@ env.Library(
'query/plan_yield_policy.cpp',
'query/query_yield.cpp',
'query/stage_builder.cpp',
+ 'run_op_kill_cursors.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp
index 30c52ef2adc..41c2b814d5c 100644
--- a/src/mongo/db/clientcursor.cpp
+++ b/src/mongo/db/clientcursor.cpp
@@ -279,7 +279,7 @@ public:
const ServiceContext::UniqueOperationContext opCtx = cc().makeOperationContext();
auto now = opCtx->getServiceContext()->getPreciseClockSource()->now();
cursorStatsTimedOut.increment(
- CursorManager::timeoutCursorsGlobal(opCtx.get(), now));
+ CursorManager::getGlobalCursorManager()->timeoutCursors(opCtx.get(), now));
}
MONGO_IDLE_THREAD_BLOCK;
sleepsecs(getClientCursorMonitorFrequencySecs());
diff --git a/src/mongo/db/cursor_manager.cpp b/src/mongo/db/cursor_manager.cpp
index 7b7fef06152..3479b122b47 100644
--- a/src/mongo/db/cursor_manager.cpp
+++ b/src/mongo/db/cursor_manager.cpp
@@ -60,122 +60,16 @@
namespace mongo {
-using std::vector;
-
constexpr int CursorManager::kNumPartitions;
-namespace {
-
-class GlobalCursorIdCache {
-public:
- GlobalCursorIdCache();
- ~GlobalCursorIdCache();
-
- /**
- * works globally
- */
- bool killCursor(OperationContext* opCtx, CursorId id, bool checkAuth);
-
- void appendStats(BSONObjBuilder& builder);
-
- std::size_t timeoutCursors(OperationContext* opCtx, Date_t now);
-
- int64_t nextSeed();
-
-private:
- // '_mutex' must not be held when acquiring a CursorManager mutex to avoid deadlock.
- SimpleMutex _mutex;
-
- using CursorIdToNssMap = stdx::unordered_map<CursorId, NamespaceString>;
- using IdToNssMap = stdx::unordered_map<unsigned, NamespaceString>;
-
- IdToNssMap _idToNss;
- unsigned _nextId;
-
- std::unique_ptr<SecureRandom> _secureRandom;
-};
-
-// Note that "globalCursorIdCache" must be declared before "globalCursorManager", as the latter
-// calls into the former during destruction.
-std::unique_ptr<GlobalCursorIdCache> globalCursorIdCache;
std::unique_ptr<CursorManager> globalCursorManager;
-MONGO_INITIALIZER(GlobalCursorIdCache)(InitializerContext* context) {
- globalCursorIdCache.reset(new GlobalCursorIdCache());
- return Status::OK();
-}
-
-MONGO_INITIALIZER_WITH_PREREQUISITES(GlobalCursorManager, ("GlobalCursorIdCache"))
+MONGO_INITIALIZER(GlobalCursorManager)
(InitializerContext* context) {
- globalCursorManager.reset(new CursorManager());
+ globalCursorManager = std::make_unique<CursorManager>();
return Status::OK();
}
-GlobalCursorIdCache::GlobalCursorIdCache() : _nextId(0), _secureRandom() {}
-
-GlobalCursorIdCache::~GlobalCursorIdCache() {}
-
-int64_t GlobalCursorIdCache::nextSeed() {
- stdx::lock_guard<SimpleMutex> lk(_mutex);
- if (!_secureRandom)
- _secureRandom = SecureRandom::create();
- return _secureRandom->nextInt64();
-}
-
-bool GlobalCursorIdCache::killCursor(OperationContext* opCtx, CursorId id, bool checkAuth) {
- // Figure out what the namespace of this cursor is.
- NamespaceString nss;
- {
- auto pin = globalCursorManager->pinCursor(opCtx, id, CursorManager::kNoCheckSession);
- if (!pin.isOK()) {
- // Either the cursor doesn't exist, or it was killed during the last time it was being
- // used, and was cleaned up after this call. Either way, we cannot kill it.
- return false;
- }
- nss = pin.getValue().getCursor()->nss();
- }
- invariant(nss.isValid());
-
- boost::optional<AutoStatsTracker> statsTracker;
- if (!nss.isCollectionlessCursorNamespace()) {
- const boost::optional<int> dbProfilingLevel = boost::none;
- statsTracker.emplace(opCtx,
- nss,
- Top::LockType::NotLocked,
- AutoStatsTracker::LogMode::kUpdateTopAndCurop,
- dbProfilingLevel);
- }
-
- // Check if we are authorized to kill this cursor.
- if (checkAuth) {
- auto ccPin = globalCursorManager->pinCursor(opCtx, id, CursorManager::kNoCheckSession);
- if (!ccPin.isOK()) {
- audit::logKillCursorsAuthzCheck(opCtx->getClient(), nss, id, ccPin.getStatus().code());
- return false;
- }
-
- AuthorizationSession* as = AuthorizationSession::get(opCtx->getClient());
- auto cursorOwner = ccPin.getValue().getCursor()->getAuthenticatedUsers();
- auto authStatus = as->checkAuthForKillCursors(nss, cursorOwner);
- if (!authStatus.isOK()) {
- audit::logKillCursorsAuthzCheck(opCtx->getClient(), nss, id, authStatus.code());
- return false;
- }
- }
-
- Status killStatus = globalCursorManager->killCursor(opCtx, id, checkAuth);
- massert(28697,
- killStatus.reason(),
- killStatus.code() == ErrorCodes::OK || killStatus.code() == ErrorCodes::CursorNotFound);
- return killStatus.isOK();
-}
-
-std::size_t GlobalCursorIdCache::timeoutCursors(OperationContext* opCtx, Date_t now) {
- return globalCursorManager->timeoutCursors(opCtx, now);
-}
-
-} // namespace
-
CursorManager* CursorManager::getGlobalCursorManager() {
return globalCursorManager.get();
}
@@ -193,32 +87,8 @@ std::pair<Status, int> CursorManager::killCursorsWithMatchingSessions(
bySessionCursorKiller.getCursorsKilled());
}
-std::size_t CursorManager::timeoutCursorsGlobal(OperationContext* opCtx, Date_t now) {
- return globalCursorIdCache->timeoutCursors(opCtx, now);
-}
-
-int CursorManager::killCursorGlobalIfAuthorized(OperationContext* opCtx, int n, const char* _ids) {
- ConstDataCursor ids(_ids);
- int numDeleted = 0;
- for (int i = 0; i < n; i++) {
- if (killCursorGlobalIfAuthorized(opCtx, ids.readAndAdvance<LittleEndian<int64_t>>()))
- numDeleted++;
- if (globalInShutdownDeprecated())
- break;
- }
- return numDeleted;
-}
-bool CursorManager::killCursorGlobalIfAuthorized(OperationContext* opCtx, CursorId id) {
- return globalCursorIdCache->killCursor(opCtx, id, true);
-}
-bool CursorManager::killCursorGlobal(OperationContext* opCtx, CursorId id) {
- return globalCursorIdCache->killCursor(opCtx, id, false);
-}
-
-// --------------------------
-
CursorManager::CursorManager()
- : _random(stdx::make_unique<PseudoRandom>(globalCursorIdCache->nextSeed())),
+ : _random(stdx::make_unique<PseudoRandom>(SecureRandom::create()->nextInt64())),
_cursorMap(stdx::make_unique<Partitioned<stdx::unordered_map<CursorId, ClientCursor*>>>()) {}
CursorManager::~CursorManager() {
diff --git a/src/mongo/db/cursor_manager.h b/src/mongo/db/cursor_manager.h
index 2671d251ead..f05beb73dc4 100644
--- a/src/mongo/db/cursor_manager.h
+++ b/src/mongo/db/cursor_manager.h
@@ -73,21 +73,6 @@ public:
*/
static CursorManager* getGlobalCursorManager();
- 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. Returns the number of cursors that
- * were timed out.
- *
- * 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);
-
CursorManager();
/**
diff --git a/src/mongo/db/run_op_kill_cursors.cpp b/src/mongo/db/run_op_kill_cursors.cpp
new file mode 100644
index 00000000000..bbade52a554
--- /dev/null
+++ b/src/mongo/db/run_op_kill_cursors.cpp
@@ -0,0 +1,106 @@
+/**
+ * Copyright (C) 2018-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/run_op_kill_cursors.h"
+
+#include "mongo/base/data_cursor.h"
+#include "mongo/db/audit.h"
+#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/cursor_id.h"
+#include "mongo/db/cursor_manager.h"
+#include "mongo/db/db_raii.h"
+#include "mongo/util/exit.h"
+
+namespace mongo {
+
+namespace {
+
+bool killCursorIfAuthorized(OperationContext* opCtx, CursorId id) {
+ auto cursorManager = CursorManager::getGlobalCursorManager();
+
+ auto pin = cursorManager->pinCursor(opCtx, id, CursorManager::kNoCheckSession);
+ if (!pin.isOK()) {
+ // Either the cursor doesn't exist, or it was killed during the last time it was being
+ // used, and was cleaned up after this call. Either way, we cannot kill it. Write the
+ // attempt to the audit log before returning.
+ audit::logKillCursorsAuthzCheck(opCtx->getClient(), {}, id, pin.getStatus().code());
+ return false;
+ }
+ auto nss = pin.getValue().getCursor()->nss();
+ invariant(nss.isValid());
+
+ boost::optional<AutoStatsTracker> statsTracker;
+ if (!nss.isCollectionlessCursorNamespace()) {
+ const boost::optional<int> dbProfilingLevel = boost::none;
+ statsTracker.emplace(opCtx,
+ nss,
+ Top::LockType::NotLocked,
+ AutoStatsTracker::LogMode::kUpdateTopAndCurop,
+ dbProfilingLevel);
+ }
+
+ AuthorizationSession* as = AuthorizationSession::get(opCtx->getClient());
+ auto cursorOwner = pin.getValue().getCursor()->getAuthenticatedUsers();
+ auto authStatus = as->checkAuthForKillCursors(nss, cursorOwner);
+ if (!authStatus.isOK()) {
+ audit::logKillCursorsAuthzCheck(opCtx->getClient(), nss, id, authStatus.code());
+ return false;
+ }
+
+ // Release the pin so that the cursor can be killed.
+ pin.getValue().release();
+
+ Status killStatus = cursorManager->killCursor(opCtx, id, true /* shouldAudit */);
+ massert(28697,
+ killStatus.reason(),
+ killStatus.code() == ErrorCodes::OK || killStatus.code() == ErrorCodes::CursorNotFound);
+ return killStatus.isOK();
+}
+
+} // namespace
+
+int runOpKillCursors(OperationContext* opCtx, size_t numCursorIds, const char* idsArray) {
+ ConstDataCursor idsDataCursor(idsArray);
+ int numKilled = 0;
+ for (size_t i = 0; i < numCursorIds; i++) {
+ CursorId nextCursorId = idsDataCursor.readAndAdvance<LittleEndian<int64_t>>();
+ if (killCursorIfAuthorized(opCtx, nextCursorId)) {
+ ++numKilled;
+ }
+
+ if (globalInShutdownDeprecated()) {
+ break;
+ }
+ }
+ return numKilled;
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/run_op_kill_cursors.h b/src/mongo/db/run_op_kill_cursors.h
new file mode 100644
index 00000000000..c4ffc1d742d
--- /dev/null
+++ b/src/mongo/db/run_op_kill_cursors.h
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2018-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include "mongo/db/operation_context.h"
+
+namespace mongo {
+
+/**
+ * Kills the cursors inside the array of cursor ids pointed to by 'idsArray', after checking that
+ * the logged in user is authorized to do so. 'numCursorIds' is the number of cursors in 'idsArray'.
+ * Also responsible for audit logging.
+ *
+ * Returns the number of cursors killed.
+ *
+ * The caller is responsible for validating that 'numCursorIds' > 0 and that the array is actually
+ * of size 'numCursorIds'.
+ */
+int runOpKillCursors(OperationContext* opCtx, size_t numCursorIds, const char* idsArray);
+
+} // namespace mongo
diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp
index c4679785fe1..ee40ef54b4b 100644
--- a/src/mongo/db/service_entry_point_common.cpp
+++ b/src/mongo/db/service_entry_point_common.cpp
@@ -66,6 +66,7 @@
#include "mongo/db/repl/repl_client_info.h"
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/db/repl/speculative_majority_read_info.h"
+#include "mongo/db/run_op_kill_cursors.h"
#include "mongo/db/s/operation_sharding_state.h"
#include "mongo/db/s/sharded_connection_info.h"
#include "mongo/db/s/sharding_state.h"
@@ -996,7 +997,7 @@ void receivedKillCursors(OperationContext* opCtx, const Message& m) {
const char* cursorArray = dbmessage.getArray(n);
- int found = CursorManager::killCursorGlobalIfAuthorized(opCtx, n, cursorArray);
+ int found = runOpKillCursors(opCtx, static_cast<size_t>(n), cursorArray);
if (shouldLog(logger::LogSeverity::Debug(1)) || found != n) {
LOG(found == n ? 1 : 0) << "killcursors: found " << found << " of " << n;
@@ -1099,12 +1100,15 @@ DbResponse receivedGetMore(OperationContext* opCtx,
// Make sure that killCursorGlobal does not throw an exception if it is interrupted.
UninterruptibleLockGuard noInterrupt(opCtx->lockState());
- // If a cursor with id 'cursorid' was authorized, it may have been advanced
- // before an exception terminated processGetMore. Erase the ClientCursor
- // because it may now be out of sync with the client's iteration state.
- // SERVER-7952
- // TODO Temporary code, see SERVER-4563 for a cleanup overview.
- CursorManager::killCursorGlobal(opCtx, cursorid);
+ // If an error was thrown prior to auth checks, then the cursor should remain alive in
+ // order to prevent an unauthorized user from resulting in the death of a cursor. In
+ // other error cases, the cursor is dead and should be cleaned up.
+ //
+ // If killing the cursor fails, ignore the error and don't try again. The cursor should
+ // be reaped by the client cursor timeout thread.
+ CursorManager::getGlobalCursorManager()
+ ->killCursor(opCtx, cursorid, false /* shouldAudit */)
+ .ignore();
}
BSONObjBuilder err;