summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Saltz <matthew.saltz@mongodb.com>2020-04-14 19:29:24 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-05-11 20:15:12 +0000
commita434867901150513736daa876b362ab9f7a22195 (patch)
tree57f8faaf4618623c886e3607a27140c272ebbc73
parent927de0e9066200b82c6316804d15795978489587 (diff)
downloadmongo-a434867901150513736daa876b362ab9f7a22195.tar.gz
SERVER-45367 Log open cursors for a namespace when submitting tasks to the range deleter
(cherry picked from commit 2c7a53f74cd6f588cca2ab968a9263d59c56684c)
-rw-r--r--src/mongo/db/cursor_manager.cpp16
-rw-r--r--src/mongo/db/cursor_manager.h5
-rw-r--r--src/mongo/db/s/cleanup_orphaned_cmd.cpp3
-rw-r--r--src/mongo/db/s/collection_sharding_state.cpp8
-rw-r--r--src/mongo/db/s/collection_sharding_state.h6
-rw-r--r--src/mongo/db/s/metadata_manager.cpp54
-rw-r--r--src/mongo/db/s/metadata_manager.h5
-rw-r--r--src/mongo/db/s/metadata_manager_test.cpp18
-rw-r--r--src/mongo/db/s/migration_source_manager.cpp3
-rw-r--r--src/mongo/dbtests/cursor_manager_test.cpp39
10 files changed, 143 insertions, 14 deletions
diff --git a/src/mongo/db/cursor_manager.cpp b/src/mongo/db/cursor_manager.cpp
index bfb27d07254..6be2ae666e0 100644
--- a/src/mongo/db/cursor_manager.cpp
+++ b/src/mongo/db/cursor_manager.cpp
@@ -640,6 +640,22 @@ void CursorManager::appendActiveCursors(std::vector<GenericCursor>* cursors) con
}
}
+std::vector<CursorId> CursorManager::getCursorIdsForNamespace(const NamespaceString& nss) const {
+ std::vector<CursorId> cursors;
+
+ auto allPartitions = _cursorMap->lockAllPartitions();
+ for (auto&& partition : allPartitions) {
+ for (auto&& entry : partition) {
+ auto cursor = entry.second;
+ if (cursor->nss() == nss) {
+ cursors.emplace_back(cursor->cursorid());
+ }
+ }
+ }
+
+ return cursors;
+}
+
stdx::unordered_set<CursorId> CursorManager::getCursorsForSession(LogicalSessionId lsid) const {
stdx::unordered_set<CursorId> cursors;
diff --git a/src/mongo/db/cursor_manager.h b/src/mongo/db/cursor_manager.h
index 299b1f3fa65..1ecb19694b9 100644
--- a/src/mongo/db/cursor_manager.h
+++ b/src/mongo/db/cursor_manager.h
@@ -196,6 +196,11 @@ public:
*/
void appendActiveCursors(std::vector<GenericCursor>* cursors) const;
+ /**
+ * Returns a vector of all open cursors for the given namespace.
+ */
+ std::vector<CursorId> getCursorIdsForNamespace(const NamespaceString& nss) const;
+
/*
* Returns a list of all open cursors for the given session.
*/
diff --git a/src/mongo/db/s/cleanup_orphaned_cmd.cpp b/src/mongo/db/s/cleanup_orphaned_cmd.cpp
index a54d3c03aac..d8cf1728f5b 100644
--- a/src/mongo/db/s/cleanup_orphaned_cmd.cpp
+++ b/src/mongo/db/s/cleanup_orphaned_cmd.cpp
@@ -111,7 +111,8 @@ CleanupResult cleanupOrphanedData(OperationContext* opCtx,
*stoppedAtKey = targetRange->getMax();
- notifn = css->cleanUpRange(*targetRange, CollectionShardingState::kNow);
+ notifn = css->cleanUpRange(
+ opCtx, autoColl.getCollection(), *targetRange, CollectionShardingState::kNow);
}
// Sleep waiting for our own deletion. We don't actually care about any others, so there is no
diff --git a/src/mongo/db/s/collection_sharding_state.cpp b/src/mongo/db/s/collection_sharding_state.cpp
index 5215d47b698..df365b79800 100644
--- a/src/mongo/db/s/collection_sharding_state.cpp
+++ b/src/mongo/db/s/collection_sharding_state.cpp
@@ -235,11 +235,13 @@ void CollectionShardingState::forgetReceive(const ChunkRange& range) {
_metadataManager->forgetReceive(range);
}
-auto CollectionShardingState::cleanUpRange(ChunkRange const& range, CleanWhen when)
- -> CleanupNotification {
+auto CollectionShardingState::cleanUpRange(OperationContext* opCtx,
+ const Collection* collection,
+ ChunkRange const& range,
+ CleanWhen when) -> CleanupNotification {
Date_t time = (when == kNow) ? Date_t{} : Date_t::now() +
stdx::chrono::seconds{orphanCleanupDelaySecs.load()};
- return _metadataManager->cleanUpRange(range, time);
+ return _metadataManager->cleanUpRange(opCtx, collection, range, time);
}
std::vector<ScopedCollectionMetadata> CollectionShardingState::overlappingMetadata(
diff --git a/src/mongo/db/s/collection_sharding_state.h b/src/mongo/db/s/collection_sharding_state.h
index eeef74e62b6..e6072916cab 100644
--- a/src/mongo/db/s/collection_sharding_state.h
+++ b/src/mongo/db/s/collection_sharding_state.h
@@ -152,7 +152,11 @@ public:
* result.abandon(), instead of waitStatus, to ignore the outcome.
*/
enum CleanWhen { kNow, kDelayed };
- auto cleanUpRange(ChunkRange const& range, CleanWhen) -> CleanupNotification;
+ auto cleanUpRange(OperationContext* opCtx,
+ const Collection* collection,
+ ChunkRange const& range,
+ CleanWhen) -> CleanupNotification;
+
/**
* Returns a vector of ScopedCollectionMetadata objects representing metadata instances in use
diff --git a/src/mongo/db/s/metadata_manager.cpp b/src/mongo/db/s/metadata_manager.cpp
index 87e59ee84e9..ba8eefd6cd3 100644
--- a/src/mongo/db/s/metadata_manager.cpp
+++ b/src/mongo/db/s/metadata_manager.cpp
@@ -38,6 +38,8 @@
#include "mongo/bson/simple_bsonobj_comparator.h"
#include "mongo/bson/util/builder.h"
#include "mongo/db/bson/dotted_path_support.h"
+#include "mongo/db/cursor_manager.h"
+#include "mongo/db/db_raii.h"
#include "mongo/db/query/internal_plans.h"
#include "mongo/db/range_arithmetic.h"
#include "mongo/db/s/collection_sharding_state.h"
@@ -150,6 +152,49 @@ void scheduleCleanup(executor::TaskExecutor* executor,
}
}
+void logRangeDeletionWaitingOnOpenCursors(const OperationContext* opCtx,
+ const Collection* collection,
+ const NamespaceString& nss,
+ const ChunkRange& range) {
+ invariant(opCtx->lockState()->isCollectionLockedForMode(nss.toString(), MODE_IS));
+ std::vector<CursorId> cursorIds;
+ // If the collection exists, gather a list of all cursors related to the collection.
+ if (collection) {
+ auto cursorIdsFromCollectionCursorManager =
+ collection->getCursorManager()->getCursorIdsForNamespace(nss);
+ cursorIds.insert(cursorIds.end(),
+ cursorIdsFromCollectionCursorManager.begin(),
+ cursorIdsFromCollectionCursorManager.end());
+
+ // Aggregation cursors are registered on the global cursor manager. A cursor on
+ // the global cursor manager can involve any number of collections, but is registered with
+ // the namespace of the aggregate command. This works well for this purpose since any other
+ // namespaces would come through a $lookup or $graphLookup which cannot read from sharded
+ // collections and so could not be contributing to the delay of a range deletion. The
+ // namespace of the aggregate command can be sharded, so we do want to include those
+ // aggregation cursors in this message.
+ auto cursorIdsFromGlobalCursorManager =
+ CursorManager::getGlobalCursorManager()->getCursorIdsForNamespace(nss);
+ cursorIds.insert(cursorIds.end(),
+ cursorIdsFromGlobalCursorManager.begin(),
+ cursorIdsFromGlobalCursorManager.end());
+ }
+
+ // Join cursorIds as a comma-separated list.
+ std::string cursorIdList =
+ cursorIds.empty() ? "" : std::accumulate(std::next(cursorIds.begin()),
+ cursorIds.end(),
+ std::to_string(cursorIds[0]),
+ [](std::string a, CursorId b) {
+ return std::move(a) + ',' + std::to_string(b);
+ });
+
+ log() << "Deletion of " << nss.ns() << " range " << redact(range.toString())
+ << " will be scheduled after all possibly dependent queries finish. "
+ "All open cursors for namespace: ["
+ << cursorIdList << "]";
+}
+
} // namespace
MetadataManager::MetadataManager(ServiceContext* serviceContext,
@@ -417,8 +462,10 @@ void MetadataManager::forgetReceive(ChunkRange const& range) {
_pushRangeToClean(lg, range, Date_t{}).abandon();
}
-auto MetadataManager::cleanUpRange(ChunkRange const& range, Date_t whenToDelete)
- -> CleanupNotification {
+auto MetadataManager::cleanUpRange(OperationContext* opCtx,
+ const Collection* collection,
+ ChunkRange const& range,
+ Date_t whenToDelete) -> CleanupNotification {
stdx::lock_guard<stdx::mutex> lg(_managerLock);
invariant(!_metadata.empty());
@@ -444,8 +491,7 @@ auto MetadataManager::cleanUpRange(ChunkRange const& range, Date_t whenToDelete)
return _pushRangeToClean(lg, range, whenToDelete);
}
- log() << "Deletion of " << _nss.ns() << " range " << redact(range.toString())
- << " will be scheduled after all possibly dependent queries finish";
+ logRangeDeletionWaitingOnOpenCursors(opCtx, collection, _nss, range);
// Put it on the oldest metadata permissible; the current one might live a long time.
auto& orphans = overlapMetadata->orphans;
diff --git a/src/mongo/db/s/metadata_manager.h b/src/mongo/db/s/metadata_manager.h
index 5a6cbda9d38..53d124c2467 100644
--- a/src/mongo/db/s/metadata_manager.h
+++ b/src/mongo/db/s/metadata_manager.h
@@ -118,7 +118,10 @@ public:
*
* Call waitStatus(opCtx) on the result to wait for the deletion to complete or fail.
*/
- CleanupNotification cleanUpRange(ChunkRange const& range, Date_t whenToDelete);
+ CleanupNotification cleanUpRange(OperationContext* opCtx,
+ const Collection* collection,
+ ChunkRange const& range,
+ Date_t whenToDelete);
/**
* Returns a vector of ScopedCollectionMetadata objects representing metadata instances in use
diff --git a/src/mongo/db/s/metadata_manager_test.cpp b/src/mongo/db/s/metadata_manager_test.cpp
index 3f8ce528555..b070c8b3219 100644
--- a/src/mongo/db/s/metadata_manager_test.cpp
+++ b/src/mongo/db/s/metadata_manager_test.cpp
@@ -80,6 +80,13 @@ protected:
configTargeter()->setFindHostReturnValue(dummyHost);
_manager = std::make_shared<MetadataManager>(getServiceContext(), kNss, executor());
+ _autoColl.emplace(operationContext(), kNss, MODE_IS);
+ }
+
+ void tearDown() override {
+ _autoColl.reset();
+ _manager.reset();
+ ShardingMongodTestFixture::tearDown();
}
std::shared_ptr<RemoteCommandTargeterMock> configTargeter() const {
@@ -146,7 +153,12 @@ protected:
return cm2Ptr;
}
+ Collection* collection() {
+ return _autoColl->getCollection();
+ }
+
std::shared_ptr<MetadataManager> _manager;
+ boost::optional<AutoGetCollection> _autoColl;
};
// In the following tests, the ranges-to-clean is not drained by the background deleter thread
@@ -172,7 +184,7 @@ TEST_F(MetadataManagerTest, AddRangeNotificationsBlockAndYield) {
_manager->refreshActiveMetadata(makeEmptyMetadata());
ChunkRange cr1(BSON("key" << 0), BSON("key" << 10));
- auto notifn1 = _manager->cleanUpRange(cr1, Date_t{});
+ auto notifn1 = _manager->cleanUpRange(operationContext(), collection(), cr1, Date_t{});
ASSERT_FALSE(notifn1.ready());
ASSERT_EQ(_manager->numberOfRangesToClean(), 1UL);
auto optNotifn = _manager->trackOrphanedDataCleanup(cr1);
@@ -218,7 +230,7 @@ TEST_F(MetadataManagerTest, NotificationBlocksUntilDeletion) {
ASSERT_EQ(_manager->numberOfMetadataSnapshots(), 3UL);
ASSERT_EQ(_manager->numberOfRangesToClean(), 0UL); // not yet...
- optNotif = _manager->cleanUpRange(cr1, Date_t{});
+ optNotif = _manager->cleanUpRange(operationContext(), collection(), cr1, Date_t{});
ASSERT_EQ(_manager->numberOfMetadataSnapshots(), 3UL);
ASSERT_EQ(_manager->numberOfRangesToClean(), 1UL);
} // scm1,2,3 destroyed, refcount of each metadata goes to zero
@@ -316,7 +328,7 @@ TEST_F(MetadataManagerTest, RangesToCleanMembership) {
ASSERT(_manager->numberOfRangesToClean() == 0UL);
ChunkRange cr1 = ChunkRange(BSON("key" << 0), BSON("key" << 10));
- auto notifn = _manager->cleanUpRange(cr1, Date_t{});
+ auto notifn = _manager->cleanUpRange(operationContext(), collection(), cr1, Date_t{});
ASSERT(!notifn.ready());
ASSERT(_manager->numberOfRangesToClean() == 1UL);
notifn.abandon();
diff --git a/src/mongo/db/s/migration_source_manager.cpp b/src/mongo/db/s/migration_source_manager.cpp
index bbc2ead1cea..be76f9102ac 100644
--- a/src/mongo/db/s/migration_source_manager.cpp
+++ b/src/mongo/db/s/migration_source_manager.cpp
@@ -637,7 +637,8 @@ Status MigrationSourceManager::commitChunkMetadataOnConfig(OperationContext* opC
auto const whenToClean = _args.getWaitForDelete() ? CollectionShardingState::kNow
: CollectionShardingState::kDelayed;
AutoGetCollection autoColl(opCtx, getNss(), MODE_IS);
- return CollectionShardingState::get(opCtx, getNss())->cleanUpRange(range, whenToClean);
+ return CollectionShardingState::get(opCtx, getNss())
+ ->cleanUpRange(opCtx, autoColl.getCollection(), range, whenToClean);
}();
if (!MONGO_FAIL_POINT(doNotRefreshRecipientAfterCommit)) {
diff --git a/src/mongo/dbtests/cursor_manager_test.cpp b/src/mongo/dbtests/cursor_manager_test.cpp
index a861f89bfb8..e89cc66a35f 100644
--- a/src/mongo/dbtests/cursor_manager_test.cpp
+++ b/src/mongo/dbtests/cursor_manager_test.cpp
@@ -585,5 +585,44 @@ TEST_F(CursorManagerTestCustomOpCtx, MultipleCursorsMultipleSessions) {
ASSERT(cursors2.find(cursor2) != cursors2.end());
}
+TEST_F(CursorManagerTestCustomOpCtx,
+ GetCursorIdsForNamespaceReturnsSingleEntryForMatchingNamespace) {
+ auto opCtx = _queryServiceContext->makeOperationContext();
+ auto pinned = makeCursor(opCtx.get());
+ auto cursorId = pinned.getCursor()->cursorid();
+ auto cursorsForNamespace = useCursorManager()->getCursorIdsForNamespace(kTestNss);
+ ASSERT_EQUALS(cursorsForNamespace.size(), 1ull);
+ ASSERT_EQUALS(cursorsForNamespace[0], cursorId);
+}
+
+TEST_F(CursorManagerTestCustomOpCtx,
+ GetCursorIdsForNamespaceReturnsMultipleEntriesForMatchingNamespace) {
+ auto opCtx = _queryServiceContext->makeOperationContext();
+ auto pinned1 = makeCursor(opCtx.get());
+ auto pinned2 = makeCursor(opCtx.get());
+ auto cursorId1 = pinned1.getCursor()->cursorid();
+ auto cursorId2 = pinned2.getCursor()->cursorid();
+ auto cursorsForNamespace = useCursorManager()->getCursorIdsForNamespace(kTestNss);
+ ASSERT_EQUALS(cursorsForNamespace.size(), 2ull);
+
+ // The results for cursorsForNamespace won't necessarily be the same as the order of insertion.
+ std::set<CursorId> cursorsForNamespaceSet(cursorsForNamespace.begin(),
+ cursorsForNamespace.end());
+
+ ASSERT_EQUALS(cursorsForNamespaceSet.count(cursorId1), 1ull);
+ ASSERT_EQUALS(cursorsForNamespaceSet.count(cursorId2), 1ull);
+}
+
+TEST_F(CursorManagerTestCustomOpCtx,
+ GetCursorIdsForNamespaceDoesNotReturnEntriesForNonMatchingNamespace) {
+ auto opCtx = _queryServiceContext->makeOperationContext();
+ // Add a cursor for kTestNss.
+ auto pinned = makeCursor(opCtx.get());
+ // Get cursors for a different NamespaceString.
+ auto cursorsForNamespace =
+ useCursorManager()->getCursorIdsForNamespace(NamespaceString("somerandom.nss"));
+ ASSERT_EQUALS(cursorsForNamespace.size(), 0ull);
+}
+
} // namespace
} // namespace mongo