diff options
author | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2019-07-12 09:50:46 -0400 |
---|---|---|
committer | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2019-07-15 10:47:12 -0400 |
commit | 71fced4ef1bdbc1e5b517057eb15be256eaf0ba7 (patch) | |
tree | eaa12252283a4702203f9865796a73ede5b011b3 /src/mongo/db/views | |
parent | 903207938dc05f9e3f4ca546232d8a7ceda99e4c (diff) | |
download | mongo-71fced4ef1bdbc1e5b517057eb15be256eaf0ba7.tar.gz |
SERVER-41041 ViewCatalog should actively reload after changes
Diffstat (limited to 'src/mongo/db/views')
-rw-r--r-- | src/mongo/db/views/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/db/views/durable_view_catalog.cpp | 31 | ||||
-rw-r--r-- | src/mongo/db/views/durable_view_catalog.h | 8 | ||||
-rw-r--r-- | src/mongo/db/views/view_catalog.cpp | 103 | ||||
-rw-r--r-- | src/mongo/db/views/view_catalog.h | 56 | ||||
-rw-r--r-- | src/mongo/db/views/view_catalog_test.cpp | 394 |
6 files changed, 337 insertions, 257 deletions
diff --git a/src/mongo/db/views/SConscript b/src/mongo/db/views/SConscript index e4b769b075a..00aba3711cb 100644 --- a/src/mongo/db/views/SConscript +++ b/src/mongo/db/views/SConscript @@ -54,7 +54,9 @@ env.CppUnitTest( ], LIBDEPS=[ 'views', + 'views_mongod', '$BUILD_DIR/mongo/db/auth/authmocks', + '$BUILD_DIR/mongo/db/catalog/catalog_test_fixture', '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', '$BUILD_DIR/mongo/db/query/query_test_service_context', '$BUILD_DIR/mongo/db/repl/replmocks', diff --git a/src/mongo/db/views/durable_view_catalog.cpp b/src/mongo/db/views/durable_view_catalog.cpp index 30206b54d91..193f7a6f432 100644 --- a/src/mongo/db/views/durable_view_catalog.cpp +++ b/src/mongo/db/views/durable_view_catalog.cpp @@ -56,11 +56,38 @@ namespace mongo { void DurableViewCatalog::onExternalChange(OperationContext* opCtx, const NamespaceString& name) { dassert(opCtx->lockState()->isDbLockedForMode(name.db(), MODE_IX)); + dassert(opCtx->lockState()->isCollectionLockedForMode( + NamespaceString(name.db(), NamespaceString::kSystemDotViewsCollectionName), MODE_X)); auto databaseHolder = DatabaseHolder::get(opCtx); auto db = databaseHolder->getDb(opCtx, name.db()); if (db) { - opCtx->recoveryUnit()->onCommit( - [db](boost::optional<Timestamp>) { ViewCatalog::get(db)->invalidate(); }); + // On an external change, an invalid view definition can be detected when the view catalog + // is reloaded. This will prevent any further usage of the view catalog until the invalid + // view definitions are removed. We use kValidateDurableViews here to catch any invalid view + // definitions in the view catalog to make it unusable for subsequent callers. + ViewCatalog* viewCatalog = ViewCatalog::get(db); + if (viewCatalog->shouldIgnoreExternalChange(opCtx, name)) { + return; + } + + viewCatalog->reload(opCtx, ViewCatalogLookupBehavior::kValidateDurableViews).ignore(); + } +} + +void DurableViewCatalog::onSystemViewsCollectionDrop(OperationContext* opCtx, + const NamespaceString& name) { + dassert(opCtx->lockState()->isDbLockedForMode(name.db(), MODE_IX)); + dassert(opCtx->lockState()->isCollectionLockedForMode( + NamespaceString(name.db(), NamespaceString::kSystemDotViewsCollectionName), MODE_X)); + dassert(name.coll() == NamespaceString::kSystemDotViewsCollectionName); + + auto databaseHolder = DatabaseHolder::get(opCtx); + auto db = databaseHolder->getDb(opCtx, name.db()); + if (db) { + // If the 'system.views' collection is dropped, we need to clear the in-memory state of the + // view catalog. + ViewCatalog* viewCatalog = ViewCatalog::get(db); + viewCatalog->clear(); } } diff --git a/src/mongo/db/views/durable_view_catalog.h b/src/mongo/db/views/durable_view_catalog.h index 03bacb2f3fb..62fd5db2c4d 100644 --- a/src/mongo/db/views/durable_view_catalog.h +++ b/src/mongo/db/views/durable_view_catalog.h @@ -63,10 +63,16 @@ public: /** * Thread-safe method to mark a catalog name was changed. This will cause the in-memory - * view catalog to be marked invalid + * view catalog to be reloaded immediately. */ static void onExternalChange(OperationContext* opCtx, const NamespaceString& name); + /** + * Thread-safe method to clear the in-memory state of the view catalog when the 'system.views' + * collection is dropped. + */ + static void onSystemViewsCollectionDrop(OperationContext* opCtx, const NamespaceString& name); + using Callback = std::function<Status(const BSONObj& view)>; virtual void iterate(OperationContext* opCtx, Callback callback) = 0; virtual void iterateIgnoreInvalidEntries(OperationContext* opCtx, Callback callback) = 0; diff --git a/src/mongo/db/views/view_catalog.cpp b/src/mongo/db/views/view_catalog.cpp index 2de991d959e..237a9495cf2 100644 --- a/src/mongo/db/views/view_catalog.cpp +++ b/src/mongo/db/views/view_catalog.cpp @@ -82,25 +82,23 @@ void ViewCatalog::set(Database* db, std::unique_ptr<ViewCatalog> catalog) { getViewCatalog(db) = std::move(catalog); } -Status ViewCatalog::reloadIfNeeded(OperationContext* opCtx) { +Status ViewCatalog::reload(OperationContext* opCtx, ViewCatalogLookupBehavior lookupBehavior) { Lock::CollectionLock systemViewsLock( opCtx, NamespaceString(_durable->getName(), NamespaceString::kSystemDotViewsCollectionName), MODE_IS); stdx::unique_lock<stdx::mutex> lk(_mutex); - return _reloadIfNeeded(lk, opCtx, ViewCatalogLookupBehavior::kValidateDurableViews); + return _reload(lk, opCtx, ViewCatalogLookupBehavior::kValidateDurableViews); } -Status ViewCatalog::_reloadIfNeeded(WithLock lk, - OperationContext* opCtx, - ViewCatalogLookupBehavior lookupBehavior) { - if (_valid.load()) - return Status::OK(); - +Status ViewCatalog::_reload(WithLock, + OperationContext* opCtx, + ViewCatalogLookupBehavior lookupBehavior) { LOG(1) << "reloading view catalog for database " << _durable->getName(); - // Need to reload, first clear our cache. _viewMap.clear(); + _valid = false; + _viewGraphNeedsRefresh = true; auto reloadCallback = [&](const BSONObj& view) -> Status { BSONObj collationSpec = view.hasField("collation") ? view["collation"].Obj() : BSONObj(); @@ -145,17 +143,38 @@ Status ViewCatalog::_reloadIfNeeded(WithLock lk, return status; } - _valid.store(true); + _valid = true; return Status::OK(); } +void ViewCatalog::clear() { + stdx::unique_lock<stdx::mutex> lk(_mutex); + + _viewMap.clear(); + _viewGraph.clear(); + _valid = true; + _viewGraphNeedsRefresh = false; +} + +bool ViewCatalog::shouldIgnoreExternalChange(OperationContext* opCtx, + const NamespaceString& name) const { + return _ignoreExternalChange; +} + +void ViewCatalog::_requireValidCatalog(WithLock) { + uassert(ErrorCodes::InvalidViewDefinition, + "Invalid view definition detected in the view catalog. Remove the invalid view " + "manually to prevent disallowing any further usage of the view catalog.", + _valid); +} + void ViewCatalog::iterate(OperationContext* opCtx, ViewIteratorCallback callback) { Lock::CollectionLock systemViewsLock( opCtx, NamespaceString(_durable->getName(), NamespaceString::kSystemDotViewsCollectionName), MODE_IS); stdx::lock_guard<stdx::mutex> lk(_mutex); - uassertStatusOK(_reloadIfNeeded(lk, opCtx, ViewCatalogLookupBehavior::kValidateDurableViews)); + _requireValidCatalog(lk); for (auto&& view : _viewMap) { callback(*view.second); } @@ -172,7 +191,11 @@ Status ViewCatalog::_createOrUpdateView(WithLock lk, invariant(opCtx->lockState()->isCollectionLockedForMode( NamespaceString(viewName.db(), NamespaceString::kSystemDotViewsCollectionName), MODE_X)); - _requireValidCatalog(lk, opCtx); + _requireValidCatalog(lk); + + ON_BLOCK_EXIT([this] { _ignoreExternalChange = false; }); + + _ignoreExternalChange = true; // Build the BSON definition for this view to be saved in the durable view catalog. If the // collation is empty, omit it from the definition altogether. @@ -209,10 +232,8 @@ Status ViewCatalog::_createOrUpdateView(WithLock lk, catalog.removeResource(viewRid, viewName.ns()); }); - // We may get invalidated, but we're exclusively locked, so the change must be ours. - opCtx->recoveryUnit()->onCommit( - [this](boost::optional<Timestamp>) { this->_valid.store(true); }); - return Status::OK(); + // Reload the view catalog with the changes applied. + return _reload(lk, opCtx, ViewCatalogLookupBehavior::kValidateDurableViews); } Status ViewCatalog::_upsertIntoGraph(WithLock lk, @@ -364,7 +385,6 @@ Status ViewCatalog::createView(OperationContext* opCtx, const NamespaceString& viewOn, const BSONArray& pipeline, const BSONObj& collation) { - invariant(opCtx->lockState()->isDbLockedForMode(viewName.db(), MODE_IX)); invariant(opCtx->lockState()->isCollectionLockedForMode(viewName, MODE_IX)); invariant(opCtx->lockState()->isCollectionLockedForMode( @@ -443,7 +463,11 @@ Status ViewCatalog::dropView(OperationContext* opCtx, const NamespaceString& vie NamespaceString(viewName.db(), NamespaceString::kSystemDotViewsCollectionName), MODE_X)); stdx::lock_guard<stdx::mutex> lk(_mutex); - _requireValidCatalog(lk, opCtx); + _requireValidCatalog(lk); + + ON_BLOCK_EXIT([this] { _ignoreExternalChange = false; }); + + _ignoreExternalChange = true; // Save a copy of the view definition in case we need to roll back. auto viewPtr = @@ -455,7 +479,7 @@ Status ViewCatalog::dropView(OperationContext* opCtx, const NamespaceString& vie ViewDefinition savedDefinition = *viewPtr; - invariant(_valid.load()); + invariant(_valid); _durable->remove(opCtx, viewName); _viewGraph.remove(savedDefinition.name()); _viewMap.erase(viewName.ns()); @@ -471,30 +495,14 @@ Status ViewCatalog::dropView(OperationContext* opCtx, const NamespaceString& vie catalog.addResource(viewRid, viewName.ns()); }); - // We may get invalidated, but we're exclusively locked, so the change must be ours. - opCtx->recoveryUnit()->onCommit( - [this](boost::optional<Timestamp>) { this->_valid.store(true); }); - return Status::OK(); + // Reload the view catalog with the changes applied. + return _reload(lk, opCtx, ViewCatalogLookupBehavior::kValidateDurableViews); } std::shared_ptr<ViewDefinition> ViewCatalog::_lookup(WithLock lk, OperationContext* opCtx, StringData ns, ViewCatalogLookupBehavior lookupBehavior) { - // We expect the catalog to be valid, so short-circuit other checks for best performance. - if (MONGO_unlikely(!_valid.load())) { - // If the catalog is invalid, we want to avoid references to virtualized or other invalid - // collection names to trigger a reload. This makes the system more robust in presence of - // invalid view definitions. - if (!NamespaceString::validCollectionName(ns)) - return nullptr; - Status status = _reloadIfNeeded(lk, opCtx, lookupBehavior); - // In case of errors we've already logged a message. Only uassert if there actually is - // a user connection, as otherwise we'd crash the server. The catalog will remain invalid, - // and any views after the first invalid one are ignored. - if (opCtx->getClient()->isFromUserConnection()) - uassertStatusOK(status); - } ViewMap::const_iterator it = _viewMap.find(ns); if (it != _viewMap.end()) { @@ -509,6 +517,18 @@ std::shared_ptr<ViewDefinition> ViewCatalog::lookup(OperationContext* opCtx, Str NamespaceString(_durable->getName(), NamespaceString::kSystemDotViewsCollectionName), MODE_IS); stdx::lock_guard<stdx::mutex> lk(_mutex); + if (!_valid && opCtx->getClient()->isFromUserConnection()) { + // We want to avoid lookups on invalid collection names. + if (!NamespaceString::validCollectionName(ns)) { + return nullptr; + } + + // ApplyOps should work on a valid existing collection, despite the presence of bad views + // otherwise the server would crash. The view catalog will remain invalid until the bad view + // definitions are removed. + _requireValidCatalog(lk); + } + return _lookup(lk, opCtx, ns, ViewCatalogLookupBehavior::kValidateDurableViews); } @@ -530,6 +550,8 @@ StatusWith<ResolvedView> ViewCatalog::resolveView(OperationContext* opCtx, MODE_IS); stdx::unique_lock<stdx::mutex> lock(_mutex); + _requireValidCatalog(lock); + // Keep looping until the resolution completes. If the catalog is invalidated during the // resolution, we start over from the beginning. while (true) { @@ -549,13 +571,6 @@ StatusWith<ResolvedView> ViewCatalog::resolveView(OperationContext* opCtx, int depth = 0; for (; depth < ViewGraph::kMaxViewDepth; depth++) { - // If the catalog has been invalidated, bail and restart. - if (!_valid.load()) { - uassertStatusOK( - _reloadIfNeeded(lock, opCtx, ViewCatalogLookupBehavior::kValidateDurableViews)); - break; - } - auto view = _lookup( lock, opCtx, resolvedNss->ns(), ViewCatalogLookupBehavior::kValidateDurableViews); if (!view) { diff --git a/src/mongo/db/views/view_catalog.h b/src/mongo/db/views/view_catalog.h index 8aee3c1b730..a8fd9df9e3e 100644 --- a/src/mongo/db/views/view_catalog.h +++ b/src/mongo/db/views/view_catalog.h @@ -71,7 +71,10 @@ public: static void set(Database* db, std::unique_ptr<ViewCatalog> catalog); explicit ViewCatalog(std::unique_ptr<DurableViewCatalog> durable) - : _durable(std::move(durable)) {} + : _durable(std::move(durable)), + _valid(false), + _viewGraphNeedsRefresh(true), + _ignoreExternalChange(false) {} /** * Iterates through the catalog, applying 'callback' to each view. This callback function @@ -133,22 +136,25 @@ public: StatusWith<ResolvedView> resolveView(OperationContext* opCtx, const NamespaceString& nss); /** - * Reload the views catalog if marked invalid. No-op if already valid. Does only minimal - * validation, namely that the view definitions are valid BSON and have no unknown fields. - * Reading stops on the first invalid entry. Errors are logged and returned. Performs no - * cycle detection etc. This is implicitly called by other methods when the ViewCatalog is - * marked invalid, and on first opening a database. + * Reloads the in-memory state of the view catalog from the 'system.views' collection catalog. + * If the 'lookupBehavior' is 'kValidateDurableViews', then the durable view definitions will be + * validated. Reading stops on the first invalid entry with errors logged and returned. Performs + * no cycle detection, etc. + * This is implicitly called by other methods when write operations are performed on the view + * catalog, on external changes to the 'system.views' collection and on the first opening of a + * database. */ - Status reloadIfNeeded(OperationContext* opCtx); + Status reload(OperationContext* opCtx, ViewCatalogLookupBehavior lookupBehavior); /** - * To be called when direct modifications to the DurableViewCatalog have been committed, so - * subsequent lookups will reload the catalog and make the changes visible. + * Clears the in-memory state of the view catalog. */ - void invalidate() { - _valid.store(false); - _viewGraphNeedsRefresh = true; - } + void clear(); + + /** + * The view catalog needs to ignore external changes for its own modifications. + */ + bool shouldIgnoreExternalChange(OperationContext* opCtx, const NamespaceString& name) const; private: Status _createOrUpdateView(WithLock, @@ -183,21 +189,23 @@ private: OperationContext* opCtx, StringData ns, ViewCatalogLookupBehavior lookupBehavior); - Status _reloadIfNeeded(WithLock, - OperationContext* opCtx, - ViewCatalogLookupBehavior lookupBehavior); - void _requireValidCatalog(WithLock lk, OperationContext* opCtx) { - uassertStatusOK( - _reloadIfNeeded(lk, opCtx, ViewCatalogLookupBehavior::kValidateDurableViews)); - invariant(_valid.load()); - } + Status _reload(WithLock, OperationContext* opCtx, ViewCatalogLookupBehavior lookupBehavior); + + /** + * uasserts with the InvalidViewDefinition error if the current in-memory state of the view + * catalog is invalid. This ensures that calling into the view catalog while it is invalid + * renders it inoperable. + */ + void _requireValidCatalog(WithLock); - stdx::mutex _mutex; // Protects all members, except for _valid. + stdx::mutex _mutex; // Protects all members. ViewMap _viewMap; + ViewMap _viewMapBackup; std::unique_ptr<DurableViewCatalog> _durable; - AtomicWord<bool> _valid; + bool _valid; ViewGraph _viewGraph; - bool _viewGraphNeedsRefresh = true; // Defers initializing the graph until the first insert. + bool _viewGraphNeedsRefresh; + bool _ignoreExternalChange; }; } // namespace mongo diff --git a/src/mongo/db/views/view_catalog_test.cpp b/src/mongo/db/views/view_catalog_test.cpp index 6737a38b6a1..87aa9340ba8 100644 --- a/src/mongo/db/views/view_catalog_test.cpp +++ b/src/mongo/db/views/view_catalog_test.cpp @@ -39,7 +39,9 @@ #include "mongo/bson/bsonmisc.h" #include "mongo/bson/bsonobj.h" #include "mongo/bson/bsonobjbuilder.h" +#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/namespace_string.h" #include "mongo/db/operation_context.h" @@ -74,61 +76,103 @@ constexpr auto kLargeString = const auto kOneKiBMatchStage = BSON("$match" << BSON("data" << kLargeString)); const auto kTinyMatchStage = BSON("$match" << BSONObj()); -class DurableViewCatalogDummy final : public DurableViewCatalog { +class ViewCatalogFixture : public CatalogTestFixture { public: - explicit DurableViewCatalogDummy() : _upsertCount(0), _iterateCount(0) {} - static const std::string name; + void setUp() override { + CatalogTestFixture::setUp(); + + WriteUnitOfWork wuow(operationContext()); + AutoGetOrCreateDb autoDb(operationContext(), "db", MODE_X); + _db = autoDb.getDb(); + invariant(_db); + + auto durableViewCatalogUnique = std::make_unique<DurableViewCatalogImpl>(_db); + durableViewCatalog = durableViewCatalogUnique.get(); - using Callback = std::function<Status(const BSONObj& view)>; - virtual void iterate(OperationContext* opCtx, Callback callback) { - ++_iterateCount; + _viewCatalog = ViewCatalog::get(_db); + + // Create the system views collection for the database. + ASSERT(_db->createCollection( + operationContext(), + NamespaceString("db", NamespaceString::kSystemDotViewsCollectionName))); + + // Create any additional databases used throughout the test. + ASSERT(AutoGetOrCreateDb(operationContext(), "db1", MODE_X).getDb()); + ASSERT(AutoGetOrCreateDb(operationContext(), "db2", MODE_X).getDb()); + wuow.commit(); } - virtual void iterateIgnoreInvalidEntries(OperationContext* opCtx, Callback callback) { - ++_iterateCount; + + void tearDown() { + CatalogTestFixture::tearDown(); } - virtual void upsert(OperationContext* opCtx, const NamespaceString& name, const BSONObj& view) { - ++_upsertCount; + + ViewCatalog* getViewCatalog() const { + return _viewCatalog; } - virtual void remove(OperationContext* opCtx, const NamespaceString& name) {} - virtual const std::string& getName() const { - return name; - }; - int getUpsertCount() { - return _upsertCount; + Status createView(OperationContext* opCtx, + const NamespaceString& viewName, + const NamespaceString& viewOn, + const BSONArray& pipeline, + const BSONObj& collation) { + Lock::DBLock dbLock(operationContext(), viewName.db(), MODE_IX); + Lock::CollectionLock collLock(operationContext(), viewName, MODE_IX); + Lock::CollectionLock sysCollLock( + operationContext(), + NamespaceString(viewName.db(), NamespaceString::kSystemDotViewsCollectionName), + MODE_X); + + WriteUnitOfWork wuow(opCtx); + Status s = _viewCatalog->createView(opCtx, viewName, viewOn, pipeline, collation); + wuow.commit(); + + return s; } - int getIterateCount() { - return _iterateCount; + Status modifyView(OperationContext* opCtx, + const NamespaceString& viewName, + const NamespaceString& viewOn, + const BSONArray& pipeline) { + Lock::DBLock dbLock(operationContext(), viewName.db(), MODE_X); + Lock::CollectionLock collLock(operationContext(), viewName, MODE_IX); + Lock::CollectionLock sysCollLock( + operationContext(), + NamespaceString(viewName.db(), NamespaceString::kSystemDotViewsCollectionName), + MODE_X); + + WriteUnitOfWork wuow(opCtx); + Status s = _viewCatalog->modifyView(opCtx, viewName, viewOn, pipeline); + wuow.commit(); + + return s; } -private: - int _upsertCount; - int _iterateCount; -}; + Status dropView(OperationContext* opCtx, const NamespaceString& viewName) { + Lock::DBLock dbLock(operationContext(), viewName.db(), MODE_IX); + Lock::CollectionLock collLock(operationContext(), viewName, MODE_IX); + Lock::CollectionLock sysCollLock( + operationContext(), + NamespaceString(viewName.db(), NamespaceString::kSystemDotViewsCollectionName), + MODE_X); -const std::string DurableViewCatalogDummy::name = "dummy"; + WriteUnitOfWork wuow(opCtx); + Status s = _viewCatalog->dropView(opCtx, viewName); + wuow.commit(); -class ViewCatalogFixture : public unittest::Test { -public: - ViewCatalogFixture() - : _queryServiceContext(std::make_unique<QueryTestServiceContext>()), - opCtx(_queryServiceContext->makeOperationContext()), - viewCatalog(std::move(durableViewCatalogUnique)) {} + return s; + } + + std::shared_ptr<ViewDefinition> lookup(OperationContext* opCtx, StringData ns) { + Lock::DBLock dbLock(operationContext(), NamespaceString(ns).db(), MODE_IS); + return _viewCatalog->lookup(operationContext(), ns); + } private: - std::unique_ptr<QueryTestServiceContext> _queryServiceContext; + Database* _db; + ViewCatalog* _viewCatalog; protected: - ServiceContext* getServiceContext() const { - return _queryServiceContext->getServiceContext(); - } - - std::unique_ptr<DurableViewCatalogDummy> durableViewCatalogUnique = - std::make_unique<DurableViewCatalogDummy>(); - DurableViewCatalogDummy* durableViewCatalog = durableViewCatalogUnique.get(); - ServiceContext::UniqueOperationContext opCtx; - ViewCatalog viewCatalog; + DurableViewCatalogImpl* durableViewCatalog; const BSONArray emptyPipeline; const BSONObj emptyCollation; }; @@ -137,7 +181,7 @@ protected: class ReplViewCatalogFixture : public ViewCatalogFixture { public: void setUp() override { - Test::setUp(); + ViewCatalogFixture::setUp(); auto service = getServiceContext(); repl::ReplSettings settings; @@ -156,47 +200,44 @@ TEST_F(ViewCatalogFixture, CreateExistingView) { const NamespaceString viewName("db.view"); const NamespaceString viewOn("db.coll"); - ASSERT_OK(viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); - ASSERT_NOT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_NOT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); } TEST_F(ViewCatalogFixture, CreateViewOnDifferentDatabase) { const NamespaceString viewName("db1.view"); const NamespaceString viewOn("db2.coll"); - ASSERT_NOT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_NOT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); } TEST_F(ViewCatalogFixture, CanCreateViewWithExprPredicate) { const NamespaceString viewOn("db.coll"); - ASSERT_OK(viewCatalog.createView(opCtx.get(), - NamespaceString("db.view1"), - viewOn, - BSON_ARRAY(BSON("$match" << BSON("$expr" << 1))), - emptyCollation)); - - ASSERT_OK(viewCatalog.createView( - opCtx.get(), - NamespaceString("db.view2"), - viewOn, - BSON_ARRAY( - BSON("$facet" << BSON("output" << BSON_ARRAY(BSON("$match" << BSON("$expr" << 1)))))), - emptyCollation)); + ASSERT_OK(createView(operationContext(), + NamespaceString("db.view1"), + viewOn, + BSON_ARRAY(BSON("$match" << BSON("$expr" << 1))), + emptyCollation)); + + ASSERT_OK(createView(operationContext(), + NamespaceString("db.view2"), + viewOn, + BSON_ARRAY(BSON("$facet" << BSON("output" << BSON_ARRAY(BSON( + "$match" << BSON("$expr" << 1)))))), + emptyCollation)); } TEST_F(ViewCatalogFixture, CanCreateViewWithJSONSchemaPredicate) { const NamespaceString viewOn("db.coll"); - ASSERT_OK(viewCatalog.createView( - opCtx.get(), + ASSERT_OK(createView( + operationContext(), NamespaceString("db.view1"), viewOn, BSON_ARRAY(BSON("$match" << BSON("$jsonSchema" << BSON("required" << BSON_ARRAY("x"))))), emptyCollation)); - ASSERT_OK(viewCatalog.createView( - opCtx.get(), + ASSERT_OK(createView( + operationContext(), NamespaceString("db.view2"), viewOn, BSON_ARRAY(BSON( @@ -208,16 +249,16 @@ TEST_F(ViewCatalogFixture, CanCreateViewWithJSONSchemaPredicate) { TEST_F(ViewCatalogFixture, CanCreateViewWithLookupUsingPipelineSyntax) { const NamespaceString viewOn("db.coll"); - ASSERT_OK(viewCatalog.createView(opCtx.get(), - NamespaceString("db.view"), - viewOn, - BSON_ARRAY(BSON("$lookup" << BSON("from" - << "fcoll" - << "as" - << "as" - << "pipeline" - << BSONArray()))), - emptyCollation)); + ASSERT_OK(createView(operationContext(), + NamespaceString("db.view"), + viewOn, + BSON_ARRAY(BSON("$lookup" << BSON("from" + << "fcoll" + << "as" + << "as" + << "pipeline" + << BSONArray()))), + emptyCollation)); } TEST_F(ViewCatalogFixture, CreateViewWithPipelineFailsOnInvalidStageName) { @@ -225,9 +266,8 @@ TEST_F(ViewCatalogFixture, CreateViewWithPipelineFailsOnInvalidStageName) { const NamespaceString viewOn("db.coll"); auto invalidPipeline = BSON_ARRAY(BSON("INVALID_STAGE_NAME" << 1)); - ASSERT_THROWS( - viewCatalog.createView(opCtx.get(), viewName, viewOn, invalidPipeline, emptyCollation), - AssertionException); + ASSERT_THROWS(createView(operationContext(), viewName, viewOn, invalidPipeline, emptyCollation), + AssertionException); } TEST_F(ReplViewCatalogFixture, CreateViewWithPipelineFailsOnIneligibleStage) { @@ -238,7 +278,7 @@ TEST_F(ReplViewCatalogFixture, CreateViewWithPipelineFailsOnIneligibleStage) { auto invalidPipeline = BSON_ARRAY(BSON("$changeStream" << BSONObj())); ASSERT_THROWS_CODE( - viewCatalog.createView(opCtx.get(), viewName, viewOn, invalidPipeline, emptyCollation), + createView(operationContext(), viewName, viewOn, invalidPipeline, emptyCollation), AssertionException, ErrorCodes::OptionNotSupportedOnView); } @@ -252,7 +292,7 @@ TEST_F(ReplViewCatalogFixture, CreateViewWithPipelineFailsOnIneligibleStagePersi << "someOtherCollection")); ASSERT_THROWS_CODE( - viewCatalog.createView(opCtx.get(), viewName, viewOn, invalidPipeline, emptyCollation), + createView(operationContext(), viewName, viewOn, invalidPipeline, emptyCollation), AssertionException, ErrorCodes::OptionNotSupportedOnView); @@ -260,7 +300,7 @@ TEST_F(ReplViewCatalogFixture, CreateViewWithPipelineFailsOnIneligibleStagePersi << "someOtherCollection")); ASSERT_THROWS_CODE( - viewCatalog.createView(opCtx.get(), viewName, viewOn, invalidPipeline, emptyCollation), + createView(operationContext(), viewName, viewOn, invalidPipeline, emptyCollation), AssertionException, ErrorCodes::OptionNotSupportedOnView); } @@ -269,8 +309,7 @@ TEST_F(ViewCatalogFixture, CreateViewOnInvalidCollectionName) { const NamespaceString viewName("db.view"); const NamespaceString viewOn("db.$coll"); - ASSERT_NOT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_NOT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); } TEST_F(ViewCatalogFixture, ExceedMaxViewDepthInOrder) { @@ -281,15 +320,13 @@ TEST_F(ViewCatalogFixture, ExceedMaxViewDepthInOrder) { const NamespaceString viewName(str::stream() << ns << i); const NamespaceString viewOn(str::stream() << ns << (i + 1)); - ASSERT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); } const NamespaceString viewName(str::stream() << ns << i); const NamespaceString viewOn(str::stream() << ns << (i + 1)); - ASSERT_NOT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_NOT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); } TEST_F(ViewCatalogFixture, ExceedMaxViewDepthByJoining) { @@ -301,23 +338,20 @@ TEST_F(ViewCatalogFixture, ExceedMaxViewDepthByJoining) { const NamespaceString viewName(str::stream() << ns << i); const NamespaceString viewOn(str::stream() << ns << (i + 1)); - ASSERT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); } for (i = 1; i < size + 1; i++) { const NamespaceString viewName(str::stream() << ns << (size + i)); const NamespaceString viewOn(str::stream() << ns << (size + i + 1)); - ASSERT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); } const NamespaceString viewName(str::stream() << ns << size); const NamespaceString viewOn(str::stream() << ns << (size + 1)); - ASSERT_NOT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_NOT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); } TEST_F(ViewCatalogFixture, CreateViewCycles) { @@ -326,7 +360,7 @@ TEST_F(ViewCatalogFixture, CreateViewCycles) { const NamespaceString viewOn("db.view1"); ASSERT_NOT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); } { @@ -334,10 +368,9 @@ TEST_F(ViewCatalogFixture, CreateViewCycles) { const NamespaceString view2("db.view2"); const NamespaceString view3("db.view3"); - ASSERT_OK(viewCatalog.createView(opCtx.get(), view1, view2, emptyPipeline, emptyCollation)); - ASSERT_OK(viewCatalog.createView(opCtx.get(), view2, view3, emptyPipeline, emptyCollation)); - ASSERT_NOT_OK( - viewCatalog.createView(opCtx.get(), view3, view1, emptyPipeline, emptyCollation)); + ASSERT_OK(createView(operationContext(), view1, view2, emptyPipeline, emptyCollation)); + ASSERT_OK(createView(operationContext(), view2, view3, emptyPipeline, emptyCollation)); + ASSERT_NOT_OK(createView(operationContext(), view3, view1, emptyPipeline, emptyCollation)); } } @@ -357,7 +390,7 @@ TEST_F(ViewCatalogFixture, CanSuccessfullyCreateViewWhosePipelineIsExactlyAtMaxS const NamespaceString viewOn("db.coll"); const BSONObj collation; - ASSERT_OK(viewCatalog.createView(opCtx.get(), viewName, viewOn, builder.arr(), collation)); + ASSERT_OK(createView(operationContext(), viewName, viewOn, builder.arr(), collation)); } TEST_F(ViewCatalogFixture, CannotCreateViewWhosePipelineExceedsMaxSizeInBytes) { @@ -374,7 +407,7 @@ TEST_F(ViewCatalogFixture, CannotCreateViewWhosePipelineExceedsMaxSizeInBytes) { const NamespaceString viewOn("db.coll"); const BSONObj collation; - ASSERT_NOT_OK(viewCatalog.createView(opCtx.get(), viewName, viewOn, builder.arr(), collation)); + ASSERT_NOT_OK(createView(operationContext(), viewName, viewOn, builder.arr(), collation)); } TEST_F(ViewCatalogFixture, CannotCreateViewIfItsFullyResolvedPipelineWouldExceedMaxSizeInBytes) { @@ -394,34 +427,34 @@ TEST_F(ViewCatalogFixture, CannotCreateViewIfItsFullyResolvedPipelineWouldExceed const BSONObj collation1; const BSONObj collation2; - ASSERT_OK(viewCatalog.createView(opCtx.get(), view1, viewOn, builder1.arr(), collation1)); - ASSERT_NOT_OK(viewCatalog.createView(opCtx.get(), view2, view1, builder2.arr(), collation2)); + ASSERT_OK(createView(operationContext(), view1, viewOn, builder1.arr(), collation1)); + ASSERT_NOT_OK(createView(operationContext(), view2, view1, builder2.arr(), collation2)); } TEST_F(ViewCatalogFixture, DropMissingView) { NamespaceString viewName("db.view"); - ASSERT_NOT_OK(viewCatalog.dropView(opCtx.get(), viewName)); + ASSERT_NOT_OK(dropView(operationContext(), viewName)); } TEST_F(ViewCatalogFixture, ModifyMissingView) { const NamespaceString viewName("db.view"); const NamespaceString viewOn("db.coll"); - ASSERT_NOT_OK(viewCatalog.modifyView(opCtx.get(), viewName, viewOn, emptyPipeline)); + ASSERT_NOT_OK(modifyView(operationContext(), viewName, viewOn, emptyPipeline)); } TEST_F(ViewCatalogFixture, ModifyViewOnDifferentDatabase) { const NamespaceString viewName("db1.view"); const NamespaceString viewOn("db2.coll"); - ASSERT_NOT_OK(viewCatalog.modifyView(opCtx.get(), viewName, viewOn, emptyPipeline)); + ASSERT_NOT_OK(modifyView(operationContext(), viewName, viewOn, emptyPipeline)); } TEST_F(ViewCatalogFixture, ModifyViewOnInvalidCollectionName) { const NamespaceString viewName("db.view"); const NamespaceString viewOn("db.$coll"); - ASSERT_NOT_OK(viewCatalog.modifyView(opCtx.get(), viewName, viewOn, emptyPipeline)); + ASSERT_NOT_OK(modifyView(operationContext(), viewName, viewOn, emptyPipeline)); } TEST_F(ReplViewCatalogFixture, ModifyViewWithPipelineFailsOnIneligibleStage) { @@ -432,35 +465,35 @@ TEST_F(ReplViewCatalogFixture, ModifyViewWithPipelineFailsOnIneligibleStage) { auto invalidPipeline = BSON_ARRAY(BSON("$changeStream" << BSONObj())); // Create the initial, valid view. - ASSERT_OK(viewCatalog.createView(opCtx.get(), viewName, viewOn, validPipeline, emptyCollation)); + ASSERT_OK(createView(operationContext(), viewName, viewOn, validPipeline, emptyCollation)); // Now attempt to replace it with a pipeline containing $changeStream. - ASSERT_THROWS_CODE(viewCatalog.modifyView(opCtx.get(), viewName, viewOn, invalidPipeline), + ASSERT_THROWS_CODE(modifyView(operationContext(), viewName, viewOn, invalidPipeline), AssertionException, ErrorCodes::OptionNotSupportedOnView); } TEST_F(ViewCatalogFixture, LookupMissingView) { - ASSERT(!viewCatalog.lookup(opCtx.get(), "db.view"_sd)); + ASSERT(!lookup(operationContext(), "db.view"_sd)); } TEST_F(ViewCatalogFixture, LookupExistingView) { const NamespaceString viewName("db.view"); const NamespaceString viewOn("db.coll"); - ASSERT_OK(viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); - ASSERT(viewCatalog.lookup(opCtx.get(), "db.view"_sd)); + ASSERT(lookup(operationContext(), "db.view"_sd)); } TEST_F(ViewCatalogFixture, LookupRIDExistingView) { const NamespaceString viewName("db.view"); const NamespaceString viewOn("db.coll"); - ASSERT_OK(viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); auto resourceID = ResourceId(RESOURCE_COLLECTION, "db.view"_sd); - auto& collectionCatalog = CollectionCatalog::get(opCtx.get()); + auto& collectionCatalog = CollectionCatalog::get(operationContext()); ASSERT(collectionCatalog.lookupResourceName(resourceID).get() == "db.view"); } @@ -468,12 +501,19 @@ TEST_F(ViewCatalogFixture, LookupRIDExistingViewRollback) { const NamespaceString viewName("db.view"); const NamespaceString viewOn("db.coll"); { - WriteUnitOfWork wunit(opCtx.get()); - ASSERT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + Lock::DBLock dbLock(operationContext(), viewName.db(), MODE_X); + Lock::CollectionLock collLock(operationContext(), viewName, MODE_IX); + Lock::CollectionLock sysCollLock( + operationContext(), + NamespaceString(viewName.db(), NamespaceString::kSystemDotViewsCollectionName), + MODE_X); + + WriteUnitOfWork wunit(operationContext()); + ASSERT_OK(getViewCatalog()->createView( + operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); } auto resourceID = ResourceId(RESOURCE_COLLECTION, "db.view"_sd); - auto& collectionCatalog = CollectionCatalog::get(opCtx.get()); + auto& collectionCatalog = CollectionCatalog::get(operationContext()); ASSERT(!collectionCatalog.lookupResourceName(resourceID)); } @@ -481,11 +521,11 @@ TEST_F(ViewCatalogFixture, LookupRIDAfterDrop) { const NamespaceString viewName("db.view"); const NamespaceString viewOn("db.coll"); - ASSERT_OK(viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); - ASSERT_OK(viewCatalog.dropView(opCtx.get(), viewName)); + ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_OK(dropView(operationContext(), viewName)); auto resourceID = ResourceId(RESOURCE_COLLECTION, "db.view"_sd); - auto& collectionCatalog = CollectionCatalog::get(opCtx.get()); + auto& collectionCatalog = CollectionCatalog::get(operationContext()); ASSERT(!collectionCatalog.lookupResourceName(resourceID)); } @@ -494,18 +534,24 @@ TEST_F(ViewCatalogFixture, LookupRIDAfterDropRollback) { const NamespaceString viewOn("db.coll"); auto resourceID = ResourceId(RESOURCE_COLLECTION, "db.view"_sd); - auto& collectionCatalog = CollectionCatalog::get(opCtx.get()); + auto& collectionCatalog = CollectionCatalog::get(operationContext()); { - WriteUnitOfWork wunit(opCtx.get()); - ASSERT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + WriteUnitOfWork wunit(operationContext()); + ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); ASSERT(collectionCatalog.lookupResourceName(resourceID).get() == viewName.ns()); wunit.commit(); } { - WriteUnitOfWork wunit(opCtx.get()); - ASSERT_OK(viewCatalog.dropView(opCtx.get(), viewName)); + Lock::DBLock dbLock(operationContext(), viewName.db(), MODE_X); + Lock::CollectionLock collLock(operationContext(), viewName, MODE_IX); + Lock::CollectionLock sysCollLock( + operationContext(), + NamespaceString(viewName.db(), NamespaceString::kSystemDotViewsCollectionName), + MODE_X); + + WriteUnitOfWork wunit(operationContext()); + ASSERT_OK(getViewCatalog()->dropView(operationContext(), viewName)); } ASSERT(collectionCatalog.lookupResourceName(resourceID).get() == viewName.ns()); @@ -516,9 +562,9 @@ TEST_F(ViewCatalogFixture, LookupRIDAfterModify) { const NamespaceString viewOn("db.coll"); auto resourceID = ResourceId(RESOURCE_COLLECTION, "db.view"_sd); - auto& collectionCatalog = CollectionCatalog::get(opCtx.get()); - ASSERT_OK(viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); - ASSERT_OK(viewCatalog.modifyView(opCtx.get(), viewName, viewOn, emptyPipeline)); + auto& collectionCatalog = CollectionCatalog::get(operationContext()); + ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_OK(modifyView(operationContext(), viewName, viewOn, emptyPipeline)); ASSERT(collectionCatalog.lookupResourceName(resourceID).get() == viewName.ns()); } @@ -527,17 +573,24 @@ TEST_F(ViewCatalogFixture, LookupRIDAfterModifyRollback) { const NamespaceString viewOn("db.coll"); auto resourceID = ResourceId(RESOURCE_COLLECTION, "db.view"_sd); - auto& collectionCatalog = CollectionCatalog::get(opCtx.get()); + auto& collectionCatalog = CollectionCatalog::get(operationContext()); { - WriteUnitOfWork wunit(opCtx.get()); - ASSERT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); + WriteUnitOfWork wunit(operationContext()); + ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); ASSERT(collectionCatalog.lookupResourceName(resourceID).get() == viewName.ns()); wunit.commit(); } { - WriteUnitOfWork wunit(opCtx.get()); - ASSERT_OK(viewCatalog.modifyView(opCtx.get(), viewName, viewOn, emptyPipeline)); + Lock::DBLock dbLock(operationContext(), viewName.db(), MODE_X); + Lock::CollectionLock collLock(operationContext(), viewName, MODE_IX); + Lock::CollectionLock sysCollLock( + operationContext(), + NamespaceString(viewName.db(), NamespaceString::kSystemDotViewsCollectionName), + MODE_X); + + WriteUnitOfWork wunit(operationContext()); + ASSERT_OK( + getViewCatalog()->modifyView(operationContext(), viewName, viewOn, emptyPipeline)); ASSERT(collectionCatalog.lookupResourceName(resourceID).get() == viewName.ns()); } ASSERT(collectionCatalog.lookupResourceName(resourceID).get() == viewName.ns()); @@ -547,32 +600,10 @@ TEST_F(ViewCatalogFixture, CreateViewThenDropAndLookup) { const NamespaceString viewName("db.view"); const NamespaceString viewOn("db.coll"); - ASSERT_OK(viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); - ASSERT_OK(viewCatalog.dropView(opCtx.get(), viewName)); - - ASSERT(!viewCatalog.lookup(opCtx.get(), "db.view"_sd)); -} - -TEST_F(ViewCatalogFixture, ModifyTenTimes) { - const char* ns = "db.view"; - int i; - - for (i = 0; i < 5; i++) { - const NamespaceString viewName(str::stream() << ns << i); - const NamespaceString viewOn(str::stream() << ns << (i + 1)); - - ASSERT_OK( - viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); - } - - for (i = 0; i < 5; i++) { - const NamespaceString viewName(str::stream() << ns << i); - const NamespaceString viewOn(str::stream() << ns << (i + 1)); - - ASSERT_OK(viewCatalog.modifyView(opCtx.get(), viewName, viewOn, emptyPipeline)); - } + ASSERT_OK(createView(operationContext(), viewName, viewOn, emptyPipeline, emptyCollation)); + ASSERT_OK(dropView(operationContext(), viewName)); - ASSERT_EQ(10, durableViewCatalog->getUpsertCount()); + ASSERT(!lookup(operationContext(), "db.view"_sd)); } TEST_F(ViewCatalogFixture, Iterate) { @@ -581,13 +612,14 @@ TEST_F(ViewCatalogFixture, Iterate) { const NamespaceString view3("db.view3"); const NamespaceString viewOn("db.coll"); - ASSERT_OK(viewCatalog.createView(opCtx.get(), view1, viewOn, emptyPipeline, emptyCollation)); - ASSERT_OK(viewCatalog.createView(opCtx.get(), view2, viewOn, emptyPipeline, emptyCollation)); - ASSERT_OK(viewCatalog.createView(opCtx.get(), view3, viewOn, emptyPipeline, emptyCollation)); + ASSERT_OK(createView(operationContext(), view1, viewOn, emptyPipeline, emptyCollation)); + ASSERT_OK(createView(operationContext(), view2, viewOn, emptyPipeline, emptyCollation)); + ASSERT_OK(createView(operationContext(), view3, viewOn, emptyPipeline, emptyCollation)); std::set<std::string> viewNames = {"db.view1", "db.view2", "db.view3"}; - viewCatalog.iterate(opCtx.get(), [&viewNames](const ViewDefinition& view) { + Lock::DBLock dbLock(operationContext(), "db", MODE_IX); + getViewCatalog()->iterate(operationContext(), [&viewNames](const ViewDefinition& view) { std::string name = view.name().toString(); ASSERT(viewNames.end() != viewNames.find(name)); viewNames.erase(name); @@ -609,11 +641,12 @@ TEST_F(ViewCatalogFixture, ResolveViewCorrectPipeline) { pipeline2 << BSON("$match" << BSON("foo" << 2)); pipeline3 << BSON("$match" << BSON("foo" << 3)); - ASSERT_OK(viewCatalog.createView(opCtx.get(), view1, viewOn, pipeline1.arr(), emptyCollation)); - ASSERT_OK(viewCatalog.createView(opCtx.get(), view2, view1, pipeline2.arr(), emptyCollation)); - ASSERT_OK(viewCatalog.createView(opCtx.get(), view3, view2, pipeline3.arr(), emptyCollation)); + ASSERT_OK(createView(operationContext(), view1, viewOn, pipeline1.arr(), emptyCollation)); + ASSERT_OK(createView(operationContext(), view2, view1, pipeline2.arr(), emptyCollation)); + ASSERT_OK(createView(operationContext(), view3, view2, pipeline3.arr(), emptyCollation)); - auto resolvedView = viewCatalog.resolveView(opCtx.get(), view3); + Lock::DBLock dbLock(operationContext(), "db", MODE_IX); + auto resolvedView = getViewCatalog()->resolveView(operationContext(), view3); ASSERT(resolvedView.isOK()); std::vector<BSONObj> expected = {BSON("$match" << BSON("foo" << 1)), @@ -632,7 +665,9 @@ TEST_F(ViewCatalogFixture, ResolveViewCorrectPipeline) { TEST_F(ViewCatalogFixture, ResolveViewOnCollectionNamespace) { const NamespaceString collectionNamespace("db.coll"); - auto resolvedView = uassertStatusOK(viewCatalog.resolveView(opCtx.get(), collectionNamespace)); + Lock::DBLock dbLock(operationContext(), "db", MODE_IS); + auto resolvedView = + uassertStatusOK(getViewCatalog()->resolveView(operationContext(), collectionNamespace)); ASSERT_EQ(resolvedView.getNamespace(), collectionNamespace); ASSERT_EQ(resolvedView.getPipeline().size(), 0U); @@ -649,12 +684,13 @@ TEST_F(ViewCatalogFixture, ResolveViewCorrectlyExtractsDefaultCollation) { pipeline2 << BSON("$match" << BSON("foo" << 2)); BSONObj collation = BSON("locale" - << "mock_reverse_string"); + << "en_US"); - ASSERT_OK(viewCatalog.createView(opCtx.get(), view1, viewOn, pipeline1.arr(), collation)); - ASSERT_OK(viewCatalog.createView(opCtx.get(), view2, view1, pipeline2.arr(), collation)); + ASSERT_OK(createView(operationContext(), view1, viewOn, pipeline1.arr(), collation)); + ASSERT_OK(createView(operationContext(), view2, view1, pipeline2.arr(), collation)); - auto resolvedView = viewCatalog.resolveView(opCtx.get(), view2); + Lock::DBLock dbLock(operationContext(), "db", MODE_IS); + auto resolvedView = getViewCatalog()->resolveView(operationContext(), view2); ASSERT(resolvedView.isOK()); ASSERT_EQ(resolvedView.getValue().getNamespace(), viewOn); @@ -667,26 +703,12 @@ TEST_F(ViewCatalogFixture, ResolveViewCorrectlyExtractsDefaultCollation) { ASSERT(SimpleBSONObjComparator::kInstance.evaluate(expected[i] == result[i])); } - auto expectedCollation = - CollatorFactoryInterface::get(opCtx->getServiceContext())->makeFromBSON(collation); + auto expectedCollation = CollatorFactoryInterface::get(operationContext()->getServiceContext()) + ->makeFromBSON(collation); ASSERT_OK(expectedCollation.getStatus()); ASSERT_BSONOBJ_EQ(resolvedView.getValue().getDefaultCollation(), expectedCollation.getValue()->getSpec().toBSON()); } -TEST_F(ViewCatalogFixture, InvalidateThenReload) { - const NamespaceString viewName("db.view"); - const NamespaceString viewOn("db.coll"); - - ASSERT_OK(viewCatalog.createView(opCtx.get(), viewName, viewOn, emptyPipeline, emptyCollation)); - ASSERT_EQ(1, durableViewCatalog->getIterateCount()); - - ASSERT(viewCatalog.lookup(opCtx.get(), "db.view"_sd)); - ASSERT_EQ(1, durableViewCatalog->getIterateCount()); - - viewCatalog.invalidate(); - ASSERT_OK(viewCatalog.reloadIfNeeded(opCtx.get())); - ASSERT_EQ(2, durableViewCatalog->getIterateCount()); -} } // namespace } // namespace mongo |