diff options
author | Geert Bosch <geert@mongodb.com> | 2018-04-16 16:19:13 -0400 |
---|---|---|
committer | Geert Bosch <geert@mongodb.com> | 2018-04-17 17:34:41 -0400 |
commit | c45a62c24761110505161ce4ecc263f4bfce9c59 (patch) | |
tree | 5cbd14a1a06a96c085619f1ab0c4616b6b8e2fb1 | |
parent | 366f5aea022ea2eccbce5c253e813c1151d53fc1 (diff) | |
download | mongo-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.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/catalog/uuid_catalog.cpp | 28 | ||||
-rw-r--r-- | src/mongo/db/catalog/uuid_catalog.h | 27 | ||||
-rw-r--r-- | src/mongo/db/catalog/uuid_catalog_test.cpp | 45 |
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 |