summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/noPassthrough/point_in_time_lookups.js3
-rw-r--r--src/mongo/db/catalog/collection_catalog_test.cpp37
-rw-r--r--src/mongo/db/db_raii.cpp26
3 files changed, 62 insertions, 4 deletions
diff --git a/jstests/noPassthrough/point_in_time_lookups.js b/jstests/noPassthrough/point_in_time_lookups.js
index 8367574c2e5..fda37331dcc 100644
--- a/jstests/noPassthrough/point_in_time_lookups.js
+++ b/jstests/noPassthrough/point_in_time_lookups.js
@@ -17,6 +17,9 @@ const replTest = new ReplSetTest({
// Set the history window to 1 hour to prevent the oldest timestamp from advancing. This
// is necessary to avoid removing data files across restarts for this test.
minSnapshotHistoryWindowInSeconds: 60 * 60,
+ // Exercise yielding and restoring point-in-time collections.
+ internalQueryExecYieldIterations: 0,
+ internalQueryExecYieldPeriodMS: 0
}
}
});
diff --git a/src/mongo/db/catalog/collection_catalog_test.cpp b/src/mongo/db/catalog/collection_catalog_test.cpp
index 343a10ae9f3..421e854969c 100644
--- a/src/mongo/db/catalog/collection_catalog_test.cpp
+++ b/src/mongo/db/catalog/collection_catalog_test.cpp
@@ -3669,5 +3669,42 @@ TEST_F(CollectionCatalogTimestampTest, OpenCollectionBetweenIndexBuildInProgress
coll);
}
}
+
+TEST_F(CollectionCatalogTimestampTest, ResolveNamespaceStringOrUUIDAtLatest) {
+ RAIIServerParameterControllerForTest featureFlagController(
+ "featureFlagPointInTimeCatalogLookups", true);
+
+ const NamespaceString nss = NamespaceString::createNamespaceString_forTest("a.b");
+ const Timestamp createCollectionTs = Timestamp(10, 10);
+ const UUID uuid = createCollection(opCtx.get(), nss, createCollectionTs);
+ const NamespaceStringOrUUID nssOrUUID = NamespaceStringOrUUID(nss.db(), uuid);
+
+ NamespaceString resolvedNss =
+ CollectionCatalog::get(opCtx.get())->resolveNamespaceStringOrUUID(opCtx.get(), nssOrUUID);
+ ASSERT_EQ(resolvedNss, nss);
+
+ const Timestamp dropCollectionTs = Timestamp(20, 20);
+ dropCollection(opCtx.get(), nss, dropCollectionTs);
+
+ // Resolving the UUID throws NamespaceNotFound as the collection is no longer in the latest
+ // collection catalog.
+ ASSERT_THROWS_CODE(
+ CollectionCatalog::get(opCtx.get())->resolveNamespaceStringOrUUID(opCtx.get(), nssOrUUID),
+ DBException,
+ ErrorCodes::NamespaceNotFound);
+
+ {
+ OneOffRead oor(opCtx.get(), createCollectionTs);
+ Lock::GlobalLock globalLock(opCtx.get(), MODE_IS);
+
+ CollectionCatalog::get(opCtx.get())
+ ->establishConsistentCollection(opCtx.get(), nss, createCollectionTs);
+
+ // Resolving the UUID looks in OpenedCollections to try to resolve the UUID.
+ resolvedNss = CollectionCatalog::get(opCtx.get())
+ ->resolveNamespaceStringOrUUID(opCtx.get(), nssOrUUID);
+ ASSERT_EQ(resolvedNss, nss);
+ }
+}
} // namespace
} // namespace mongo
diff --git a/src/mongo/db/db_raii.cpp b/src/mongo/db/db_raii.cpp
index 4d65ddeba24..f9d8bb2e446 100644
--- a/src/mongo/db/db_raii.cpp
+++ b/src/mongo/db/db_raii.cpp
@@ -1084,10 +1084,28 @@ ConsistentCatalogAndSnapshot getConsistentCatalogAndSnapshot(
const auto catalogBeforeSnapshot = CollectionCatalog::get(opCtx);
- // It is incorrect to resolve the UUID here as we haven't established a consistent view of
- // this UUID yet. During a concurrent rename it can be wrong. This namespace is only used to
- // determine if it is an internal namespace.
- const auto nss = catalogBeforeSnapshot->resolveNamespaceStringOrUUID(opCtx, nsOrUUID);
+ // When a query yields it releases its snapshot, and any point-in-time instantiated
+ // collections stored on the snapshot decoration are destructed. At the start of a query,
+ // collections are fetched using a namespace. However, when a query is restoring from
+ // yield it attempts to fetch collections by UUID. It's possible for a UUID to no longer
+ // resolve to a namespace in the latest collection catalog if that collection was dropped
+ // while the query was yielding. This doesn't conclude that the collection is inaccessible
+ // at an earlier point-in-time as the data files may still be on disk. This namespace is
+ // used to determine if the read source needs to be changed and we only do this if the
+ // original read source is kNoTimestamp or kLastApplied. If it's neither of the two we can
+ // safely continue.
+ NamespaceString nss;
+ try {
+ nss = catalogBeforeSnapshot->resolveNamespaceStringOrUUID(opCtx, nsOrUUID);
+ } catch (const ExceptionFor<ErrorCodes::NamespaceNotFound>&) {
+ invariant(nsOrUUID.uuid());
+
+ const auto readSource = opCtx->recoveryUnit()->getTimestampReadSource();
+ if (readSource == RecoveryUnit::ReadSource::kNoTimestamp ||
+ readSource == RecoveryUnit::ReadSource::kLastApplied) {
+ throw;
+ }
+ }
// This may modify the read source on the recovery unit for opCtx if the current read source
// is either kNoTimestamp or kLastApplied.