summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/shard_role.cpp170
-rw-r--r--src/mongo/db/shard_role.h158
-rw-r--r--src/mongo/db/shard_role_test.cpp721
-rw-r--r--src/mongo/db/transaction_resources.cpp2
-rw-r--r--src/mongo/db/transaction_resources.h16
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