diff options
author | Jordi Serra Torrens <jordi.serra-torrens@mongodb.com> | 2023-02-23 18:20:21 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-02-23 21:56:21 +0000 |
commit | d386b47762d7981bdb3129ffa05c11a8fbb82409 (patch) | |
tree | f2666e8f9d3a2631d98b2a8073b8c4629c9d1c0d /src | |
parent | d0a2fb82f0560050a8023e8276ac3d5253206d36 (diff) | |
download | mongo-d386b47762d7981bdb3129ffa05c11a8fbb82409.tar.gz |
SERVER-73005 Support view acquisition on CollectionSnapshot API
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/shard_role.cpp | 170 | ||||
-rw-r--r-- | src/mongo/db/shard_role.h | 158 | ||||
-rw-r--r-- | src/mongo/db/shard_role_test.cpp | 721 | ||||
-rw-r--r-- | src/mongo/db/transaction_resources.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/transaction_resources.h | 16 |
5 files changed, 674 insertions, 393 deletions
diff --git a/src/mongo/db/shard_role.cpp b/src/mongo/db/shard_role.cpp index b4d093fa97a..c77a91a1564 100644 --- a/src/mongo/db/shard_role.cpp +++ b/src/mongo/db/shard_role.cpp @@ -85,7 +85,7 @@ using ResolvedNamespaceOrViewAcquisitionRequestsMap = ResolvedNamespaceOrViewAcquisitionRequestsMap resolveNamespaceOrViewAcquisitionRequests( OperationContext* opCtx, - std::initializer_list<NamespaceOrViewAcquisitionRequest> acquisitionRequests) { + const std::vector<CollectionOrViewAcquisitionRequest>& acquisitionRequests) { auto catalog = CollectionCatalog::get(opCtx); ResolvedNamespaceOrViewAcquisitionRequestsMap sortedAcquisitionRequests; @@ -183,13 +183,13 @@ void checkPlacementVersion(OperationContext* opCtx, const AcquisitionPrerequisit } struct SnapshotedServices { - CollectionPtr collectionPtr; + std::variant<CollectionPtr, std::shared_ptr<const ViewDefinition>> collectionPtrOrView; ScopedCollectionDescription collectionDescription; boost::optional<ScopedCollectionFilter> ownershipFilter; }; -CollectionPtr acquireCollectionPtr(OperationContext* opCtx, - const AcquisitionPrerequisites& prerequisites) { +std::variant<CollectionPtr, std::shared_ptr<const ViewDefinition>> acquireCollectionPtrOrView( + OperationContext* opCtx, const AcquisitionPrerequisites& prerequisites) { const auto& nss = prerequisites.nss; const auto catalog = CollectionCatalog::get(opCtx); @@ -197,19 +197,18 @@ CollectionPtr acquireCollectionPtr(OperationContext* opCtx, if (coll) { verifyDbAndCollection(opCtx, nss, coll); - } else if (catalog->lookupView(opCtx, nss)) { + checkCollectionUUIDMismatch(opCtx, nss, coll, prerequisites.uuid); + return coll; + } else if (auto view = catalog->lookupView(opCtx, nss)) { + checkCollectionUUIDMismatch(opCtx, nss, coll, prerequisites.uuid); uassert(ErrorCodes::CommandNotSupportedOnView, str::stream() << "Namespace " << nss << " is a view, not a collection", prerequisites.viewMode == AcquisitionPrerequisites::kCanBeView); + return view; } else { uasserted(ErrorCodes::NamespaceNotFound, str::stream() << "Namespace " << nss << "does not exist."); } - - // Checks after having established the storage catalog snapshot - checkCollectionUUIDMismatch(opCtx, nss, coll, prerequisites.uuid); - - return coll; } SnapshotedServices acquireServicesSnapshot(OperationContext* opCtx, @@ -219,7 +218,7 @@ SnapshotedServices acquireServicesSnapshot(OperationContext* opCtx, // Check placement version before acquiring the catalog snapshot checkPlacementVersion(opCtx, prerequisites); - auto coll = acquireCollectionPtr(opCtx, prerequisites); + auto coll = acquireCollectionPtrOrView(opCtx, prerequisites); const bool isPlacementConcernVersioned = prerequisites.placementConcern.dbVersion || prerequisites.placementConcern.shardVersion; @@ -260,28 +259,44 @@ std::vector<ScopedCollectionOrViewAcquisition> acquireResolvedCollectionsOrViews auto& prerequisites = acquisitionRequest.second.prerequisites; auto snapshotedServices = acquireServicesSnapshot(opCtx, prerequisites); + const bool isCollection = + std::holds_alternative<CollectionPtr>(snapshotedServices.collectionPtrOrView); + + if (isCollection) { + const auto& collectionPtr = + std::get<CollectionPtr>(snapshotedServices.collectionPtrOrView); + invariant(!prerequisites.uuid || prerequisites.uuid == collectionPtr->uuid()); + if (!prerequisites.uuid) { + // If the uuid wasn't originally set on the AcquisitionRequest, set it now on the + // prerequisites so that on restore from yield we can check we are restoring the + // same instance of the ns. + prerequisites.uuid = collectionPtr->uuid(); + } - invariant(snapshotedServices.collectionPtr); - invariant(!prerequisites.uuid || - prerequisites.uuid == snapshotedServices.collectionPtr->uuid()); - if (!prerequisites.uuid) { - // If the uuid wasn't originally set on the AcquisitionRequest, set it now on the - // prerequisites so that on restore from yield we can check we are restoring the same - // instance of the ns. - prerequisites.uuid = snapshotedServices.collectionPtr->uuid(); + const shard_role_details::AcquiredCollection& acquiredCollection = + getOrMakeTransactionResources(opCtx).addAcquiredCollection( + {prerequisites, + std::move(acquisitionRequest.second.dbLock), + std::move(acquisitionRequest.second.collLock), + std::move(snapshotedServices.collectionDescription), + std::move(snapshotedServices.ownershipFilter), + std::move(std::get<CollectionPtr>(snapshotedServices.collectionPtrOrView))}); + + ScopedCollectionAcquisition scopedAcquisition(opCtx, acquiredCollection); + acquisitions.emplace_back(std::move(scopedAcquisition)); + } else { + // It's a view. + const shard_role_details::AcquiredView& acquiredView = + getOrMakeTransactionResources(opCtx).addAcquiredView( + {prerequisites, + std::move(acquisitionRequest.second.dbLock), + std::move(acquisitionRequest.second.collLock), + std::move(std::get<std::shared_ptr<const ViewDefinition>>( + snapshotedServices.collectionPtrOrView))}); + + ScopedViewAcquisition scopedAcquisition(opCtx, acquiredView); + acquisitions.emplace_back(std::move(scopedAcquisition)); } - - const shard_role_details::AcquiredCollection& acquiredCollection = - getOrMakeTransactionResources(opCtx).addAcquiredCollection( - {prerequisites, - std::move(acquisitionRequest.second.dbLock), - std::move(acquisitionRequest.second.collLock), - std::move(snapshotedServices.collectionDescription), - std::move(snapshotedServices.ownershipFilter), - std::move(snapshotedServices.collectionPtr)}); - - ScopedCollectionOrViewAcquisition scopedAcquisition(opCtx, acquiredCollection); - acquisitions.emplace_back(std::move(scopedAcquisition)); } return acquisitions; @@ -290,10 +305,10 @@ std::vector<ScopedCollectionOrViewAcquisition> acquireResolvedCollectionsOrViews } // namespace const AcquisitionPrerequisites::PlacementConcern - NamespaceOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection{boost::none, - boost::none}; + CollectionOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection{boost::none, + boost::none}; -NamespaceOrViewAcquisitionRequest::NamespaceOrViewAcquisitionRequest( +CollectionOrViewAcquisitionRequest::CollectionOrViewAcquisitionRequest( OperationContext* opCtx, NamespaceString nss, repl::ReadConcernArgs readConcern, @@ -305,7 +320,7 @@ NamespaceOrViewAcquisitionRequest::NamespaceOrViewAcquisitionRequest( operationType(operationType), viewMode(viewMode) {} -ScopedCollectionOrViewAcquisition::~ScopedCollectionOrViewAcquisition() { +ScopedCollectionAcquisition::~ScopedCollectionAcquisition() { if (_opCtx) { const auto& transactionResources = getTransactionResources(_opCtx); if (transactionResources) { @@ -317,27 +332,60 @@ ScopedCollectionOrViewAcquisition::~ScopedCollectionOrViewAcquisition() { } } -const NamespaceString& ScopedCollectionOrViewAcquisition::nss() const { - return _acquiredCollection.prerequisites.nss; +ScopedViewAcquisition::~ScopedViewAcquisition() { + if (_opCtx) { + const auto& transactionResources = getTransactionResources(_opCtx); + if (transactionResources) { + transactionResources->acquiredViews.remove_if( + [this](const shard_role_details::AcquiredView& txnResourceAcquiredView) { + return &txnResourceAcquiredView == &(this->_acquiredView); + }); + } + } } -const ScopedCollectionDescription& ScopedCollectionOrViewAcquisition::getShardingDescription() - const { - return _acquiredCollection.collectionDescription; +ScopedCollectionAcquisition acquireCollection(OperationContext* opCtx, + CollectionAcquisitionRequest acquisitionRequest, + LockMode mode) { + return std::get<ScopedCollectionAcquisition>( + acquireCollectionOrView(opCtx, acquisitionRequest, mode)); } -const boost::optional<ScopedCollectionFilter>& -ScopedCollectionOrViewAcquisition::getCollectionFilter() const { - return _acquiredCollection.ownershipFilter; +std::vector<ScopedCollectionAcquisition> acquireCollections( + OperationContext* opCtx, + std::vector<CollectionAcquisitionRequest> acquisitionRequests, + LockMode mode) { + // Transform the CollectionAcquisitionRequests to NamespaceOrViewAcquisitionRequests. + std::vector<CollectionOrViewAcquisitionRequest> namespaceOrViewAcquisitionRequests; + std::move(acquisitionRequests.begin(), + acquisitionRequests.end(), + std::back_inserter(namespaceOrViewAcquisitionRequests)); + + // Acquire the collections + auto acquisitions = acquireCollectionsOrViews(opCtx, namespaceOrViewAcquisitionRequests, mode); + + // Transform the acquisitions to ScopedCollectionAcquisitions + std::vector<ScopedCollectionAcquisition> collectionAcquisitions; + for (auto& acquisition : acquisitions) { + // It must be a collection, because that's what the acquisition request stated. + invariant(std::holds_alternative<ScopedCollectionAcquisition>(acquisition)); + + collectionAcquisitions.emplace_back( + std::move(std::get<ScopedCollectionAcquisition>(acquisition))); + } + return collectionAcquisitions; } -const CollectionPtr& ScopedCollectionOrViewAcquisition::getCollectionPtr() const { - return _acquiredCollection.collectionPtr; +ScopedCollectionOrViewAcquisition acquireCollectionOrView( + OperationContext* opCtx, CollectionOrViewAcquisitionRequest acquisitionRequest, LockMode mode) { + auto acquisition = acquireCollectionsOrViews(opCtx, {std::move(acquisitionRequest)}, mode); + invariant(acquisition.size() == 1); + return std::move(acquisition.front()); } std::vector<ScopedCollectionOrViewAcquisition> acquireCollectionsOrViews( OperationContext* opCtx, - std::initializer_list<NamespaceOrViewAcquisitionRequest> acquisitionRequests, + std::vector<CollectionOrViewAcquisitionRequest> acquisitionRequests, LockMode mode) { if (acquisitionRequests.size() == 0) { return {}; @@ -383,7 +431,7 @@ std::vector<ScopedCollectionOrViewAcquisition> acquireCollectionsOrViews( std::vector<ScopedCollectionOrViewAcquisition> acquireCollectionsOrViewsWithoutTakingLocks( OperationContext* opCtx, - std::initializer_list<NamespaceOrViewAcquisitionRequest> acquisitionRequests) { + std::initializer_list<CollectionOrViewAcquisitionRequest> acquisitionRequests) { while (true) { auto sortedAcquisitionRequests = resolveNamespaceOrViewAcquisitionRequests(opCtx, acquisitionRequests); @@ -406,13 +454,18 @@ YieldedTransactionResources::YieldedTransactionResources( : _yieldedResources(std::move(yieldedResources)) {} YieldedTransactionResources yieldTransactionResourcesFromOperationContext(OperationContext* opCtx) { - auto transactionResources = std::move(getTransactionResources(opCtx)); + auto& transactionResources = getTransactionResources(opCtx); if (!transactionResources) { return YieldedTransactionResources(); } invariant(!transactionResources->yielded); + // Yielding view acquisitions is not supported. + tassert(7300502, + "Yielding view acquisitions is forbidden", + transactionResources->acquiredViews.empty()); + invariant(!transactionResources->lockSnapshot.is_initialized()); transactionResources->lockSnapshot.emplace(); opCtx->lockState()->saveLockStateAndUnlock(&(*transactionResources->lockSnapshot)); @@ -449,16 +502,31 @@ void restoreTransactionResourcesToOperationContext(OperationContext* opCtx, if (prerequisites.operationType == AcquisitionPrerequisites::OperationType::kRead) { // Just reacquire the CollectionPtr. Reads don't care about placement changes because // they have already established a ScopedCollectionFilter that acts as RangePreserver. - auto collectionPtr = acquireCollectionPtr(opCtx, prerequisites); + auto collectionPtrOrView = acquireCollectionPtrOrView(opCtx, prerequisites); + + // We do not support yielding view acquisitions. Therefore it is not possible that upon + // restore 'acquireCollectionPtrOrView' snapshoted a view -- it would not have met the + // prerequisite that the collection instance is still the same as the one before + // yielding. + invariant(std::holds_alternative<CollectionPtr>(collectionPtrOrView)); // Update the services snapshot on TransactionResources - acquiredCollection.collectionPtr = std::move(collectionPtr); + acquiredCollection.collectionPtr = + std::move(std::get<CollectionPtr>(collectionPtrOrView)); } else { auto reacquiredServicesSnapshot = acquireServicesSnapshot(opCtx, prerequisites); + // We do not support yielding view acquisitions. Therefore it is not possible that upon + // restore 'acquireCollectionPtrOrView' snapshoted a view -- it would not have met the + // prerequisite that the collection instance is still the same as the one before + // yielding. + invariant(std::holds_alternative<CollectionPtr>( + reacquiredServicesSnapshot.collectionPtrOrView)); + // Update the services snapshot on TransactionResources - acquiredCollection.collectionPtr = std::move(reacquiredServicesSnapshot.collectionPtr); + acquiredCollection.collectionPtr = + std::move(std::get<CollectionPtr>(reacquiredServicesSnapshot.collectionPtrOrView)); acquiredCollection.collectionDescription = std::move(reacquiredServicesSnapshot.collectionDescription); acquiredCollection.ownershipFilter = diff --git a/src/mongo/db/shard_role.h b/src/mongo/db/shard_role.h index 228748e4534..8f651c9f965 100644 --- a/src/mongo/db/shard_role.h +++ b/src/mongo/db/shard_role.h @@ -44,13 +44,13 @@ namespace mongo { * taken into account in addition to the ReadConcern of the transaction, which is stored in the * OperationContext. */ -struct NamespaceOrViewAcquisitionRequest { +struct CollectionOrViewAcquisitionRequest { static const AcquisitionPrerequisites::PlacementConcern kPretendUnshardedDueToDirectConnection; /** * Overload, which acquires a collection by NSS, ignoring the current UUID mapping. */ - NamespaceOrViewAcquisitionRequest( + CollectionOrViewAcquisitionRequest( NamespaceString nss, AcquisitionPrerequisites::PlacementConcern placementConcern, repl::ReadConcernArgs readConcern, @@ -66,7 +66,7 @@ struct NamespaceOrViewAcquisitionRequest { * Overload, which acquires a collection by NSS/UUID combination, requiring that the UUID of the * namespace matches exactly. */ - NamespaceOrViewAcquisitionRequest( + CollectionOrViewAcquisitionRequest( NamespaceString nss, UUID uuid, AcquisitionPrerequisites::PlacementConcern placementConcern, @@ -84,7 +84,7 @@ struct NamespaceOrViewAcquisitionRequest { * Overload, which acquires a collection by NSS or DB/UUID, without imposing an expected * relationship between NSS and UUID. */ - NamespaceOrViewAcquisitionRequest( + CollectionOrViewAcquisitionRequest( NamespaceStringOrUUID nssOrUUID, AcquisitionPrerequisites::PlacementConcern placementConcern, repl::ReadConcernArgs readConcern, @@ -102,7 +102,7 @@ struct NamespaceOrViewAcquisitionRequest { * Overload, which acquires a collection by NSS, ignoring the current UUID mapping. Takes the * placement concern from the opCtx's OperationShardingState. */ - NamespaceOrViewAcquisitionRequest( + CollectionOrViewAcquisitionRequest( OperationContext* opCtx, NamespaceString nss, repl::ReadConcernArgs readConcern, @@ -119,41 +119,98 @@ struct NamespaceOrViewAcquisitionRequest { AcquisitionPrerequisites::ViewMode viewMode; }; -/** - * See the comments on the TransactionResources class for the semantics of this class. - */ -class ScopedCollectionOrViewAcquisition { +struct CollectionAcquisitionRequest : public CollectionOrViewAcquisitionRequest { + /** + * Overload, which acquires a collection by NSS, ignoring the current UUID mapping. + */ + CollectionAcquisitionRequest(NamespaceString nss, + AcquisitionPrerequisites::PlacementConcern placementConcern, + repl::ReadConcernArgs readConcern, + AcquisitionPrerequisites::OperationType operationType) + : CollectionOrViewAcquisitionRequest(nss, + placementConcern, + readConcern, + operationType, + AcquisitionPrerequisites::kMustBeCollection) {} + + /** + * Overload, which acquires a collection by NSS/UUID combination, requiring that the UUID of the + * namespace matches exactly. + */ + CollectionAcquisitionRequest(NamespaceString nss, + UUID uuid, + AcquisitionPrerequisites::PlacementConcern placementConcern, + repl::ReadConcernArgs readConcern, + AcquisitionPrerequisites::OperationType operationType) + : CollectionOrViewAcquisitionRequest(nss, + uuid, + placementConcern, + readConcern, + operationType, + AcquisitionPrerequisites::kMustBeCollection) {} + + /** + * Overload, which acquires a collection by NSS or DB/UUID, without imposing an expected + * relationship between NSS and UUID. + */ + CollectionAcquisitionRequest(NamespaceStringOrUUID nssOrUUID, + AcquisitionPrerequisites::PlacementConcern placementConcern, + repl::ReadConcernArgs readConcern, + AcquisitionPrerequisites::OperationType operationType) + : CollectionOrViewAcquisitionRequest(nssOrUUID, + placementConcern, + readConcern, + operationType, + AcquisitionPrerequisites::kMustBeCollection) {} + + /** + * Overload, which acquires a collection by NSS, ignoring the current UUID mapping. Takes the + * placement concern from the opCtx's OperationShardingState. + */ + CollectionAcquisitionRequest(OperationContext* opCtx, + NamespaceString nss, + repl::ReadConcernArgs readConcern, + AcquisitionPrerequisites::OperationType operationType) + : CollectionOrViewAcquisitionRequest( + opCtx, nss, readConcern, operationType, AcquisitionPrerequisites::kMustBeCollection) { + } +}; + +class ScopedCollectionAcquisition { public: - ScopedCollectionOrViewAcquisition() = delete; - ScopedCollectionOrViewAcquisition(const mongo::ScopedCollectionOrViewAcquisition&) = delete; + ScopedCollectionAcquisition(const mongo::ScopedCollectionAcquisition&) = delete; - ScopedCollectionOrViewAcquisition(mongo::ScopedCollectionOrViewAcquisition&& other) + ScopedCollectionAcquisition(mongo::ScopedCollectionAcquisition&& other) : _opCtx(other._opCtx), _acquiredCollection(other._acquiredCollection) { other._opCtx = nullptr; } - ~ScopedCollectionOrViewAcquisition(); + ~ScopedCollectionAcquisition(); - ScopedCollectionOrViewAcquisition( - OperationContext* opCtx, const shard_role_details::AcquiredCollection& acquiredCollection) + ScopedCollectionAcquisition(OperationContext* opCtx, + const shard_role_details::AcquiredCollection& acquiredCollection) : _opCtx(opCtx), _acquiredCollection(acquiredCollection) {} - const NamespaceString& nss() const; - - bool isView() const { - // TODO: SERVER-73005 Support views - return false; + const NamespaceString& nss() const { + return _acquiredCollection.prerequisites.nss; } // Access to services associated with the specified collection top to bottom on the hierarchical // stack // Sharding services - const ScopedCollectionDescription& getShardingDescription() const; - const boost::optional<ScopedCollectionFilter>& getCollectionFilter() const; + const ScopedCollectionDescription& getShardingDescription() const { + return _acquiredCollection.collectionDescription; + } + + const boost::optional<ScopedCollectionFilter>& getCollectionFilter() const { + return _acquiredCollection.ownershipFilter; + } // StorEx services - const CollectionPtr& getCollectionPtr() const; + const CollectionPtr& getCollectionPtr() const { + return _acquiredCollection.collectionPtr; + } private: OperationContext* _opCtx; @@ -164,6 +221,43 @@ private: const shard_role_details::AcquiredCollection& _acquiredCollection; }; +class ScopedViewAcquisition { +public: + ScopedViewAcquisition(const mongo::ScopedViewAcquisition&) = delete; + + ScopedViewAcquisition(mongo::ScopedViewAcquisition&& other) + : _opCtx(other._opCtx), _acquiredView(other._acquiredView) { + other._opCtx = nullptr; + } + + ~ScopedViewAcquisition(); + + ScopedViewAcquisition(OperationContext* opCtx, + const shard_role_details::AcquiredView& acquiredView) + : _opCtx(opCtx), _acquiredView(acquiredView) {} + + const NamespaceString& nss() const { + return _acquiredView.prerequisites.nss; + } + + // StorEx services + const ViewDefinition& getViewDefinition() const { + invariant(_acquiredView.viewDefinition); + return *(_acquiredView.viewDefinition); + } + +private: + OperationContext* _opCtx; + + // Points to the acquired resources that live on the TransactionResources opCtx decoration. The + // lifetime of these resources is tied to the lifetime of this + // ScopedCollectionOrViewAcquisition. + const shard_role_details::AcquiredView& _acquiredView; +}; + +using ScopedCollectionOrViewAcquisition = + std::variant<ScopedCollectionAcquisition, ScopedViewAcquisition>; + /** * Takes into account the specified namespace acquisition requests and if they can be satisfied, * adds the acquired collections to the set ot TransactionResources for the current operation. @@ -171,9 +265,22 @@ private: * This method will acquire and 2-phase hold all the necessary hierarchical locks (Global, DB and * Collection). */ +ScopedCollectionAcquisition acquireCollection(OperationContext* opCtx, + CollectionAcquisitionRequest acquisitionRequest, + LockMode mode); + +std::vector<ScopedCollectionAcquisition> acquireCollections( + OperationContext* opCtx, + std::vector<CollectionAcquisitionRequest> acquisitionRequests, + LockMode mode); + + +ScopedCollectionOrViewAcquisition acquireCollectionOrView( + OperationContext* opCtx, CollectionOrViewAcquisitionRequest acquisitionRequest, LockMode mode); + std::vector<ScopedCollectionOrViewAcquisition> acquireCollectionsOrViews( OperationContext* opCtx, - std::initializer_list<NamespaceOrViewAcquisitionRequest> acquisitionRequests, + std::vector<CollectionOrViewAcquisitionRequest> acquisitionRequests, LockMode mode); /** @@ -181,8 +288,7 @@ std::vector<ScopedCollectionOrViewAcquisition> acquireCollectionsOrViews( * 2-phase hierarchical locks. */ std::vector<ScopedCollectionOrViewAcquisition> acquireCollectionsOrViewsWithoutTakingLocks( - OperationContext* opCtx, - std::initializer_list<NamespaceOrViewAcquisitionRequest> acquisitionRequests); + OperationContext* opCtx, std::vector<CollectionOrViewAcquisitionRequest> acquisitionRequests); /** * Serves as a temporary container for transaction resources which have been yielded via a call to diff --git a/src/mongo/db/shard_role_test.cpp b/src/mongo/db/shard_role_test.cpp index 7e6565fef4f..6dec804ef07 100644 --- a/src/mongo/db/shard_role_test.cpp +++ b/src/mongo/db/shard_role_test.cpp @@ -49,6 +49,16 @@ void createTestCollection(OperationContext* opCtx, const NamespaceString& nss) { uassertStatusOK(createCollection(opCtx, nss.dbName(), BSON("create" << nss.coll()))); } +void createTestView(OperationContext* opCtx, + const NamespaceString& nss, + const NamespaceString& viewOn, + const std::vector<BSONObj>& pipeline) { + uassertStatusOK(createCollection( + opCtx, + nss.dbName(), + BSON("create" << nss.coll() << "viewOn" << viewOn.coll() << "pipeline" << pipeline))); +} + void installDatabaseMetadata(OperationContext* opCtx, const DatabaseName& dbName, const DatabaseVersion& dbVersion) { @@ -136,12 +146,18 @@ protected: ChunkVersion(CollectionGeneration{OID::gen(), Timestamp(5, 0)}, CollectionPlacement(10, 1)), boost::optional<CollectionIndexes>(boost::none)); + const NamespaceString nssView = + NamespaceString::createNamespaceString_forTest(dbNameTestDb, "view"); + const std::vector<BSONObj> viewPipeline = {BSON("$match" << BSON("x" << 1))}; + // Workaround to be able to write parametrized TEST_F void testRestoreFailsIfCollectionNoLongerExists( AcquisitionPrerequisites::OperationType operationType); void testRestoreFailsIfCollectionRenamed(AcquisitionPrerequisites::OperationType operationType); void testRestoreFailsIfCollectionDroppedAndRecreated( AcquisitionPrerequisites::OperationType operationType); + void testRestoreFailsIfCollectionIsNowAView( + AcquisitionPrerequisites::OperationType operationType); private: ServiceContext::UniqueOperationContext _opCtx; @@ -167,9 +183,11 @@ void ShardRoleTest::setUp() { // Setup test collections and metadata installDatabaseMetadata(opCtx(), dbNameTestDb, dbVersionTestDb); + // Create nssUnshardedCollection1 createTestCollection(opCtx(), nssUnshardedCollection1); installUnshardedCollectionMetadata(opCtx(), nssUnshardedCollection1); + // Create nssShardedCollection1 createTestCollection(opCtx(), nssShardedCollection1); const auto uuidShardedCollection1 = getCollectionUUID(_opCtx.get(), nssShardedCollection1); installDatabaseMetadata(opCtx(), dbNameTestDb, dbVersionTestDb); @@ -182,6 +200,9 @@ void ShardRoleTest::setUp() { shardVersionShardedCollection1.placementVersion(), thisShardId)}, thisShardId); + + // Setup nssView + createTestView(opCtx(), nssView, nssUnshardedCollection1, viewPipeline); } void ShardRoleTest::tearDown() { @@ -194,7 +215,7 @@ TEST_F(ShardRoleTest, NamespaceOrViewAcquisitionRequestWithOpCtxTakesPlacementFr const auto nss = nssUnshardedCollection1; { - NamespaceOrViewAcquisitionRequest acquisitionRequest( + CollectionOrViewAcquisitionRequest acquisitionRequest( opCtx(), nss, {}, AcquisitionPrerequisites::kWrite); ASSERT_EQ(boost::none, acquisitionRequest.placementConcern.dbVersion); ASSERT_EQ(boost::none, acquisitionRequest.placementConcern.shardVersion); @@ -205,7 +226,7 @@ TEST_F(ShardRoleTest, NamespaceOrViewAcquisitionRequestWithOpCtxTakesPlacementFr NamespaceString::createNamespaceString_forTest("test2.foo"); ScopedSetShardRole setShardRole( opCtx(), anotherCollection, ShardVersion::UNSHARDED(), dbVersionTestDb); - NamespaceOrViewAcquisitionRequest acquisitionRequest( + CollectionOrViewAcquisitionRequest acquisitionRequest( opCtx(), nss, {}, AcquisitionPrerequisites::kWrite); ASSERT_EQ(boost::none, acquisitionRequest.placementConcern.dbVersion); ASSERT_EQ(boost::none, acquisitionRequest.placementConcern.shardVersion); @@ -215,7 +236,7 @@ TEST_F(ShardRoleTest, NamespaceOrViewAcquisitionRequestWithOpCtxTakesPlacementFr const auto dbVersion = boost::none; const auto shardVersion = boost::none; ScopedSetShardRole setShardRole(opCtx(), nss, shardVersion, dbVersion); - NamespaceOrViewAcquisitionRequest acquisitionRequest( + CollectionOrViewAcquisitionRequest acquisitionRequest( opCtx(), nss, {}, AcquisitionPrerequisites::kWrite); ASSERT_EQ(dbVersion, acquisitionRequest.placementConcern.dbVersion); ASSERT_EQ(shardVersion, acquisitionRequest.placementConcern.shardVersion); @@ -225,7 +246,7 @@ TEST_F(ShardRoleTest, NamespaceOrViewAcquisitionRequestWithOpCtxTakesPlacementFr const auto dbVersion = dbVersionTestDb; const auto shardVersion = ShardVersion::UNSHARDED(); ScopedSetShardRole setShardRole(opCtx(), nss, shardVersion, dbVersion); - NamespaceOrViewAcquisitionRequest acquisitionRequest( + CollectionOrViewAcquisitionRequest acquisitionRequest( opCtx(), nss, {}, AcquisitionPrerequisites::kWrite); ASSERT_EQ(dbVersion, acquisitionRequest.placementConcern.dbVersion); ASSERT_EQ(shardVersion, acquisitionRequest.placementConcern.shardVersion); @@ -235,7 +256,7 @@ TEST_F(ShardRoleTest, NamespaceOrViewAcquisitionRequestWithOpCtxTakesPlacementFr const auto dbVersion = boost::none; const auto shardVersion = shardVersionShardedCollection1; ScopedSetShardRole setShardRole(opCtx(), nss, shardVersion, dbVersion); - NamespaceOrViewAcquisitionRequest acquisitionRequest( + CollectionOrViewAcquisitionRequest acquisitionRequest( opCtx(), nss, {}, AcquisitionPrerequisites::kWrite); ASSERT_EQ(dbVersion, acquisitionRequest.placementConcern.dbVersion); ASSERT_EQ(shardVersion, acquisitionRequest.placementConcern.shardVersion); @@ -248,21 +269,17 @@ TEST_F(ShardRoleTest, NamespaceOrViewAcquisitionRequestWithOpCtxTakesPlacementFr TEST_F(ShardRoleTest, AcquireUnshardedCollWithCorrectPlacementVersion) { AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, ShardVersion::UNSHARDED()}; - const auto acquisitions = - acquireCollectionsOrViews(opCtx(), - {{nssUnshardedCollection1, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX); - - ASSERT_EQ(1, acquisitions.size()); - ASSERT_EQ(nssUnshardedCollection1, acquisitions.front().nss()); - ASSERT_EQ(nssUnshardedCollection1, acquisitions.front().getCollectionPtr()->ns()); - ASSERT_FALSE(acquisitions.front().isView()); - ASSERT_FALSE(acquisitions.front().getShardingDescription().isSharded()); - ASSERT_FALSE(acquisitions.front().getCollectionFilter().has_value()); + const auto acquisition = acquireCollection(opCtx(), + {nssUnshardedCollection1, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX); + + ASSERT_EQ(nssUnshardedCollection1, acquisition.nss()); + ASSERT_EQ(nssUnshardedCollection1, acquisition.getCollectionPtr()->ns()); + ASSERT_FALSE(acquisition.getShardingDescription().isSharded()); + ASSERT_FALSE(acquisition.getCollectionFilter().has_value()); } TEST_F(ShardRoleTest, AcquireUnshardedCollWithIncorrectPlacementVersionThrows) { @@ -270,22 +287,22 @@ TEST_F(ShardRoleTest, AcquireUnshardedCollWithIncorrectPlacementVersionThrows) { AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{incorrectDbVersion, ShardVersion::UNSHARDED()}; - ASSERT_THROWS_WITH_CHECK( - acquireCollectionsOrViews(opCtx(), - {{nssUnshardedCollection1, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX), - ExceptionFor<ErrorCodes::StaleDbVersion>, - [&](const DBException& ex) { - const auto exInfo = ex.extraInfo<StaleDbRoutingVersion>(); - ASSERT_EQ(dbNameTestDb.db(), exInfo->getDb()); - ASSERT_EQ(incorrectDbVersion, exInfo->getVersionReceived()); - ASSERT_EQ(dbVersionTestDb, exInfo->getVersionWanted()); - ASSERT_FALSE(exInfo->getCriticalSectionSignal().is_initialized()); - }); + ASSERT_THROWS_WITH_CHECK(acquireCollection(opCtx(), + { + nssUnshardedCollection1, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite, + }, + MODE_IX), + ExceptionFor<ErrorCodes::StaleDbVersion>, + [&](const DBException& ex) { + const auto exInfo = ex.extraInfo<StaleDbRoutingVersion>(); + ASSERT_EQ(dbNameTestDb.db(), exInfo->getDb()); + ASSERT_EQ(incorrectDbVersion, exInfo->getVersionReceived()); + ASSERT_EQ(dbVersionTestDb, exInfo->getVersionWanted()); + ASSERT_FALSE(exInfo->getCriticalSectionSignal().is_initialized()); + }); } TEST_F(ShardRoleTest, AcquireUnshardedCollWhenShardDoesNotKnowThePlacementVersionThrows) { @@ -299,22 +316,20 @@ TEST_F(ShardRoleTest, AcquireUnshardedCollWhenShardDoesNotKnowThePlacementVersio AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, ShardVersion::UNSHARDED()}; - ASSERT_THROWS_WITH_CHECK( - acquireCollectionsOrViews(opCtx(), - {{nssUnshardedCollection1, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX), - ExceptionFor<ErrorCodes::StaleDbVersion>, - [&](const DBException& ex) { - const auto exInfo = ex.extraInfo<StaleDbRoutingVersion>(); - ASSERT_EQ(dbNameTestDb.db(), exInfo->getDb()); - ASSERT_EQ(dbVersionTestDb, exInfo->getVersionReceived()); - ASSERT_EQ(boost::none, exInfo->getVersionWanted()); - ASSERT_FALSE(exInfo->getCriticalSectionSignal().is_initialized()); - }); + ASSERT_THROWS_WITH_CHECK(acquireCollection(opCtx(), + {nssUnshardedCollection1, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX), + ExceptionFor<ErrorCodes::StaleDbVersion>, + [&](const DBException& ex) { + const auto exInfo = ex.extraInfo<StaleDbRoutingVersion>(); + ASSERT_EQ(dbNameTestDb.db(), exInfo->getDb()); + ASSERT_EQ(dbVersionTestDb, exInfo->getVersionReceived()); + ASSERT_EQ(boost::none, exInfo->getVersionWanted()); + ASSERT_FALSE(exInfo->getCriticalSectionSignal().is_initialized()); + }); } TEST_F(ShardRoleTest, AcquireUnshardedCollWhenCriticalSectionIsActiveThrows) { @@ -331,22 +346,21 @@ TEST_F(ShardRoleTest, AcquireUnshardedCollWhenCriticalSectionIsActiveThrows) { { AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, ShardVersion::UNSHARDED()}; - ASSERT_THROWS_WITH_CHECK( - acquireCollectionsOrViews(opCtx(), - {{nssUnshardedCollection1, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX), - ExceptionFor<ErrorCodes::StaleDbVersion>, - [&](const DBException& ex) { - const auto exInfo = ex.extraInfo<StaleDbRoutingVersion>(); - ASSERT_EQ(dbNameTestDb.db(), exInfo->getDb()); - ASSERT_EQ(dbVersionTestDb, exInfo->getVersionReceived()); - ASSERT_EQ(boost::none, exInfo->getVersionWanted()); - ASSERT_TRUE(exInfo->getCriticalSectionSignal().is_initialized()); - }); + ASSERT_THROWS_WITH_CHECK(acquireCollection(opCtx(), + {nssUnshardedCollection1, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX), + ExceptionFor<ErrorCodes::StaleDbVersion>, + [&](const DBException& ex) { + const auto exInfo = ex.extraInfo<StaleDbRoutingVersion>(); + ASSERT_EQ(dbNameTestDb.db(), exInfo->getDb()); + ASSERT_EQ(dbVersionTestDb, exInfo->getVersionReceived()); + ASSERT_EQ(boost::none, exInfo->getVersionWanted()); + ASSERT_TRUE( + exInfo->getCriticalSectionSignal().is_initialized()); + }); } { @@ -361,22 +375,18 @@ TEST_F(ShardRoleTest, AcquireUnshardedCollWhenCriticalSectionIsActiveThrows) { TEST_F(ShardRoleTest, AcquireUnshardedCollWithoutSpecifyingPlacementVersion) { AcquisitionPrerequisites::PlacementConcern placementConcern = - NamespaceOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection; - const auto acquisitions = - acquireCollectionsOrViews(opCtx(), - {{nssUnshardedCollection1, - {placementConcern}, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX); - - ASSERT_EQ(1, acquisitions.size()); - ASSERT_EQ(nssUnshardedCollection1, acquisitions.front().nss()); - ASSERT_EQ(nssUnshardedCollection1, acquisitions.front().getCollectionPtr()->ns()); - ASSERT_FALSE(acquisitions.front().isView()); - ASSERT_FALSE(acquisitions.front().getShardingDescription().isSharded()); - ASSERT_FALSE(acquisitions.front().getCollectionFilter().has_value()); + CollectionOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection; + const auto acquisition = acquireCollection(opCtx(), + {nssUnshardedCollection1, + {placementConcern}, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX); + + ASSERT_EQ(nssUnshardedCollection1, acquisition.nss()); + ASSERT_EQ(nssUnshardedCollection1, acquisition.getCollectionPtr()->ns()); + ASSERT_FALSE(acquisition.getShardingDescription().isSharded()); + ASSERT_FALSE(acquisition.getCollectionFilter().has_value()); } // --------------------------------------------------------------------------- @@ -386,43 +396,40 @@ TEST_F(ShardRoleTest, AcquireShardedCollWithCorrectPlacementVersion) { AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{{} /* dbVersion */, shardVersionShardedCollection1}; - const auto acquisitions = - acquireCollectionsOrViews(opCtx(), - {{nssShardedCollection1, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX); - - ASSERT_EQ(1, acquisitions.size()); - ASSERT_EQ(nssShardedCollection1, acquisitions.front().nss()); - ASSERT_EQ(nssShardedCollection1, acquisitions.front().getCollectionPtr()->ns()); - ASSERT_FALSE(acquisitions.front().isView()); - ASSERT_TRUE(acquisitions.front().getShardingDescription().isSharded()); - ASSERT_TRUE(acquisitions.front().getCollectionFilter().has_value()); + const auto acquisition = acquireCollection(opCtx(), + {nssShardedCollection1, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX); + + ASSERT_EQ(nssShardedCollection1, acquisition.nss()); + ASSERT_EQ(nssShardedCollection1, acquisition.getCollectionPtr()->ns()); + ASSERT_TRUE(acquisition.getShardingDescription().isSharded()); + ASSERT_TRUE(acquisition.getCollectionFilter().has_value()); } TEST_F(ShardRoleTest, AcquireShardedCollWithIncorrectPlacementVersionThrows) { AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, ShardVersion::UNSHARDED()}; - ASSERT_THROWS_WITH_CHECK( - acquireCollectionsOrViews(opCtx(), - {{nssShardedCollection1, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX), - ExceptionFor<ErrorCodes::StaleConfig>, - [&](const DBException& ex) { - const auto exInfo = ex.extraInfo<StaleConfigInfo>(); - ASSERT_EQ(nssShardedCollection1, exInfo->getNss()); - ASSERT_EQ(ShardVersion::UNSHARDED(), exInfo->getVersionReceived()); - ASSERT_EQ(shardVersionShardedCollection1, exInfo->getVersionWanted()); - ASSERT_EQ(ShardId("this"), exInfo->getShardId()); - ASSERT_FALSE(exInfo->getCriticalSectionSignal().is_initialized()); - }); + ASSERT_THROWS_WITH_CHECK(acquireCollection(opCtx(), + { + nssShardedCollection1, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite, + }, + MODE_IX), + ExceptionFor<ErrorCodes::StaleConfig>, + [&](const DBException& ex) { + const auto exInfo = ex.extraInfo<StaleConfigInfo>(); + ASSERT_EQ(nssShardedCollection1, exInfo->getNss()); + ASSERT_EQ(ShardVersion::UNSHARDED(), exInfo->getVersionReceived()); + ASSERT_EQ(shardVersionShardedCollection1, + exInfo->getVersionWanted()); + ASSERT_EQ(ShardId("this"), exInfo->getShardId()); + ASSERT_FALSE(exInfo->getCriticalSectionSignal().is_initialized()); + }); } TEST_F(ShardRoleTest, AcquireShardedCollWhenShardDoesNotKnowThePlacementVersionThrows) { @@ -436,23 +443,22 @@ TEST_F(ShardRoleTest, AcquireShardedCollWhenShardDoesNotKnowThePlacementVersionT AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{{}, shardVersionShardedCollection1}; - ASSERT_THROWS_WITH_CHECK( - acquireCollectionsOrViews(opCtx(), - {{nssShardedCollection1, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX), - ExceptionFor<ErrorCodes::StaleConfig>, - [&](const DBException& ex) { - const auto exInfo = ex.extraInfo<StaleConfigInfo>(); - ASSERT_EQ(nssShardedCollection1, exInfo->getNss()); - ASSERT_EQ(shardVersionShardedCollection1, exInfo->getVersionReceived()); - ASSERT_EQ(boost::none, exInfo->getVersionWanted()); - ASSERT_EQ(ShardId("this"), exInfo->getShardId()); - ASSERT_FALSE(exInfo->getCriticalSectionSignal().is_initialized()); - }); + ASSERT_THROWS_WITH_CHECK(acquireCollection(opCtx(), + {nssShardedCollection1, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX), + ExceptionFor<ErrorCodes::StaleConfig>, + [&](const DBException& ex) { + const auto exInfo = ex.extraInfo<StaleConfigInfo>(); + ASSERT_EQ(nssShardedCollection1, exInfo->getNss()); + ASSERT_EQ(shardVersionShardedCollection1, + exInfo->getVersionReceived()); + ASSERT_EQ(boost::none, exInfo->getVersionWanted()); + ASSERT_EQ(ShardId("this"), exInfo->getShardId()); + ASSERT_FALSE(exInfo->getCriticalSectionSignal().is_initialized()); + }); } TEST_F(ShardRoleTest, AcquireShardedCollWhenCriticalSectionIsActiveThrows) { @@ -470,13 +476,12 @@ TEST_F(ShardRoleTest, AcquireShardedCollWhenCriticalSectionIsActiveThrows) { AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{{}, shardVersionShardedCollection1}; ASSERT_THROWS_WITH_CHECK( - acquireCollectionsOrViews(opCtx(), - {{nssShardedCollection1, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX), + acquireCollection(opCtx(), + {nssShardedCollection1, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX), ExceptionFor<ErrorCodes::StaleConfig>, [&](const DBException& ex) { const auto exInfo = ex.extraInfo<StaleConfigInfo>(); @@ -499,24 +504,22 @@ TEST_F(ShardRoleTest, AcquireShardedCollWhenCriticalSectionIsActiveThrows) { TEST_F(ShardRoleTest, AcquireShardedCollWithoutSpecifyingPlacementVersion) { AcquisitionPrerequisites::PlacementConcern placementConcern = - NamespaceOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection; - const auto acquisitions = - acquireCollectionsOrViews(opCtx(), - {{nssShardedCollection1, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX); - - ASSERT_EQ(1, acquisitions.size()); - ASSERT_EQ(nssShardedCollection1, acquisitions.front().nss()); - ASSERT_EQ(nssShardedCollection1, acquisitions.front().getCollectionPtr()->ns()); - ASSERT_FALSE(acquisitions.front().isView()); + CollectionOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection; + const auto acquisition = acquireCollection(opCtx(), + { + nssShardedCollection1, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite, + }, + MODE_IX); + + ASSERT_EQ(nssShardedCollection1, acquisition.nss()); + ASSERT_EQ(nssShardedCollection1, acquisition.getCollectionPtr()->ns()); // Note that the collection is treated as unsharded because the operation is unversioned. - ASSERT_FALSE(acquisitions.front().getShardingDescription().isSharded()); - ASSERT_FALSE(acquisitions.front().getCollectionFilter().has_value()); + ASSERT_FALSE(acquisition.getShardingDescription().isSharded()); + ASSERT_FALSE(acquisition.getCollectionFilter().has_value()); } // --------------------------------------------------------------------------- @@ -526,13 +529,12 @@ TEST_F(ShardRoleTest, AcquireCollectionFailsIfItDoesNotExist) { const NamespaceString inexistentNss = NamespaceString::createNamespaceString_forTest(dbNameTestDb, "inexistent"); AcquisitionPrerequisites::PlacementConcern placementConcern; - ASSERT_THROWS_CODE(acquireCollectionsOrViews(opCtx(), - {{inexistentNss, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX), + ASSERT_THROWS_CODE(acquireCollection(opCtx(), + {inexistentNss, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX), DBException, ErrorCodes::NamespaceNotFound); } @@ -543,40 +545,68 @@ TEST_F(ShardRoleTest, AcquireInexistentCollectionWithWrongPlacementThrowsBecause NamespaceString::createNamespaceString_forTest(dbNameTestDb, "inexistent"); AcquisitionPrerequisites::PlacementConcern placementConcern{incorrectDbVersion, {}}; - ASSERT_THROWS_WITH_CHECK( - acquireCollectionsOrViews(opCtx(), - {{inexistentNss, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX), - ExceptionFor<ErrorCodes::StaleDbVersion>, - [&](const DBException& ex) { - const auto exInfo = ex.extraInfo<StaleDbRoutingVersion>(); - ASSERT_EQ(dbNameTestDb.db(), exInfo->getDb()); - ASSERT_EQ(incorrectDbVersion, exInfo->getVersionReceived()); - ASSERT_EQ(dbVersionTestDb, exInfo->getVersionWanted()); - ASSERT_FALSE(exInfo->getCriticalSectionSignal().is_initialized()); - }); + ASSERT_THROWS_WITH_CHECK(acquireCollection(opCtx(), + {inexistentNss, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX), + ExceptionFor<ErrorCodes::StaleDbVersion>, + [&](const DBException& ex) { + const auto exInfo = ex.extraInfo<StaleDbRoutingVersion>(); + ASSERT_EQ(dbNameTestDb.db(), exInfo->getDb()); + ASSERT_EQ(incorrectDbVersion, exInfo->getVersionReceived()); + ASSERT_EQ(dbVersionTestDb, exInfo->getVersionWanted()); + ASSERT_FALSE(exInfo->getCriticalSectionSignal().is_initialized()); + }); +} + +TEST_F(ShardRoleTest, AcquireCollectionButItIsAView) { + ASSERT_THROWS_CODE( + acquireCollection( + opCtx(), + {nssView, + CollectionOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX), + DBException, + ErrorCodes::CommandNotSupportedOnView); + + const auto acquisition = acquireCollectionOrView( + opCtx(), + {nssView, + CollectionOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite, + AcquisitionPrerequisites::kCanBeView}, + MODE_IX); + + ASSERT_TRUE(std::holds_alternative<ScopedViewAcquisition>(acquisition)); + const ScopedViewAcquisition& viewAcquisition = std::get<ScopedViewAcquisition>(acquisition); + + ASSERT_EQ(nssView, viewAcquisition.nss()); + ASSERT_EQ(nssUnshardedCollection1, viewAcquisition.getViewDefinition().viewOn()); + ASSERT(std::equal(viewPipeline.begin(), + viewPipeline.end(), + viewAcquisition.getViewDefinition().pipeline().begin(), + SimpleBSONObjComparator::kInstance.makeEqualTo())); } // --------------------------------------------------------------------------- // Acquire multiple collections TEST_F(ShardRoleTest, AcquireMultipleCollectionsAllWithCorrectPlacementConcern) { - const auto acquisitions = acquireCollectionsOrViews( + const auto acquisitions = acquireCollections( opCtx(), {{nssUnshardedCollection1, AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, ShardVersion::UNSHARDED()}, repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}, + AcquisitionPrerequisites::kWrite}, {nssShardedCollection1, AcquisitionPrerequisites::PlacementConcern{{}, shardVersionShardedCollection1}, repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, + AcquisitionPrerequisites::kWrite}}, MODE_IX); ASSERT_EQ(2, acquisitions.size()); @@ -588,7 +618,6 @@ TEST_F(ShardRoleTest, AcquireMultipleCollectionsAllWithCorrectPlacementConcern) return acquisition.nss() == nss; }); ASSERT(acquisitionUnshardedColl != acquisitions.end()); - ASSERT_FALSE(acquisitionUnshardedColl->isView()); ASSERT_FALSE(acquisitionUnshardedColl->getShardingDescription().isSharded()); ASSERT_FALSE(acquisitionUnshardedColl->getCollectionFilter().has_value()); @@ -599,7 +628,6 @@ TEST_F(ShardRoleTest, AcquireMultipleCollectionsAllWithCorrectPlacementConcern) return acquisition.nss() == nss; }); ASSERT(acquisitionShardedColl != acquisitions.end()); - ASSERT_FALSE(acquisitionShardedColl->isView()); ASSERT_TRUE(acquisitionShardedColl->getShardingDescription().isSharded()); ASSERT_TRUE(acquisitionShardedColl->getCollectionFilter().has_value()); @@ -614,20 +642,18 @@ TEST_F(ShardRoleTest, AcquireMultipleCollectionsAllWithCorrectPlacementConcern) TEST_F(ShardRoleTest, AcquireMultipleCollectionsWithIncorrectPlacementConcernThrows) { ASSERT_THROWS_WITH_CHECK( - acquireCollectionsOrViews(opCtx(), - {{nssUnshardedCollection1, - AcquisitionPrerequisites::PlacementConcern{ - dbVersionTestDb, ShardVersion::UNSHARDED()}, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}, - {nssShardedCollection1, - AcquisitionPrerequisites::PlacementConcern{ - dbVersionTestDb, ShardVersion::UNSHARDED()}, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX), + acquireCollections(opCtx(), + {{nssUnshardedCollection1, + AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, + ShardVersion::UNSHARDED()}, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + {nssShardedCollection1, + AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, + ShardVersion::UNSHARDED()}, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}}, + MODE_IX), ExceptionFor<ErrorCodes::StaleConfig>, [&](const DBException& ex) { const auto exInfo = ex.extraInfo<StaleConfigInfo>(); @@ -643,18 +669,16 @@ DEATH_TEST_REGEX_F(ShardRoleTest, ForbiddenToAcquireMultipleCollectionsOnDifferentDatabases, "Tripwire assertion") { ASSERT_THROWS_CODE( - acquireCollectionsOrViews( + acquireCollections( opCtx(), {{nssUnshardedCollection1, - NamespaceOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection, + CollectionOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection, repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}, + AcquisitionPrerequisites::kWrite}, {NamespaceString::createNamespaceString_forTest("anotherDb", "foo"), - NamespaceOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection, + CollectionOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection, repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, + AcquisitionPrerequisites::kWrite}}, MODE_IX), DBException, 7300400); @@ -665,78 +689,67 @@ DEATH_TEST_REGEX_F(ShardRoleTest, TEST_F(ShardRoleTest, AcquireCollectionByUUID) { const auto uuid = getCollectionUUID(opCtx(), nssUnshardedCollection1); - const auto acquisitions = acquireCollectionsOrViews( + const auto acquisition = acquireCollection( opCtx(), - {{NamespaceStringOrUUID(dbNameTestDb, uuid), - AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, ShardVersion::UNSHARDED()}, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, + {NamespaceStringOrUUID(dbNameTestDb, uuid), + AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, ShardVersion::UNSHARDED()}, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, MODE_IX); - ASSERT_EQ(1, acquisitions.size()); - ASSERT_EQ(nssUnshardedCollection1, acquisitions.front().nss()); - ASSERT_EQ(nssUnshardedCollection1, acquisitions.front().getCollectionPtr()->ns()); + ASSERT_EQ(nssUnshardedCollection1, acquisition.nss()); + ASSERT_EQ(nssUnshardedCollection1, acquisition.getCollectionPtr()->ns()); } TEST_F(ShardRoleTest, AcquireCollectionByUUIDButWrongDbNameThrows) { const auto uuid = getCollectionUUID(opCtx(), nssUnshardedCollection1); - ASSERT_THROWS_CODE(acquireCollectionsOrViews(opCtx(), - {{NamespaceStringOrUUID("anotherDbName", uuid), - {}, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX), + ASSERT_THROWS_CODE(acquireCollection(opCtx(), + {NamespaceStringOrUUID("anotherDbName", uuid), + {}, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX), DBException, ErrorCodes::NamespaceNotFound); } TEST_F(ShardRoleTest, AcquireCollectionByWrongUUID) { const auto uuid = UUID::gen(); - ASSERT_THROWS_CODE(acquireCollectionsOrViews(opCtx(), - {{NamespaceStringOrUUID(dbNameTestDb, uuid), - {}, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX), + ASSERT_THROWS_CODE(acquireCollection(opCtx(), + {NamespaceStringOrUUID(dbNameTestDb, uuid), + {}, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX), DBException, ErrorCodes::NamespaceNotFound); } // --------------------------------------------------------------------------- -// Acquire collection by nss and expected UUID +// Acquire by nss and expected UUID TEST_F(ShardRoleTest, AcquireCollectionByNssAndExpectedUUID) { const auto uuid = getCollectionUUID(opCtx(), nssUnshardedCollection1); - const auto acquisitions = - acquireCollectionsOrViews(opCtx(), - {{nssUnshardedCollection1, - uuid, - {}, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX); - - ASSERT_EQ(1, acquisitions.size()); - ASSERT_EQ(nssUnshardedCollection1, acquisitions.front().nss()); - ASSERT_EQ(nssUnshardedCollection1, acquisitions.front().getCollectionPtr()->ns()); + const auto acquisition = acquireCollection(opCtx(), + {nssUnshardedCollection1, + uuid, + {}, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite}, + MODE_IX); + + ASSERT_EQ(nssUnshardedCollection1, acquisition.nss()); + ASSERT_EQ(nssUnshardedCollection1, acquisition.getCollectionPtr()->ns()); } TEST_F(ShardRoleTest, AcquireCollectionByNssAndWrongExpectedUUIDThrows) { const auto nss = nssUnshardedCollection1; const auto wrongUuid = UUID::gen(); ASSERT_THROWS_WITH_CHECK( - acquireCollectionsOrViews(opCtx(), - {{nss, - wrongUuid, - {}, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX), + acquireCollection( + opCtx(), + {nss, wrongUuid, {}, repl::ReadConcernArgs(), AcquisitionPrerequisites::kWrite}, + MODE_IX), ExceptionFor<ErrorCodes::CollectionUUIDMismatch>, [&](const DBException& ex) { const auto exInfo = ex.extraInfo<CollectionUUIDMismatchInfo>(); @@ -747,6 +760,64 @@ TEST_F(ShardRoleTest, AcquireCollectionByNssAndWrongExpectedUUIDThrows) { }); } +TEST_F(ShardRoleTest, AcquireViewWithExpectedUUIDAlwaysThrows) { + // Because views don't really have a uuid. + const auto expectedUUID = UUID::gen(); + ASSERT_THROWS_CODE(acquireCollectionsOrViews(opCtx(), + {{nssView, + expectedUUID, + {}, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite, + AcquisitionPrerequisites::kCanBeView}}, + MODE_IX), + DBException, + ErrorCodes::CollectionUUIDMismatch); +} + +// --------------------------------------------------------------------------- +// Acquire collection or view + +TEST_F(ShardRoleTest, AcquireCollectionOrView) { + ASSERT_THROWS_CODE(acquireCollectionOrView(opCtx(), + { + nssView, + {}, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite, + AcquisitionPrerequisites::kMustBeCollection, + }, + MODE_IX), + DBException, + ErrorCodes::CommandNotSupportedOnView); + + { + auto acquisition = acquireCollectionOrView(opCtx(), + { + nssView, + {}, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite, + AcquisitionPrerequisites::kCanBeView, + }, + MODE_IX); + ASSERT_TRUE(std::holds_alternative<ScopedViewAcquisition>(acquisition)); + } + + { + auto acquisition = acquireCollectionOrView(opCtx(), + { + nssUnshardedCollection1, + {}, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite, + AcquisitionPrerequisites::kCanBeView, + }, + MODE_IX); + ASSERT_TRUE(std::holds_alternative<ScopedCollectionAcquisition>(acquisition)); + } +} + // --------------------------------------------------------------------------- // Yield and restore @@ -755,14 +826,14 @@ TEST_F(ShardRoleTest, YieldAndRestoreAcquisitionWithLocks) { AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, ShardVersion::UNSHARDED()}; - const auto acquisition = - acquireCollectionsOrViews(opCtx(), - {{nss, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX); + const auto acquisition = acquireCollection(opCtx(), + { + nss, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite, + }, + MODE_IX); ASSERT_TRUE(opCtx()->lockState()->isDbLockedForMode(nss.db(), MODE_IX)); ASSERT_TRUE(opCtx()->lockState()->isCollectionLockedForMode(nss, MODE_IX)); @@ -783,14 +854,10 @@ TEST_F(ShardRoleTest, RestoreForWriteFailsIfPlacementConcernNoLongerMet) { AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{{}, shardVersionShardedCollection1}; - const auto acquisition = - acquireCollectionsOrViews(opCtx(), - {{nss, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX); + const auto acquisition = acquireCollection( + opCtx(), + {nss, placementConcern, repl::ReadConcernArgs(), AcquisitionPrerequisites::kWrite}, + MODE_IX); // Yield the resources auto yieldedTransactionResources = yieldTransactionResourcesFromOperationContext(opCtx()); @@ -836,17 +903,17 @@ TEST_F(ShardRoleTest, RestoreWithShardVersionIgnored) { AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{{}, ShardVersion::IGNORED()}; - const auto acquisition = - acquireCollectionsOrViews(opCtx(), - {{nss, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kWrite, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX); - - ASSERT_TRUE(acquisition.front().getShardingDescription().isSharded()); - ASSERT_TRUE(acquisition.front().getCollectionFilter().has_value()); + const auto acquisition = acquireCollection(opCtx(), + { + nss, + placementConcern, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite, + }, + MODE_IX); + + ASSERT_TRUE(acquisition.getShardingDescription().isSharded()); + ASSERT_TRUE(acquisition.getCollectionFilter().has_value()); // Yield the resources auto yieldedTransactionResources = yieldTransactionResourcesFromOperationContext(opCtx()); @@ -881,14 +948,8 @@ void ShardRoleTest::testRestoreFailsIfCollectionNoLongerExists( AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{{}, shardVersionShardedCollection1}; - const auto acquisition = - acquireCollectionsOrViews(opCtx(), - {{nss, - placementConcern, - repl::ReadConcernArgs(), - operationType, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX); + const auto acquisition = acquireCollection( + opCtx(), {nss, placementConcern, repl::ReadConcernArgs(), operationType}, MODE_IX); // Yield the resources auto yieldedTransactionResources = yieldTransactionResourcesFromOperationContext(opCtx()); @@ -918,14 +979,8 @@ void ShardRoleTest::testRestoreFailsIfCollectionRenamed( AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, ShardVersion::UNSHARDED()}; - const auto acquisition = - acquireCollectionsOrViews(opCtx(), - {{nss, - placementConcern, - repl::ReadConcernArgs(), - operationType, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX); + const auto acquisition = acquireCollection( + opCtx(), {nss, placementConcern, repl::ReadConcernArgs(), operationType}, MODE_IX); // Yield the resources auto yieldedTransactionResources = yieldTransactionResourcesFromOperationContext(opCtx()); @@ -961,14 +1016,8 @@ void ShardRoleTest::testRestoreFailsIfCollectionDroppedAndRecreated( AcquisitionPrerequisites::PlacementConcern placementConcern = AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, ShardVersion::UNSHARDED()}; - const auto acquisition = - acquireCollectionsOrViews(opCtx(), - {{nss, - placementConcern, - repl::ReadConcernArgs(), - operationType, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX); + const auto acquisition = acquireCollection( + opCtx(), {nss, placementConcern, repl::ReadConcernArgs(), operationType}, MODE_IX); // Yield the resources auto yieldedTransactionResources = yieldTransactionResourcesFromOperationContext(opCtx()); @@ -1002,14 +1051,10 @@ TEST_F(ShardRoleTest, RestoreForReadSucceedsEvenIfPlacementHasChanged) { SharedSemiFuture<void> ongoingQueriesCompletionFuture; { - const auto acquisition = - acquireCollectionsOrViews(opCtx(), - {{nss, - placementConcern, - repl::ReadConcernArgs(), - AcquisitionPrerequisites::kRead, - AcquisitionPrerequisites::kMustBeCollection}}, - MODE_IX); + const auto acquisition = acquireCollection( + opCtx(), + {nss, placementConcern, repl::ReadConcernArgs(), AcquisitionPrerequisites::kRead}, + MODE_IX); ongoingQueriesCompletionFuture = CollectionShardingRuntime::assertCollectionLockedAndAcquireShared(opCtx(), nss) @@ -1021,8 +1066,8 @@ TEST_F(ShardRoleTest, RestoreForReadSucceedsEvenIfPlacementHasChanged) { auto yieldedTransactionResources = yieldTransactionResourcesFromOperationContext(opCtx()); ASSERT_FALSE(ongoingQueriesCompletionFuture.isReady()); - ASSERT_TRUE(acquisition.front().getCollectionFilter().has_value()); - ASSERT_TRUE(acquisition.front().getCollectionFilter()->keyBelongsToMe(BSON("skey" << 0))); + ASSERT_TRUE(acquisition.getCollectionFilter().has_value()); + ASSERT_TRUE(acquisition.getCollectionFilter()->keyBelongsToMe(BSON("skey" << 0))); // Placement changes const auto newShardVersion = [&]() { @@ -1051,13 +1096,59 @@ TEST_F(ShardRoleTest, RestoreForReadSucceedsEvenIfPlacementHasChanged) { // Even though placement has changed, the filter (and preserver) still point to the original // placement. - ASSERT_TRUE(acquisition.front().getCollectionFilter().has_value()); - ASSERT_TRUE(acquisition.front().getCollectionFilter()->keyBelongsToMe(BSON("skey" << 0))); + ASSERT_TRUE(acquisition.getCollectionFilter().has_value()); + ASSERT_TRUE(acquisition.getCollectionFilter()->keyBelongsToMe(BSON("skey" << 0))); } // Acquisition released. Now the range is no longer in use. ASSERT_TRUE(ongoingQueriesCompletionFuture.isReady()); } +DEATH_TEST_REGEX_F(ShardRoleTest, YieldingViewAcquisitionIsForbidden, "Tripwire assertion") { + const auto acquisition = acquireCollectionsOrViews( + opCtx(), + {{nssView, + CollectionOrViewAcquisitionRequest::kPretendUnshardedDueToDirectConnection, + repl::ReadConcernArgs(), + AcquisitionPrerequisites::kWrite, + AcquisitionPrerequisites::kCanBeView}}, + MODE_IX); + + ASSERT_THROWS_CODE( + yieldTransactionResourcesFromOperationContext(opCtx()), DBException, 7300502); +} + +void ShardRoleTest::testRestoreFailsIfCollectionIsNowAView( + AcquisitionPrerequisites::OperationType operationType) { + const auto nss = nssUnshardedCollection1; + AcquisitionPrerequisites::PlacementConcern placementConcern = + AcquisitionPrerequisites::PlacementConcern{dbVersionTestDb, ShardVersion::UNSHARDED()}; + + const auto acquisition = acquireCollection( + opCtx(), {nss, placementConcern, repl::ReadConcernArgs(), operationType}, MODE_IX); + + // Yield the resources. + auto yieldedTransactionResources = yieldTransactionResourcesFromOperationContext(opCtx()); + + // Drop collection and create a view in its place. + { + DBDirectClient client(opCtx()); + client.dropCollection(nss); + createTestView(opCtx(), nss, nssShardedCollection1, {}); + } + + // Restore should fail. + ASSERT_THROWS_CODE(restoreTransactionResourcesToOperationContext( + opCtx(), std::move(yieldedTransactionResources)), + DBException, + ErrorCodes::CollectionUUIDMismatch); +} +TEST_F(ShardRoleTest, RestoreForReadFailsIfCollectionIsNowAView) { + testRestoreFailsIfCollectionIsNowAView(AcquisitionPrerequisites::kRead); +} +TEST_F(ShardRoleTest, RestoreForWriteFailsIfCollectionIsNowAView) { + testRestoreFailsIfCollectionIsNowAView(AcquisitionPrerequisites::kWrite); +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/transaction_resources.cpp b/src/mongo/db/transaction_resources.cpp index da48397c968..74398217cca 100644 --- a/src/mongo/db/transaction_resources.cpp +++ b/src/mongo/db/transaction_resources.cpp @@ -39,12 +39,14 @@ void TransactionResources::releaseAllResourcesOnCommitOrAbort() noexcept { locker.reset(); lockSnapshot.reset(); acquiredCollections.clear(); + acquiredViews.clear(); } TransactionResources::~TransactionResources() { invariant(!locker); invariant(!lockSnapshot); invariant(acquiredCollections.empty()); + invariant(acquiredViews.empty()); } } // namespace shard_role_details diff --git a/src/mongo/db/transaction_resources.h b/src/mongo/db/transaction_resources.h index 8ac30e91744..fd95262496b 100644 --- a/src/mongo/db/transaction_resources.h +++ b/src/mongo/db/transaction_resources.h @@ -37,6 +37,7 @@ #include "mongo/db/operation_context.h" #include "mongo/db/repl/read_concern_args.h" #include "mongo/db/s/scoped_collection_metadata.h" +#include "mongo/db/views/view.h" #include "mongo/s/shard_version.h" #include "mongo/util/uuid.h" @@ -83,6 +84,15 @@ struct AcquiredCollection { CollectionPtr collectionPtr; }; +struct AcquiredView { + AcquisitionPrerequisites prerequisites; + + std::shared_ptr<Lock::DBLock> dbLock; + boost::optional<Lock::CollectionLock> collectionLock; + + std::shared_ptr<const ViewDefinition> viewDefinition; +}; + /** * This class is a container for all the collection resources which are currently acquired by a * given operation. Operations consist of one or more transactions, which "acquire" and "release" @@ -130,13 +140,16 @@ struct TransactionResources { ~TransactionResources(); - // void addAcquiredCollection(const NamespaceString& nss, UUID uuid); const AcquiredCollection& addAcquiredCollection(AcquiredCollection&& acquiredCollection) { return acquiredCollections.emplace_back(std::move(acquiredCollection)); } void releaseCollection(UUID uuid); + const AcquiredView& addAcquiredView(AcquiredView&& acquiredView) { + return acquiredViews.emplace_back(std::move(acquiredView)); + } + void releaseAllResourcesOnCommitOrAbort() noexcept; // The read concern with which the whole operation started. Remains the same for the duration of @@ -169,6 +182,7 @@ struct TransactionResources { // Set of all collections which are currently acquired std::list<AcquiredCollection> acquiredCollections; + std::list<AcquiredView> acquiredViews; }; } // namespace shard_role_details |