summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Wlodarek <gregory.wlodarek@mongodb.com>2022-03-09 21:04:22 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-03-09 21:52:37 +0000
commitf07124df698a81e7e67023da45e8fad4d44e7628 (patch)
tree20282169c4af900eb48089b67d24d124c3418f7b
parentf27d9b694591e3267dbca65771f7c02ce7018559 (diff)
downloadmongo-f07124df698a81e7e67023da45e8fad4d44e7628.tar.gz
SERVER-64369 Must not allow deletes from capped collections in FCV 4.4
-rw-r--r--jstests/multiVersion/capped_deletes.js23
-rw-r--r--jstests/replsets/apply_ops_capped_collection.js1
-rw-r--r--src/mongo/db/catalog/collection_impl.cpp20
-rw-r--r--src/mongo/db/query/get_executor.cpp24
4 files changed, 59 insertions, 9 deletions
diff --git a/jstests/multiVersion/capped_deletes.js b/jstests/multiVersion/capped_deletes.js
new file mode 100644
index 00000000000..8aa9b7a0a49
--- /dev/null
+++ b/jstests/multiVersion/capped_deletes.js
@@ -0,0 +1,23 @@
+/**
+ * Test that user deletes on capped collections are only allowed in FCV 5.0.
+ */
+(function() {
+"use strict";
+
+const conn = MongoRunner.runMongod();
+const db = conn.getDB("test");
+
+assert.commandWorked(db.createCollection("a", {capped: true, size: 1024}));
+assert.commandWorked(db.a.insert({_id: 1}));
+assert.commandWorked(db.a.insert({_id: 2}));
+
+// FCV 5.0.
+assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
+assert.commandWorked(db.a.remove({_id: 1}));
+
+// FCV 4.4.
+assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+assert.writeErrorWithCode(db.a.remove({_id: 2}), ErrorCodes.IllegalOperation);
+
+MongoRunner.stopMongod(conn);
+})();
diff --git a/jstests/replsets/apply_ops_capped_collection.js b/jstests/replsets/apply_ops_capped_collection.js
index cfdd7ec6299..aedbcbf5840 100644
--- a/jstests/replsets/apply_ops_capped_collection.js
+++ b/jstests/replsets/apply_ops_capped_collection.js
@@ -6,6 +6,7 @@
* multiversion_incompatible,
* requires_capped,
* requires_replication,
+ * requires_fcv_50,
* ]
*/
(function() {
diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp
index faad2b4ee34..b669a982a5e 100644
--- a/src/mongo/db/catalog/collection_impl.cpp
+++ b/src/mongo/db/catalog/collection_impl.cpp
@@ -1138,9 +1138,23 @@ void CollectionImpl::deleteDocument(OperationContext* opCtx,
bool fromMigrate,
bool noWarn,
Collection::StoreDeletedDoc storeDeletedDoc) const {
- if (isCapped() && opCtx->inMultiDocumentTransaction()) {
- uasserted(ErrorCodes::IllegalOperation,
- "Cannot remove from a capped collection in a multi-document transaction");
+ if (isCapped()) {
+ const auto isFCV50 = serverGlobalParams.featureCompatibility.isVersionInitialized() &&
+ serverGlobalParams.featureCompatibility.getVersion() ==
+ ServerGlobalParams::FeatureCompatibility::Version::kVersion50;
+
+ if (isFCV50) {
+ if (opCtx->inMultiDocumentTransaction()) {
+ // User deletes outside of multi-document transacations can only happen in FCV 5.0.
+ uasserted(ErrorCodes::IllegalOperation,
+ "Cannot remove from a capped collection in a multi-document transaction");
+ }
+ } else if (opCtx->isEnforcingConstraints()) {
+ // System operations such as tenant migration or secondary batch application can delete
+ // from capped collections.
+ LOGV2(20291, "failing remove on a capped ns", "namespace"_attr = _ns);
+ uasserted(10089, "cannot remove from a capped collection");
+ }
}
std::vector<OplogSlot> oplogSlots;
diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp
index 500722734d7..7acf1ee351d 100644
--- a/src/mongo/db/query/get_executor.cpp
+++ b/src/mongo/db/query/get_executor.cpp
@@ -1327,16 +1327,28 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDele
}
}
- if (collection && collection->isCapped() && opCtx->inMultiDocumentTransaction()) {
+ if (collection && collection->isCapped()) {
// This check is duplicated from CollectionImpl::deleteDocument() for two reasons:
// - Performing a remove on an empty capped collection would not call
// CollectionImpl::deleteDocument().
// - We can avoid doing lookups on documents and erroring later when trying to delete them.
- return Status(
- ErrorCodes::IllegalOperation,
- str::stream()
- << "Cannot remove from a capped collection in a multi-document transaction: "
- << nss.ns());
+ const auto isFCV50 = serverGlobalParams.featureCompatibility.isVersionInitialized() &&
+ serverGlobalParams.featureCompatibility.getVersion() ==
+ ServerGlobalParams::FeatureCompatibility::Version::kVersion50;
+
+ if (isFCV50) {
+ if (opCtx->inMultiDocumentTransaction()) {
+ return Status(ErrorCodes::IllegalOperation,
+ str::stream() << "Cannot remove from a capped collection in a "
+ "multi-document transaction: "
+ << nss.ns());
+ }
+ } else if (opCtx->isEnforcingConstraints()) {
+ // System operations such as tenant migration or secondary batch application can delete
+ // from capped collections.
+ return Status(ErrorCodes::IllegalOperation,
+ str::stream() << "cannot remove from a capped collection: " << nss.ns());
+ }
}
bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() &&