diff options
author | Gregory Noma <gregory.noma@gmail.com> | 2022-09-14 18:34:02 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-09-16 20:30:14 +0000 |
commit | bfd35c950c9863ef08b8f7adbdf760820ef4da96 (patch) | |
tree | 81c4c63191d7f4f0f04bff28533b3fd591f7abbe /src/mongo | |
parent | ec54f761d043e56cf484de864a89c3645223f878 (diff) | |
download | mongo-bfd35c950c9863ef08b8f7adbdf760820ef4da96.tar.gz |
SERVER-67383 Track resource names using `ResourceCatalog`
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/catalog/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_catalog.cpp | 126 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_catalog.h | 42 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_catalog_test.cpp | 148 | ||||
-rw-r--r-- | src/mongo/db/concurrency/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/db/concurrency/lock_manager.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/concurrency/resource_catalog.cpp | 97 | ||||
-rw-r--r-- | src/mongo/db/concurrency/resource_catalog.h | 61 | ||||
-rw-r--r-- | src/mongo/db/concurrency/resource_catalog_test.cpp | 153 | ||||
-rw-r--r-- | src/mongo/db/storage/kv/storage_engine_test.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/storage/storage_engine.h | 2 | ||||
-rw-r--r-- | src/mongo/db/storage/storage_engine_impl.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/storage/storage_engine_impl.h | 2 | ||||
-rw-r--r-- | src/mongo/db/storage/storage_engine_init.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/storage/storage_engine_mock.h | 2 | ||||
-rw-r--r-- | src/mongo/db/views/view_catalog_test.cpp | 21 |
16 files changed, 378 insertions, 301 deletions
diff --git a/src/mongo/db/catalog/SConscript b/src/mongo/db/catalog/SConscript index 43286e7e458..860d357a631 100644 --- a/src/mongo/db/catalog/SConscript +++ b/src/mongo/db/catalog/SConscript @@ -293,6 +293,7 @@ env.Library( 'views_for_database.cpp', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/concurrency/lock_manager', '$BUILD_DIR/mongo/db/multitenancy', '$BUILD_DIR/mongo/db/profile_filter', '$BUILD_DIR/mongo/db/query/collation/collator_factory_interface', diff --git a/src/mongo/db/catalog/collection_catalog.cpp b/src/mongo/db/catalog/collection_catalog.cpp index c435df0add4..7a98aae38b2 100644 --- a/src/mongo/db/catalog/collection_catalog.cpp +++ b/src/mongo/db/catalog/collection_catalog.cpp @@ -35,6 +35,7 @@ #include "mongo/db/catalog/uncommitted_catalog_updates.h" #include "mongo/db/concurrency/exception_util.h" #include "mongo/db/concurrency/lock_manager_defs.h" +#include "mongo/db/concurrency/resource_catalog.h" #include "mongo/db/multitenancy_gen.h" #include "mongo/db/server_feature_flags_gen.h" #include "mongo/db/server_options.h" @@ -153,16 +154,14 @@ public: break; } case UncommittedCatalogUpdates::Entry::Action::kRenamedCollection: { - writeJobs.push_back( - [& from = entry.nss, &to = entry.renameTo](CollectionCatalog& catalog) { - catalog._collections.erase(from); - - ResourceId oldRid = ResourceId(RESOURCE_COLLECTION, from); - ResourceId newRid = ResourceId(RESOURCE_COLLECTION, to); + writeJobs.push_back([opCtx = _opCtx, &from = entry.nss, &to = entry.renameTo]( + CollectionCatalog& catalog) { + catalog._collections.erase(from); - catalog.removeResource(oldRid, from); - catalog.addResource(newRid, to); - }); + auto& resourceCatalog = ResourceCatalog::get(opCtx->getServiceContext()); + resourceCatalog.remove({RESOURCE_COLLECTION, from}, from); + resourceCatalog.add({RESOURCE_COLLECTION, to}, to); + }); break; } case UncommittedCatalogUpdates::Entry::Action::kDroppedCollection: { @@ -215,18 +214,20 @@ public: break; } case UncommittedCatalogUpdates::Entry::Action::kAddViewResource: { - writeJobs.push_back([& viewName = entry.nss](CollectionCatalog& catalog) { - auto viewRid = ResourceId(RESOURCE_COLLECTION, viewName); - catalog.addResource(viewRid, viewName); - catalog.deregisterUncommittedView(viewName); - }); + writeJobs.push_back( + [opCtx = _opCtx, &viewName = entry.nss](CollectionCatalog& catalog) { + ResourceCatalog::get(opCtx->getServiceContext()) + .add({RESOURCE_COLLECTION, viewName}, viewName); + catalog.deregisterUncommittedView(viewName); + }); break; } case UncommittedCatalogUpdates::Entry::Action::kRemoveViewResource: { - writeJobs.push_back([& viewName = entry.nss](CollectionCatalog& catalog) { - auto viewRid = ResourceId(RESOURCE_COLLECTION, viewName); - catalog.removeResource(viewRid, viewName); - }); + writeJobs.push_back( + [opCtx = _opCtx, &viewName = entry.nss](CollectionCatalog& catalog) { + ResourceCatalog::get(opCtx->getServiceContext()) + .remove({RESOURCE_COLLECTION, viewName}, viewName); + }); break; } case UncommittedCatalogUpdates::Entry::Action::kDroppedIndex: { @@ -857,8 +858,7 @@ void CollectionCatalog::onOpenDatabase(OperationContext* opCtx, void CollectionCatalog::onCloseDatabase(OperationContext* opCtx, DatabaseName dbName) { invariant(opCtx->lockState()->isDbLockedForMode(dbName, MODE_X)); - auto rid = ResourceId(RESOURCE_DATABASE, dbName); - removeResource(rid, dbName); + ResourceCatalog::get(opCtx->getServiceContext()).remove({RESOURCE_DATABASE, dbName}, dbName); _viewsForDatabase.erase(dbName); } @@ -1344,11 +1344,9 @@ void CollectionCatalog::registerCollection(OperationContext* opCtx, invariant(static_cast<size_t>(_stats.internal + _stats.userCollections) == _collections.size()); - auto dbRid = ResourceId(RESOURCE_DATABASE, nss.dbName()); - addResource(dbRid, nss.dbName()); - - auto collRid = ResourceId(RESOURCE_COLLECTION, nss); - addResource(collRid, nss); + auto& resourceCatalog = ResourceCatalog::get(opCtx->getServiceContext()); + resourceCatalog.add({RESOURCE_DATABASE, nss.dbName()}, nss.dbName()); + resourceCatalog.add({RESOURCE_COLLECTION, nss}, nss); } std::shared_ptr<Collection> CollectionCatalog::deregisterCollection(OperationContext* opCtx, @@ -1396,8 +1394,7 @@ std::shared_ptr<Collection> CollectionCatalog::deregisterCollection(OperationCon coll->onDeregisterFromCatalog(opCtx); - auto collRid = ResourceId(RESOURCE_COLLECTION, ns); - removeResource(collRid, ns); + ResourceCatalog::get(opCtx->getServiceContext()).remove({RESOURCE_COLLECTION, ns}, ns); return coll; } @@ -1453,7 +1450,7 @@ void CollectionCatalog::_ensureNamespaceDoesNotExist(OperationContext* opCtx, } } -void CollectionCatalog::deregisterAllCollectionsAndViews() { +void CollectionCatalog::deregisterAllCollectionsAndViews(ServiceContext* svcCtx) { LOGV2(20282, "Deregistering all the collections"); for (auto& entry : _catalog) { auto uuid = entry.first; @@ -1472,7 +1469,7 @@ void CollectionCatalog::deregisterAllCollectionsAndViews() { _dropPendingIndex.clear(); _stats = {}; - _resourceInformation.clear(); + ResourceCatalog::get(svcCtx).clear(); } void CollectionCatalog::clearViews(OperationContext* opCtx, const DatabaseName& dbName) const { @@ -1545,77 +1542,6 @@ CollectionCatalog::iterator CollectionCatalog::end(OperationContext* opCtx) cons return iterator(opCtx, _orderedCollections.end(), *this); } -boost::optional<std::string> CollectionCatalog::lookupResourceName(const ResourceId& rid) const { - invariant(rid.getType() == RESOURCE_DATABASE || rid.getType() == RESOURCE_COLLECTION); - - auto search = _resourceInformation.find(rid); - if (search == _resourceInformation.end()) { - return boost::none; - } - - const std::set<std::string>& namespaces = search->second; - - // When there are multiple namespaces mapped to the same ResourceId, return boost::none as the - // ResourceId does not identify a single namespace. - if (namespaces.size() > 1) { - return boost::none; - } - - return *namespaces.begin(); -} - - -void CollectionCatalog::_removeResource(const ResourceId& rid, const std::string& entry) { - auto search = _resourceInformation.find(rid); - if (search == _resourceInformation.end()) { - return; - } - - std::set<std::string>& namespaces = search->second; - namespaces.erase(entry); - - // Remove the map entry if this is the last namespace in the set for the ResourceId. - if (namespaces.size() == 0) { - _resourceInformation.erase(search); - } -} - -void CollectionCatalog::removeResource(const ResourceId& rid, const NamespaceString& nss) { - invariant(rid.getType() == RESOURCE_COLLECTION); - _removeResource(rid, nss.toStringWithTenantId()); -} - -void CollectionCatalog::removeResource(const ResourceId& rid, const DatabaseName& dbName) { - invariant(rid.getType() == RESOURCE_DATABASE); - _removeResource(rid, dbName.toStringWithTenantId()); -} - -void CollectionCatalog::_addResource(const ResourceId& rid, const std::string& entry) { - auto search = _resourceInformation.find(rid); - if (search == _resourceInformation.end()) { - std::set<std::string> newSet = {entry}; - _resourceInformation.insert(std::make_pair(rid, newSet)); - return; - } - - std::set<std::string>& namespaces = search->second; - if (namespaces.count(entry) > 0) { - return; - } - - namespaces.insert(entry); -} - -void CollectionCatalog::addResource(const ResourceId& rid, const NamespaceString& nss) { - invariant(rid.getType() == RESOURCE_COLLECTION); - _addResource(rid, nss.toStringWithTenantId()); -} - -void CollectionCatalog::addResource(const ResourceId& rid, const DatabaseName& dbName) { - invariant(rid.getType() == RESOURCE_DATABASE); - _addResource(rid, dbName.toStringWithTenantId()); -} - void CollectionCatalog::invariantHasExclusiveAccessToCollection(OperationContext* opCtx, const NamespaceString& nss) { auto& uncommittedCatalogUpdates = UncommittedCatalogUpdates::get(opCtx); diff --git a/src/mongo/db/catalog/collection_catalog.h b/src/mongo/db/catalog/collection_catalog.h index a2892e2a946..80d73fb11fb 100644 --- a/src/mongo/db/catalog/collection_catalog.h +++ b/src/mongo/db/catalog/collection_catalog.h @@ -313,7 +313,7 @@ public: /** * Deregister all the collection objects and view namespaces. */ - void deregisterAllCollectionsAndViews(); + void deregisterAllCollectionsAndViews(ServiceContext* svcCtx); /** * Adds the index entry to the drop pending state in the catalog. @@ -566,33 +566,6 @@ public: iterator end(OperationContext* opCtx) const; /** - * Lookup the name of a resource by its ResourceId. If there are multiple namespaces mapped to - * the same ResourceId entry, we return the boost::none for those namespaces until there is only - * one namespace in the set. If the ResourceId is not found, boost::none is returned. - */ - boost::optional<std::string> lookupResourceName(const ResourceId& rid) const; - - /** - * Removes an existing ResourceId 'rid' with namespace 'nss' from the map. - */ - void removeResource(const ResourceId& rid, const NamespaceString& nss); - - /** - * Removes an existing ResourceId 'rid' with database name 'dbName' from the map. - */ - void removeResource(const ResourceId& rid, const DatabaseName& dbName); - - /** - * Inserts a new ResourceId 'rid' into the map with namespace 'nss'. - */ - void addResource(const ResourceId& rid, const NamespaceString& nss); - - /** - * Inserts a new ResourceId 'rid' into the map with database name 'dbName'. - */ - void addResource(const ResourceId& rid, const DatabaseName& dbName); - - /** * Ensures we have a MODE_X lock on a collection or MODE_IX lock for newly created collections. */ static void invariantHasExclusiveAccessToCollection(OperationContext* opCtx, @@ -641,16 +614,6 @@ private: bool _alreadyClonedForBatchedWriter(const std::shared_ptr<Collection>& collection) const; /** - * Inserts a new ResourceId 'rid' into the map with namespace 'entry'. - */ - void _addResource(const ResourceId& rid, const std::string& entry); - - /** - * Removes an existing ResourceId 'rid' with namespace 'entry' from the map. - */ - void _removeResource(const ResourceId& rid, const std::string& entry); - - /** * Throws 'WriteConflictException' if given namespace is already registered with the catalog, as * either a view or collection. The results will include namespaces which have been registered * by preCommitHooks on other threads, but which have not truly been committed yet. @@ -705,9 +668,6 @@ private: // global lock in at least MODE_IS to read it. uint64_t _epoch = 0; - // Mapping from ResourceId to a set of strings that contains collection and database namespaces. - std::map<ResourceId, std::set<std::string>> _resourceInformation; - /** * Contains non-default database profile settings. New collections, current collections and * views must all be able to access the correct profile settings for the database in which they diff --git a/src/mongo/db/catalog/collection_catalog_test.cpp b/src/mongo/db/catalog/collection_catalog_test.cpp index e48a742b8ec..bba37ae83b6 100644 --- a/src/mongo/db/catalog/collection_catalog_test.cpp +++ b/src/mongo/db/catalog/collection_catalog_test.cpp @@ -36,6 +36,7 @@ #include "mongo/db/catalog/collection_mock.h" #include "mongo/db/catalog_raii.h" #include "mongo/db/concurrency/lock_manager_defs.h" +#include "mongo/db/concurrency/resource_catalog.h" #include "mongo/db/index_builds_coordinator.h" #include "mongo/db/service_context_d_test_fixture.h" #include "mongo/idl/server_parameter_test_util.h" @@ -165,124 +166,6 @@ protected: std::map<std::string, std::map<UUID, CollectionPtr>> dbMap; }; -class CollectionCatalogResourceMapTest : public unittest::Test { -public: - void setUp() { - // The first and second collection namespaces map to the same ResourceId. - firstCollection = NamespaceString(boost::none, "1661880728"); - secondCollection = NamespaceString(boost::none, "1626936312"); - - firstResourceId = ResourceId(RESOURCE_COLLECTION, firstCollection); - secondResourceId = ResourceId(RESOURCE_COLLECTION, secondCollection); - ASSERT_EQ(firstResourceId, secondResourceId); - - thirdCollection = NamespaceString(boost::none, "2930102946"); - thirdResourceId = ResourceId(RESOURCE_COLLECTION, thirdCollection); - ASSERT_NE(firstResourceId, thirdResourceId); - } - -protected: - NamespaceString firstCollection; - ResourceId firstResourceId; - - NamespaceString secondCollection; - ResourceId secondResourceId; - - NamespaceString thirdCollection; - ResourceId thirdResourceId; - - CollectionCatalog catalog; -}; - -TEST_F(CollectionCatalogResourceMapTest, EmptyTest) { - boost::optional<std::string> resource = catalog.lookupResourceName(firstResourceId); - ASSERT_EQ(boost::none, resource); - - catalog.removeResource(secondResourceId, secondCollection); - resource = catalog.lookupResourceName(secondResourceId); - ASSERT_EQ(boost::none, resource); -} - -TEST_F(CollectionCatalogResourceMapTest, InsertTest) { - catalog.addResource(firstResourceId, firstCollection); - boost::optional<std::string> resource = catalog.lookupResourceName(thirdResourceId); - ASSERT_EQ(boost::none, resource); - - catalog.addResource(thirdResourceId, thirdCollection); - - resource = catalog.lookupResourceName(firstResourceId); - ASSERT_EQ(firstCollection.toStringWithTenantId(), *resource); - - resource = catalog.lookupResourceName(thirdResourceId); - ASSERT_EQ(thirdCollection.toStringWithTenantId(), resource); -} - -TEST_F(CollectionCatalogResourceMapTest, RemoveTest) { - catalog.addResource(firstResourceId, firstCollection); - catalog.addResource(thirdResourceId, thirdCollection); - - // This fails to remove the resource because of an invalid namespace. - catalog.removeResource(firstResourceId, NamespaceString(boost::none, "BadNamespace")); - boost::optional<std::string> resource = catalog.lookupResourceName(firstResourceId); - ASSERT_EQ(firstCollection.toStringWithTenantId(), *resource); - - catalog.removeResource(firstResourceId, firstCollection); - catalog.removeResource(firstResourceId, firstCollection); - catalog.removeResource(thirdResourceId, thirdCollection); - - resource = catalog.lookupResourceName(firstResourceId); - ASSERT_EQ(boost::none, resource); - - resource = catalog.lookupResourceName(thirdResourceId); - ASSERT_EQ(boost::none, resource); -} - -TEST_F(CollectionCatalogResourceMapTest, CollisionTest) { - // firstCollection and secondCollection map to the same ResourceId. - catalog.addResource(firstResourceId, firstCollection); - catalog.addResource(secondResourceId, secondCollection); - - // Looking up the namespace on a ResourceId while it has a collision should - // return the empty string. - boost::optional<std::string> resource = catalog.lookupResourceName(firstResourceId); - ASSERT_EQ(boost::none, resource); - - resource = catalog.lookupResourceName(secondResourceId); - ASSERT_EQ(boost::none, resource); - - // We remove a namespace, resolving the collision. - catalog.removeResource(firstResourceId, firstCollection); - resource = catalog.lookupResourceName(secondResourceId); - ASSERT_EQ(secondCollection.toStringWithTenantId(), *resource); - - // Adding the same namespace twice does not create a collision. - catalog.addResource(secondResourceId, secondCollection); - resource = catalog.lookupResourceName(secondResourceId); - ASSERT_EQ(secondCollection.toStringWithTenantId(), *resource); - - // The map should function normally for entries without collisions. - catalog.addResource(firstResourceId, firstCollection); - resource = catalog.lookupResourceName(secondResourceId); - ASSERT_EQ(boost::none, resource); - - catalog.addResource(thirdResourceId, thirdCollection); - resource = catalog.lookupResourceName(thirdResourceId); - ASSERT_EQ(thirdCollection.toStringWithTenantId(), *resource); - - catalog.removeResource(thirdResourceId, thirdCollection); - resource = catalog.lookupResourceName(thirdResourceId); - ASSERT_EQ(boost::none, resource); - - catalog.removeResource(firstResourceId, firstCollection); - catalog.removeResource(secondResourceId, secondCollection); - - resource = catalog.lookupResourceName(firstResourceId); - ASSERT_EQ(boost::none, resource); - - resource = catalog.lookupResourceName(secondResourceId); - ASSERT_EQ(boost::none, resource); -} - class CollectionCatalogResourceTest : public ServiceContextMongoDTest { public: void setUp() { @@ -305,7 +188,7 @@ public: auto collName = coll->ns(); ResourceId rid(RESOURCE_COLLECTION, collName); - ASSERT_NE(catalog.lookupResourceName(rid), boost::none); + ASSERT_NE(ResourceCatalog::get(getServiceContext()).name(rid), boost::none); numEntries++; } ASSERT_EQ(5, numEntries); @@ -344,23 +227,23 @@ protected: }; TEST_F(CollectionCatalogResourceTest, RemoveAllResources) { - catalog.deregisterAllCollectionsAndViews(); + catalog.deregisterAllCollectionsAndViews(getServiceContext()); const DatabaseName dbName = DatabaseName(boost::none, "resourceDb"); auto rid = ResourceId(RESOURCE_DATABASE, dbName); - ASSERT_EQ(boost::none, catalog.lookupResourceName(rid)); + ASSERT_EQ(boost::none, ResourceCatalog::get(getServiceContext()).name(rid)); for (int i = 0; i < 5; i++) { NamespaceString nss("resourceDb", "coll" + std::to_string(i)); rid = ResourceId(RESOURCE_COLLECTION, nss); - ASSERT_EQ(boost::none, catalog.lookupResourceName((rid))); + ASSERT_EQ(boost::none, ResourceCatalog::get(getServiceContext()).name(rid)); } } TEST_F(CollectionCatalogResourceTest, LookupDatabaseResource) { const DatabaseName dbName = DatabaseName(boost::none, "resourceDb"); auto rid = ResourceId(RESOURCE_DATABASE, dbName); - boost::optional<std::string> ridStr = catalog.lookupResourceName(rid); + auto ridStr = ResourceCatalog::get(getServiceContext()).name(rid); ASSERT(ridStr); ASSERT(ridStr->find(dbName.toStringWithTenantId()) != std::string::npos); @@ -369,13 +252,13 @@ TEST_F(CollectionCatalogResourceTest, LookupDatabaseResource) { TEST_F(CollectionCatalogResourceTest, LookupMissingDatabaseResource) { const DatabaseName dbName = DatabaseName(boost::none, "missingDb"); auto rid = ResourceId(RESOURCE_DATABASE, dbName); - ASSERT(!catalog.lookupResourceName(rid)); + ASSERT(!ResourceCatalog::get(getServiceContext()).name(rid)); } TEST_F(CollectionCatalogResourceTest, LookupCollectionResource) { const NamespaceString collNs = NamespaceString(boost::none, "resourceDb.coll1"); auto rid = ResourceId(RESOURCE_COLLECTION, collNs); - boost::optional<std::string> ridStr = catalog.lookupResourceName(rid); + auto ridStr = ResourceCatalog::get(getServiceContext()).name(rid); ASSERT(ridStr); ASSERT(ridStr->find(collNs.toStringWithTenantId()) != std::string::npos); @@ -384,7 +267,7 @@ TEST_F(CollectionCatalogResourceTest, LookupCollectionResource) { TEST_F(CollectionCatalogResourceTest, LookupMissingCollectionResource) { const NamespaceString nss = NamespaceString(boost::none, "resourceDb.coll5"); auto rid = ResourceId(RESOURCE_COLLECTION, nss); - ASSERT(!catalog.lookupResourceName(rid)); + ASSERT(!ResourceCatalog::get(getServiceContext()).name(rid)); } TEST_F(CollectionCatalogResourceTest, RemoveCollection) { @@ -392,7 +275,7 @@ TEST_F(CollectionCatalogResourceTest, RemoveCollection) { auto coll = catalog.lookupCollectionByNamespace(opCtx.get(), NamespaceString(collNs)); catalog.deregisterCollection(opCtx.get(), coll->uuid(), /*isDropPending=*/false); auto rid = ResourceId(RESOURCE_COLLECTION, collNs); - ASSERT(!catalog.lookupResourceName(rid)); + ASSERT(!ResourceCatalog::get(getServiceContext()).name(rid)); } // Create an iterator over the CollectionCatalog and assert that all collections are present. @@ -610,11 +493,6 @@ TEST_F(CollectionCatalogTest, CollectionCatalogEpoch) { ASSERT_EQ(originalEpoch + 1, incrementedEpoch); } -DEATH_TEST_F(CollectionCatalogResourceTest, AddInvalidResourceType, "invariant") { - auto rid = ResourceId(RESOURCE_GLOBAL, 0); - catalog.addResource(rid, NamespaceString(boost::none, "")); -} - TEST_F(CollectionCatalogTest, GetAllCollectionNamesAndGetAllDbNames) { NamespaceString aColl("dbA", "collA"); NamespaceString b1Coll("dbB", "collB1"); @@ -645,7 +523,7 @@ TEST_F(CollectionCatalogTest, GetAllCollectionNamesAndGetAllDbNames) { DatabaseName(boost::none, "testdb")}; ASSERT(catalog.getAllDbNames() == dbNames); - catalog.deregisterAllCollectionsAndViews(); + catalog.deregisterAllCollectionsAndViews(getServiceContext()); } // Test setting and fetching the profile level for a database. @@ -739,7 +617,7 @@ TEST_F(CollectionCatalogTest, GetAllCollectionNamesAndGetAllDbNamesWithUncommitt std::vector<DatabaseName> dbList = {DatabaseName(boost::none, "testdb")}; ASSERT(catalog.getAllDbNames() == dbList); - catalog.deregisterAllCollectionsAndViews(); + catalog.deregisterAllCollectionsAndViews(getServiceContext()); } class ForEachCollectionFromDbTest : public CatalogTestFixture { @@ -915,7 +793,7 @@ public: CollectionOptions options; options.uuid.emplace(UUID::gen()); - auto storageEngine = opCtx->getServiceContext()->getStorageEngine(); + auto storageEngine = getServiceContext()->getStorageEngine(); std::pair<RecordId, std::unique_ptr<RecordStore>> catalogIdRecordStorePair = uassertStatusOK(storageEngine->getCatalog()->createCollection( opCtx, nss, options, /*allocateDefaultSpace=*/true)); diff --git a/src/mongo/db/concurrency/SConscript b/src/mongo/db/concurrency/SConscript index b902468ada9..37880a0c061 100644 --- a/src/mongo/db/concurrency/SConscript +++ b/src/mongo/db/concurrency/SConscript @@ -53,6 +53,7 @@ env.Library( 'lock_state.cpp', 'lock_stats.cpp', 'replication_state_transition_lock_guard.cpp', + 'resource_catalog.cpp', ], LIBDEPS=[ '$BUILD_DIR/mongo/db/service_context', @@ -64,7 +65,6 @@ env.Library( 'lock_manager_defs', ], LIBDEPS_PRIVATE=[ - '$BUILD_DIR/mongo/db/catalog/collection_catalog', '$BUILD_DIR/mongo/db/concurrency/flow_control_ticketholder', '$BUILD_DIR/mongo/db/server_base', ], @@ -98,6 +98,7 @@ env.CppUnitTest( 'lock_manager_test.cpp', 'lock_state_test.cpp', 'lock_stats_test.cpp', + 'resource_catalog_test.cpp', ], LIBDEPS=[ '$BUILD_DIR/mongo/db/auth/authmocks', diff --git a/src/mongo/db/concurrency/lock_manager.cpp b/src/mongo/db/concurrency/lock_manager.cpp index 4bd35cb207e..fe3acad56b5 100644 --- a/src/mongo/db/concurrency/lock_manager.cpp +++ b/src/mongo/db/concurrency/lock_manager.cpp @@ -40,9 +40,9 @@ #include "mongo/base/static_assert.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/config.h" -#include "mongo/db/catalog/collection_catalog.h" #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/concurrency/locker.h" +#include "mongo/db/concurrency/resource_catalog.h" #include "mongo/db/service_context.h" #include "mongo/logv2/log.h" #include "mongo/util/assert_util.h" @@ -975,9 +975,7 @@ std::string ResourceId::toString() const { } if (getType() == RESOURCE_DATABASE || getType() == RESOURCE_COLLECTION) { - auto catalog = CollectionCatalog::get(getGlobalServiceContext()); - boost::optional<std::string> resourceName = catalog->lookupResourceName(*this); - if (resourceName) { + if (auto resourceName = ResourceCatalog::get(getGlobalServiceContext()).name(*this)) { ss << ", " << *resourceName; } } diff --git a/src/mongo/db/concurrency/resource_catalog.cpp b/src/mongo/db/concurrency/resource_catalog.cpp new file mode 100644 index 00000000000..62183c3a4f8 --- /dev/null +++ b/src/mongo/db/concurrency/resource_catalog.cpp @@ -0,0 +1,97 @@ +/** + * Copyright (C) 2022-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/db/concurrency/resource_catalog.h" + +#include "mongo/db/service_context.h" + +namespace mongo { +namespace { +const auto getResourceCatalog = ServiceContext::declareDecoration<ResourceCatalog>(); +} // namespace + +ResourceCatalog& ResourceCatalog::get(ServiceContext* svcCtx) { + return getResourceCatalog(svcCtx); +} + +void ResourceCatalog::add(ResourceId id, const NamespaceString& ns) { + invariant(id.getType() == RESOURCE_COLLECTION); + _add(id, ns.toStringWithTenantId()); +} + +void ResourceCatalog::add(ResourceId id, const DatabaseName& dbName) { + invariant(id.getType() == RESOURCE_DATABASE); + _add(id, dbName.toStringWithTenantId()); +} + +void ResourceCatalog::_add(ResourceId id, std::string name) { + stdx::lock_guard<Latch> lk{_mutex}; + _resources[id].insert(std::move(name)); +} + +void ResourceCatalog::remove(ResourceId id, const NamespaceString& ns) { + invariant(id.getType() == RESOURCE_COLLECTION); + _remove(id, ns.toStringWithTenantId()); +} + +void ResourceCatalog::remove(ResourceId id, const DatabaseName& dbName) { + invariant(id.getType() == RESOURCE_DATABASE); + _remove(id, dbName.toStringWithTenantId()); +} + +void ResourceCatalog::_remove(ResourceId id, const std::string& name) { + stdx::lock_guard<Latch> lk{_mutex}; + + auto it = _resources.find(id); + if (it == _resources.end()) { + return; + } + + it->second.erase(name); + + if (it->second.empty()) { + _resources.erase(it); + } +} + +void ResourceCatalog::clear() { + stdx::lock_guard<Latch> lk{_mutex}; + _resources.clear(); +} + +boost::optional<std::string> ResourceCatalog::name(ResourceId id) const { + invariant(id.getType() == RESOURCE_DATABASE || id.getType() == RESOURCE_COLLECTION); + stdx::lock_guard<Latch> lk{_mutex}; + + auto it = _resources.find(id); + return it == _resources.end() || it->second.size() > 1 + ? boost::none + : boost::make_optional(*it->second.begin()); +} +} // namespace mongo diff --git a/src/mongo/db/concurrency/resource_catalog.h b/src/mongo/db/concurrency/resource_catalog.h new file mode 100644 index 00000000000..44f684053b4 --- /dev/null +++ b/src/mongo/db/concurrency/resource_catalog.h @@ -0,0 +1,61 @@ +/** + * Copyright (C) 2022-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/concurrency/lock_manager_defs.h" + +namespace mongo { +class ResourceCatalog { +public: + static ResourceCatalog& get(ServiceContext* scvCtx); + + void add(ResourceId id, const NamespaceString& ns); + void add(ResourceId id, const DatabaseName& dbName); + + void remove(ResourceId id, const NamespaceString& ns); + void remove(ResourceId id, const DatabaseName& dbName); + + void clear(); + + /** + * Returns the name of a resource by its id. If the id is not found or it maps to multiple + * resources, returns boost::none. + */ + boost::optional<std::string> name(ResourceId id) const; + +private: + void _add(ResourceId id, std::string name); + + void _remove(ResourceId id, const std::string& name); + + mutable Mutex _mutex = MONGO_MAKE_LATCH("ResourceCatalog"); + stdx::unordered_map<ResourceId, StringSet> _resources; +}; +} // namespace mongo diff --git a/src/mongo/db/concurrency/resource_catalog_test.cpp b/src/mongo/db/concurrency/resource_catalog_test.cpp new file mode 100644 index 00000000000..99752d3acd4 --- /dev/null +++ b/src/mongo/db/concurrency/resource_catalog_test.cpp @@ -0,0 +1,153 @@ +/** + * Copyright (C) 2022-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/db/concurrency/resource_catalog.h" +#include "mongo/unittest/death_test.h" +#include "mongo/unittest/unittest.h" + +namespace mongo { +namespace { +class ResourceCatalogTest : public unittest::Test { +public: + void setUp() { + ASSERT_EQ(firstResourceId, secondResourceId); + ASSERT_NE(firstResourceId, thirdResourceId); + } + +protected: + NamespaceString firstCollection{boost::none, "1661880728"}; + ResourceId firstResourceId{RESOURCE_COLLECTION, firstCollection}; + + NamespaceString secondCollection{boost::none, "1626936312"}; + ResourceId secondResourceId{RESOURCE_COLLECTION, secondCollection}; + + NamespaceString thirdCollection{boost::none, "2930102946"}; + ResourceId thirdResourceId{RESOURCE_COLLECTION, thirdCollection}; + + ResourceCatalog catalog; +}; + +TEST_F(ResourceCatalogTest, EmptyTest) { + auto resource = catalog.name(firstResourceId); + ASSERT_EQ(boost::none, resource); + + catalog.remove(secondResourceId, secondCollection); + resource = catalog.name(secondResourceId); + ASSERT_EQ(boost::none, resource); +} + +TEST_F(ResourceCatalogTest, InsertTest) { + catalog.add(firstResourceId, firstCollection); + auto resource = catalog.name(thirdResourceId); + ASSERT_EQ(boost::none, resource); + + catalog.add(thirdResourceId, thirdCollection); + + resource = catalog.name(firstResourceId); + ASSERT_EQ(firstCollection.toStringWithTenantId(), *resource); + + resource = catalog.name(thirdResourceId); + ASSERT_EQ(thirdCollection.toStringWithTenantId(), resource); +} + +TEST_F(ResourceCatalogTest, RemoveTest) { + catalog.add(firstResourceId, firstCollection); + catalog.add(thirdResourceId, thirdCollection); + + // This fails to remove the resource because of an invalid namespace. + catalog.remove(firstResourceId, NamespaceString(boost::none, "BadNamespace")); + auto resource = catalog.name(firstResourceId); + ASSERT_EQ(firstCollection.toStringWithTenantId(), *resource); + + catalog.remove(firstResourceId, firstCollection); + catalog.remove(firstResourceId, firstCollection); + catalog.remove(thirdResourceId, thirdCollection); + + resource = catalog.name(firstResourceId); + ASSERT_EQ(boost::none, resource); + + resource = catalog.name(thirdResourceId); + ASSERT_EQ(boost::none, resource); +} + +TEST_F(ResourceCatalogTest, CollisionTest) { + // firstCollection and secondCollection map to the same ResourceId. + catalog.add(firstResourceId, firstCollection); + catalog.add(secondResourceId, secondCollection); + + // Looking up the namespace on a ResourceId while it has a collision should + // return the empty string. + auto resource = catalog.name(firstResourceId); + ASSERT_EQ(boost::none, resource); + + resource = catalog.name(secondResourceId); + ASSERT_EQ(boost::none, resource); + + // We remove a namespace, resolving the collision. + catalog.remove(firstResourceId, firstCollection); + resource = catalog.name(secondResourceId); + ASSERT_EQ(secondCollection.toStringWithTenantId(), *resource); + + // Adding the same namespace twice does not create a collision. + catalog.add(secondResourceId, secondCollection); + resource = catalog.name(secondResourceId); + ASSERT_EQ(secondCollection.toStringWithTenantId(), *resource); + + // The map should function normally for entries without collisions. + catalog.add(firstResourceId, firstCollection); + resource = catalog.name(secondResourceId); + ASSERT_EQ(boost::none, resource); + + catalog.add(thirdResourceId, thirdCollection); + resource = catalog.name(thirdResourceId); + ASSERT_EQ(thirdCollection.toStringWithTenantId(), *resource); + + catalog.remove(thirdResourceId, thirdCollection); + resource = catalog.name(thirdResourceId); + ASSERT_EQ(boost::none, resource); + + catalog.remove(firstResourceId, firstCollection); + catalog.remove(secondResourceId, secondCollection); + + resource = catalog.name(firstResourceId); + ASSERT_EQ(boost::none, resource); + + resource = catalog.name(secondResourceId); + ASSERT_EQ(boost::none, resource); +} + +DEATH_TEST_F(ResourceCatalogTest, AddDatabaseInvalidResourceType, "invariant") { + catalog.add({RESOURCE_GLOBAL, 0}, DatabaseName{"db"}); +} + +DEATH_TEST_F(ResourceCatalogTest, AddCollectionInvalidResourceType, "invariant") { + catalog.add({RESOURCE_GLOBAL, 0}, NamespaceString{"db.coll"}); +} +} // namespace +} // namespace mongo diff --git a/src/mongo/db/storage/kv/storage_engine_test.cpp b/src/mongo/db/storage/kv/storage_engine_test.cpp index eced5c5c3ff..2a143839964 100644 --- a/src/mongo/db/storage/kv/storage_engine_test.cpp +++ b/src/mongo/db/storage/kv/storage_engine_test.cpp @@ -569,7 +569,7 @@ public: } void tearDown() { - _storageEngine->cleanShutdown(); + _storageEngine->cleanShutdown(getServiceContext()); _storageEngine.reset(); ServiceContextTest::tearDown(); diff --git a/src/mongo/db/storage/storage_engine.h b/src/mongo/db/storage/storage_engine.h index 8f0425a8835..a67a04e7aa7 100644 --- a/src/mongo/db/storage/storage_engine.h +++ b/src/mongo/db/storage/storage_engine.h @@ -380,7 +380,7 @@ public: * On error, the storage engine should assert and crash. * There is intentionally no uncleanShutdown(). */ - virtual void cleanShutdown() = 0; + virtual void cleanShutdown(ServiceContext* svcCtx) = 0; /** * Returns the SnapshotManager for this StorageEngine or NULL if not supported. diff --git a/src/mongo/db/storage/storage_engine_impl.cpp b/src/mongo/db/storage/storage_engine_impl.cpp index 81c1f192bcd..5dbf45070e5 100644 --- a/src/mongo/db/storage/storage_engine_impl.cpp +++ b/src/mongo/db/storage/storage_engine_impl.cpp @@ -406,8 +406,9 @@ void StorageEngineImpl::closeCatalog(OperationContext* opCtx) { _dumpCatalog(opCtx); } - CollectionCatalog::write( - opCtx, [&](CollectionCatalog& catalog) { catalog.deregisterAllCollectionsAndViews(); }); + CollectionCatalog::write(opCtx, [opCtx](CollectionCatalog& catalog) { + catalog.deregisterAllCollectionsAndViews(opCtx->getServiceContext()); + }); _catalog.reset(); _catalogRecordStore.reset(); @@ -791,14 +792,14 @@ std::string StorageEngineImpl::getFilesystemPathForDb(const DatabaseName& dbName return _catalog->getFilesystemPathForDb(dbName.toString()); } -void StorageEngineImpl::cleanShutdown() { +void StorageEngineImpl::cleanShutdown(ServiceContext* svcCtx) { if (_timestampMonitor) { _timestampMonitor->clearListeners(); } - CollectionCatalog::write(getGlobalServiceContext(), [](CollectionCatalog& catalog) { + CollectionCatalog::write(svcCtx, [svcCtx](CollectionCatalog& catalog) { catalog.onCloseCatalog(); - catalog.deregisterAllCollectionsAndViews(); + catalog.deregisterAllCollectionsAndViews(svcCtx); }); _catalog.reset(); diff --git a/src/mongo/db/storage/storage_engine_impl.h b/src/mongo/db/storage/storage_engine_impl.h index bfd08a7f98a..f95b86f32a7 100644 --- a/src/mongo/db/storage/storage_engine_impl.h +++ b/src/mongo/db/storage/storage_engine_impl.h @@ -118,7 +118,7 @@ public: virtual std::unique_ptr<TemporaryRecordStore> makeTemporaryRecordStoreFromExistingIdent( OperationContext* opCtx, StringData ident) override; - virtual void cleanShutdown() override; + virtual void cleanShutdown(ServiceContext* svcCtx) override; virtual void setStableTimestamp(Timestamp stableTimestamp, bool force = false) override; diff --git a/src/mongo/db/storage/storage_engine_init.cpp b/src/mongo/db/storage/storage_engine_init.cpp index 28d88eb30d2..6af9d37d139 100644 --- a/src/mongo/db/storage/storage_engine_init.cpp +++ b/src/mongo/db/storage/storage_engine_init.cpp @@ -227,7 +227,7 @@ void shutdownGlobalStorageEngineCleanly(ServiceContext* service, // are shutting the storage engine down. Additionally, we need to terminate any background // threads as they may be holding onto an OperationContext, as opposed to pausing them. StorageControl::stopStorageControls(service, errorToReport, /*forRestart=*/false); - storageEngine->cleanShutdown(); + storageEngine->cleanShutdown(service); auto& lockFile = StorageEngineLockFile::get(service); if (lockFile) { lockFile->clearPidAndUnlock(); diff --git a/src/mongo/db/storage/storage_engine_mock.h b/src/mongo/db/storage/storage_engine_mock.h index 697bcab7900..66665f9edec 100644 --- a/src/mongo/db/storage/storage_engine_mock.h +++ b/src/mongo/db/storage/storage_engine_mock.h @@ -100,7 +100,7 @@ public: OperationContext* opCtx, StringData ident) final { return {}; } - void cleanShutdown() final {} + void cleanShutdown(ServiceContext* svcCtx) final {} SnapshotManager* getSnapshotManager() const final { return nullptr; } diff --git a/src/mongo/db/views/view_catalog_test.cpp b/src/mongo/db/views/view_catalog_test.cpp index c81f29f2bbe..140af5331a4 100644 --- a/src/mongo/db/views/view_catalog_test.cpp +++ b/src/mongo/db/views/view_catalog_test.cpp @@ -42,7 +42,7 @@ #include "mongo/db/catalog/catalog_test_fixture.h" #include "mongo/db/catalog/collection_catalog.h" #include "mongo/db/catalog_raii.h" -#include "mongo/db/concurrency/lock_manager_defs.h" +#include "mongo/db/concurrency/resource_catalog.h" #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context.h" #include "mongo/db/query/collation/collator_factory_interface.h" @@ -526,7 +526,7 @@ TEST_F(ViewCatalogFixture, LookupRIDExistingView) { ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); auto resourceID = ResourceId(RESOURCE_COLLECTION, NamespaceString(boost::none, "db.view")); - ASSERT(getCatalog()->lookupResourceName(resourceID).value() == "db.view"); + ASSERT_EQ(ResourceCatalog::get(getServiceContext()).name(resourceID), std::string{"db.view"}); } TEST_F(ViewCatalogFixture, LookupRIDExistingViewRollback) { @@ -549,7 +549,7 @@ TEST_F(ViewCatalogFixture, LookupRIDExistingViewRollback) { view_catalog_helpers::validatePipeline)); } auto resourceID = ResourceId(RESOURCE_COLLECTION, NamespaceString(boost::none, "db.view")); - ASSERT(!getCatalog()->lookupResourceName(resourceID)); + ASSERT(!ResourceCatalog::get(getServiceContext()).name(resourceID)); } TEST_F(ViewCatalogFixture, LookupRIDAfterDrop) { @@ -560,7 +560,7 @@ TEST_F(ViewCatalogFixture, LookupRIDAfterDrop) { ASSERT_OK(dropView(operationContext(), viewName)); auto resourceID = ResourceId(RESOURCE_COLLECTION, NamespaceString(boost::none, "db.view")); - ASSERT(!getCatalog()->lookupResourceName(resourceID)); + ASSERT(!ResourceCatalog::get(getServiceContext()).name(resourceID)); } TEST_F(ViewCatalogFixture, LookupRIDAfterDropRollback) { @@ -572,7 +572,8 @@ TEST_F(ViewCatalogFixture, LookupRIDAfterDropRollback) { WriteUnitOfWork wunit(operationContext()); ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); wunit.commit(); - ASSERT(getCatalog()->lookupResourceName(resourceID).value() == viewName.ns()); + ASSERT_EQ(ResourceCatalog::get(getServiceContext()).name(resourceID).value(), + viewName.ns()); } { @@ -588,7 +589,7 @@ TEST_F(ViewCatalogFixture, LookupRIDAfterDropRollback) { // Do not commit, rollback. } // Make sure drop was rolled back and view is still in catalog. - ASSERT(getCatalog()->lookupResourceName(resourceID).value() == viewName.ns()); + ASSERT_EQ(ResourceCatalog::get(getServiceContext()).name(resourceID), viewName.ns()); } TEST_F(ViewCatalogFixture, LookupRIDAfterModify) { @@ -598,7 +599,7 @@ TEST_F(ViewCatalogFixture, LookupRIDAfterModify) { auto resourceID = ResourceId(RESOURCE_COLLECTION, NamespaceString(boost::none, "db.view")); ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); ASSERT_OK(modifyView(operationContext(), viewName, viewOn, emptyPipeline)); - ASSERT(getCatalog()->lookupResourceName(resourceID).value() == viewName.ns()); + ASSERT_EQ(ResourceCatalog::get(getServiceContext()).name(resourceID), viewName.ns()); } TEST_F(ViewCatalogFixture, LookupRIDAfterModifyRollback) { @@ -610,7 +611,7 @@ TEST_F(ViewCatalogFixture, LookupRIDAfterModifyRollback) { WriteUnitOfWork wunit(operationContext()); ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); wunit.commit(); - ASSERT(getCatalog()->lookupResourceName(resourceID).value() == viewName.ns()); + ASSERT_EQ(ResourceCatalog::get(getServiceContext()).name(resourceID), viewName.ns()); } { @@ -627,11 +628,11 @@ TEST_F(ViewCatalogFixture, LookupRIDAfterModifyRollback) { viewOn, emptyPipeline, view_catalog_helpers::validatePipeline)); - ASSERT(getCatalog()->lookupResourceName(resourceID).value() == viewName.ns()); + ASSERT_EQ(ResourceCatalog::get(getServiceContext()).name(resourceID), viewName.ns()); // Do not commit, rollback. } // Make sure view resource is still available after rollback. - ASSERT(getCatalog()->lookupResourceName(resourceID).value() == viewName.ns()); + ASSERT_EQ(ResourceCatalog::get(getServiceContext()).name(resourceID), viewName.ns()); } TEST_F(ViewCatalogFixture, CreateViewThenDropAndLookup) { |