summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeert Bosch <geert@mongodb.com>2018-04-16 16:19:13 -0400
committerGeert Bosch <geert@mongodb.com>2018-04-17 17:34:41 -0400
commitc45a62c24761110505161ce4ecc263f4bfce9c59 (patch)
tree5cbd14a1a06a96c085619f1ab0c4616b6b8e2fb1
parent366f5aea022ea2eccbce5c253e813c1151d53fc1 (diff)
downloadmongo-c45a62c24761110505161ce4ecc263f4bfce9c59.tar.gz
SERVER-33632 UUIDCatalog queries fall back to pre-close state
While the UUIDCatalog is closed for reloading during rollback and catalog reload, queries by UUID may need to resolve the NSS for authorization purposes before taking locks. Use a shadow catalog to allow such name resolution.
-rw-r--r--src/mongo/db/catalog/catalog_control.cpp11
-rw-r--r--src/mongo/db/catalog/uuid_catalog.cpp28
-rw-r--r--src/mongo/db/catalog/uuid_catalog.h27
-rw-r--r--src/mongo/db/catalog/uuid_catalog_test.cpp45
4 files changed, 106 insertions, 5 deletions
diff --git a/src/mongo/db/catalog/catalog_control.cpp b/src/mongo/db/catalog/catalog_control.cpp
index ea06eb9df67..684862b6a9f 100644
--- a/src/mongo/db/catalog/catalog_control.cpp
+++ b/src/mongo/db/catalog/catalog_control.cpp
@@ -46,6 +46,13 @@ namespace catalog {
void closeCatalog(OperationContext* opCtx) {
invariant(opCtx->lockState()->isW());
+ // Closing UUID Catalog: only lookupNSSByUUID will fall back to using pre-closing state to
+ // allow authorization for currently unknown UUIDs. This is needed because authorization needs
+ // to work before acquiring locks, and might otherwise spuriously regard a UUID as unknown
+ // while reloading the catalog.
+ UUIDCatalog::get(opCtx).onCloseCatalog();
+ LOG(1) << "closeCatalog: closing UUID catalog";
+
// Close all databases.
log() << "closeCatalog: closing all databases";
constexpr auto reason = "closing databases for closeCatalog";
@@ -166,6 +173,10 @@ void openCatalog(OperationContext* opCtx) {
}
}
}
+ // Opening UUID Catalog: The UUID catalog is now in sync with the storage engine catalog. Clear
+ // the pre-closing state.
+ UUIDCatalog::get(opCtx).onOpenCatalog();
+ LOG(1) << "openCatalog: finished reloading UUID catalog";
}
} // namespace catalog
} // namespace mongo
diff --git a/src/mongo/db/catalog/uuid_catalog.cpp b/src/mongo/db/catalog/uuid_catalog.cpp
index 15edc59c320..3ec994d7ef0 100644
--- a/src/mongo/db/catalog/uuid_catalog.cpp
+++ b/src/mongo/db/catalog/uuid_catalog.cpp
@@ -155,6 +155,20 @@ void UUIDCatalog::onCloseDatabase(Database* db) {
}
}
+void UUIDCatalog::onCloseCatalog() {
+ stdx::lock_guard<stdx::mutex> lock(_catalogLock);
+ invariant(!_shadowCatalog);
+ _shadowCatalog.emplace();
+ for (auto entry : _catalog)
+ _shadowCatalog->insert({entry.first, entry.second->ns()});
+}
+
+void UUIDCatalog::onOpenCatalog() {
+ stdx::lock_guard<stdx::mutex> lock(_catalogLock);
+ invariant(_shadowCatalog);
+ _shadowCatalog.reset();
+}
+
Collection* UUIDCatalog::lookupCollectionByUUID(CollectionUUID uuid) const {
stdx::lock_guard<stdx::mutex> lock(_catalogLock);
auto foundIt = _catalog.find(uuid);
@@ -164,8 +178,18 @@ Collection* UUIDCatalog::lookupCollectionByUUID(CollectionUUID uuid) const {
NamespaceString UUIDCatalog::lookupNSSByUUID(CollectionUUID uuid) const {
stdx::lock_guard<stdx::mutex> lock(_catalogLock);
auto foundIt = _catalog.find(uuid);
- Collection* coll = foundIt == _catalog.end() ? nullptr : foundIt->second;
- return foundIt == _catalog.end() ? NamespaceString() : coll->ns();
+ if (foundIt != _catalog.end())
+ return foundIt->second->ns();
+
+ // Only in the case that the catalog is closed and a UUID is currently unknown, resolve it
+ // using the pre-close state. This ensures that any tasks reloading the catalog can see their
+ // own updates.
+ if (_shadowCatalog) {
+ auto shadowIt = _shadowCatalog->find(uuid);
+ if (shadowIt != _shadowCatalog->end())
+ return shadowIt->second;
+ }
+ return NamespaceString();
}
void UUIDCatalog::registerUUIDCatalogEntry(CollectionUUID uuid, Collection* coll) {
diff --git a/src/mongo/db/catalog/uuid_catalog.h b/src/mongo/db/catalog/uuid_catalog.h
index 57a6061df39..aa864eb2571 100644
--- a/src/mongo/db/catalog/uuid_catalog.h
+++ b/src/mongo/db/catalog/uuid_catalog.h
@@ -153,20 +153,34 @@ public:
void registerUUIDCatalogEntry(CollectionUUID uuid, Collection* coll);
Collection* removeUUIDCatalogEntry(CollectionUUID uuid);
- /* This function gets the Collection* pointer that corresponds to
+ /**
+ * This function gets the Collection* pointer that corresponds to
* CollectionUUID uuid. The required locks should be obtained prior
* to calling this function, or else the found Collection pointer
* might no longer be valid when the call returns.
*/
Collection* lookupCollectionByUUID(CollectionUUID uuid) const;
- /* This function gets the NamespaceString from the Collection* pointer that
+ /**
+ * This function gets the NamespaceString from the Collection* pointer that
* corresponds to CollectionUUID uuid. If there is no such pointer, an empty
- * NamespaceString is returned.
+ * NamespaceString is returned. See onCloseCatalog/onOpenCatalog for more info.
*/
NamespaceString lookupNSSByUUID(CollectionUUID uuid) const;
/**
+ * Puts the catalog in closed state. In this state, the lookupNSSByUUID method will fall back
+ * to the pre-close state to resolve queries for currently unknown UUIDs. This allows
+ * authorization, which needs to do lookups outside of database locks, to proceed.
+ */
+ void onCloseCatalog();
+
+ /**
+ * Puts the catatlog back in open state, removing the pre-close state. See onCloseCatalog.
+ */
+ void onOpenCatalog();
+
+ /**
* Return the UUID lexicographically preceding `uuid` in the database named by `db`.
*
* Return `boost::none` if `uuid` is not found, or is the first UUID in that database.
@@ -185,6 +199,13 @@ private:
const stdx::lock_guard<stdx::mutex>&);
mutable mongo::stdx::mutex _catalogLock;
+ /**
+ * When present, indicates that the catalog is in closed state, and contains a map from UUID
+ * to pre-close NSS. See also onCloseCatalog.
+ */
+ boost::optional<
+ mongo::stdx::unordered_map<CollectionUUID, NamespaceString, CollectionUUID::Hash>>
+ _shadowCatalog;
/**
* Map from database names to ordered `vector`s of their UUIDs.
diff --git a/src/mongo/db/catalog/uuid_catalog_test.cpp b/src/mongo/db/catalog/uuid_catalog_test.cpp
index 20115a42642..0028f7d38f4 100644
--- a/src/mongo/db/catalog/uuid_catalog_test.cpp
+++ b/src/mongo/db/catalog/uuid_catalog_test.cpp
@@ -185,4 +185,49 @@ TEST_F(UUIDCatalogTest, InvalidateOrdering) {
ASSERT(prevNext);
ASSERT_EQUALS(*prevNext, nextUUID);
}
+
+TEST_F(UUIDCatalogTest, LookupNSSByUUIDForClosedCatalogReturnsOldNSSIfDropped) {
+ catalog.onCloseCatalog();
+ catalog.onDropCollection(&opCtx, colUUID);
+ ASSERT(catalog.lookupCollectionByUUID(colUUID) == nullptr);
+ ASSERT_EQUALS(catalog.lookupNSSByUUID(colUUID), nss);
+ catalog.onOpenCatalog();
+ ASSERT_EQUALS(catalog.lookupNSSByUUID(colUUID), NamespaceString());
+}
+
+TEST_F(UUIDCatalogTest, LookupNSSByUUIDForClosedCatalogReturnsNewlyCreatedNSS) {
+ auto newUUID = CollectionUUID::gen();
+ NamespaceString newNss(nss.db(), "newcol");
+ Collection newCol(stdx::make_unique<CollectionMock>(newNss));
+
+ // Ensure that looking up non-existing UUIDs doesn't affect later registration of those UUIDs.
+ catalog.onCloseCatalog();
+ ASSERT(catalog.lookupCollectionByUUID(newUUID) == nullptr);
+ ASSERT(catalog.lookupNSSByUUID(newUUID) == NamespaceString());
+ catalog.onCreateCollection(&opCtx, &newCol, newUUID);
+ ASSERT_EQUALS(catalog.lookupCollectionByUUID(newUUID), &newCol);
+ ASSERT_EQUALS(catalog.lookupNSSByUUID(colUUID), nss);
+
+ // Ensure that collection still exists after opening the catalog again.
+ catalog.onOpenCatalog();
+ ASSERT_EQUALS(catalog.lookupCollectionByUUID(newUUID), &newCol);
+ ASSERT_EQUALS(catalog.lookupNSSByUUID(colUUID), nss);
+}
+
+TEST_F(UUIDCatalogTest, LookupNSSByUUIDForClosedCatalogReturnsFreshestNSS) {
+ NamespaceString newNss(nss.db(), "newcol");
+ Collection newCol(stdx::make_unique<CollectionMock>(newNss));
+ catalog.onCloseCatalog();
+ catalog.onDropCollection(&opCtx, colUUID);
+ ASSERT(catalog.lookupCollectionByUUID(colUUID) == nullptr);
+ ASSERT_EQUALS(catalog.lookupNSSByUUID(colUUID), nss);
+ catalog.onCreateCollection(&opCtx, &newCol, colUUID);
+ ASSERT_EQUALS(catalog.lookupCollectionByUUID(colUUID), &newCol);
+ ASSERT_EQUALS(catalog.lookupNSSByUUID(colUUID), newNss);
+
+ // Ensure that collection still exists after opening the catalog again.
+ catalog.onOpenCatalog();
+ ASSERT_EQUALS(catalog.lookupCollectionByUUID(colUUID), &newCol);
+ ASSERT_EQUALS(catalog.lookupNSSByUUID(colUUID), newNss);
+}
} // namespace