summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuhong Zhang <danielzhangyh@gmail.com>2021-09-29 22:26:32 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-09-29 22:56:26 +0000
commit7591af2652cd1d00f9255033dc5ec3c3d82deca3 (patch)
tree3e11f2a45e09155beca9ad66bbce522c49623b36
parenta6810aa4a19bc5c0330494778e73e6c7cbcc21f8 (diff)
downloadmongo-7591af2652cd1d00f9255033dc5ec3c3d82deca3.tar.gz
SERVER-60156 Add a way to bypass storageValid() for time-series updates
-rw-r--r--src/mongo/db/exec/update_stage.cpp2
-rw-r--r--src/mongo/db/exec/upsert_stage.cpp2
-rw-r--r--src/mongo/db/ops/parsed_update.cpp5
-rw-r--r--src/mongo/db/update/array_culling_node.cpp2
-rw-r--r--src/mongo/db/update/modifier_node.cpp2
-rw-r--r--src/mongo/db/update/modifier_node.h2
-rw-r--r--src/mongo/db/update/object_replace_executor.cpp13
-rw-r--r--src/mongo/db/update/pop_node.cpp2
-rw-r--r--src/mongo/db/update/storage_validation.cpp12
-rw-r--r--src/mongo/db/update/storage_validation.h22
-rw-r--r--src/mongo/db/update/unset_node.cpp4
-rw-r--r--src/mongo/db/update/update_driver.cpp1
-rw-r--r--src/mongo/db/update/update_driver.h8
-rw-r--r--src/mongo/db/update/update_executor.h4
14 files changed, 51 insertions, 30 deletions
diff --git a/src/mongo/db/exec/update_stage.cpp b/src/mongo/db/exec/update_stage.cpp
index 2b6e3afddb9..f202f93d447 100644
--- a/src/mongo/db/exec/update_stage.cpp
+++ b/src/mongo/db/exec/update_stage.cpp
@@ -133,7 +133,7 @@ UpdateStage::UpdateStage(ExpressionContext* expCtx,
_idReturning(WorkingSet::INVALID_ID),
_updatedRecordIds(params.request->isMulti() ? new RecordIdSet() : nullptr) {
- // Should the modifiers validate their embedded docs via storage_validation::storageValid()?
+ // Should the modifiers validate their embedded docs via storage_validation::scanDocument()?
// Only user updates should be checked. Any system or replication stuff should pass through.
const auto request = _params.request;
diff --git a/src/mongo/db/exec/upsert_stage.cpp b/src/mongo/db/exec/upsert_stage.cpp
index 035419f4c39..ce29c419b7d 100644
--- a/src/mongo/db/exec/upsert_stage.cpp
+++ b/src/mongo/db/exec/upsert_stage.cpp
@@ -283,7 +283,7 @@ void UpsertStage::_assertDocumentToBeInsertedIsValid(const mb::Document& documen
serverGlobalParams.featureCompatibility.isVersionInitialized() &&
serverGlobalParams.featureCompatibility.isGreaterThanOrEqualTo(
multiversion::FeatureCompatibilityVersion::kFullyDowngradedTo_5_0);
- storage_validation::storageValid(document,
+ storage_validation::scanDocument(document,
allowTopLevelDollarPrefixes,
true, /* Should validate for storage */
&containsDotsAndDollarsField);
diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp
index f36bee843fb..2d4df260b1a 100644
--- a/src/mongo/db/ops/parsed_update.cpp
+++ b/src/mongo/db/ops/parsed_update.cpp
@@ -182,6 +182,11 @@ void ParsedUpdate::parseUpdate() {
_driver.setCollator(_expCtx->getCollator());
_driver.setLogOp(true);
_driver.setFromOplogApplication(_request->isFromOplogApplication());
+ // Time-series operations will not result in any documents with dots or dollars fields.
+ if (auto source = _request->source(); source == OperationSource::kTimeseriesInsert ||
+ source == OperationSource::kTimeseriesUpdate) {
+ _driver.setSkipDotsDollarsCheck(true);
+ }
_driver.parse(_request->getUpdateModification(),
_arrayFilters,
diff --git a/src/mongo/db/update/array_culling_node.cpp b/src/mongo/db/update/array_culling_node.cpp
index ef6c85e45d3..76e2dd25780 100644
--- a/src/mongo/db/update/array_culling_node.cpp
+++ b/src/mongo/db/update/array_culling_node.cpp
@@ -70,7 +70,7 @@ void ArrayCullingNode::validateUpdate(mutablebson::ConstElement updatedElement,
// override validateUpdate to not validate storage constraints but we still want to know if
// there is any field name containing '.'/'$'.
bool doRecursiveCheck = true;
- storage_validation::storageValid(updatedElement,
+ storage_validation::scanDocument(updatedElement,
doRecursiveCheck,
recursionLevel,
false, /* allowTopLevelDollarPrefixedFields */
diff --git a/src/mongo/db/update/modifier_node.cpp b/src/mongo/db/update/modifier_node.cpp
index c8c3327cc82..d1872b411ac 100644
--- a/src/mongo/db/update/modifier_node.cpp
+++ b/src/mongo/db/update/modifier_node.cpp
@@ -375,7 +375,7 @@ void ModifierNode::validateUpdate(mutablebson::ConstElement updatedElement,
bool* containsDotsAndDollarsField) const {
const bool doRecursiveCheck = true;
- storage_validation::storageValid(updatedElement,
+ storage_validation::scanDocument(updatedElement,
doRecursiveCheck,
recursionLevel,
false, /* allowTopLevelDollarPrefixedFields */
diff --git a/src/mongo/db/update/modifier_node.h b/src/mongo/db/update/modifier_node.h
index 53ec3e7f375..42bb70ee336 100644
--- a/src/mongo/db/update/modifier_node.h
+++ b/src/mongo/db/update/modifier_node.h
@@ -103,7 +103,7 @@ protected:
/**
* ModifierNode::apply() calls this method after it finishes applying its update to validate
* that no changes resulted in an invalid document. See the implementation of
- * storage_validation::storageValid() for more detail about document validation requirements.
+ * storage_validation::scanDocument() for more detail about document validation requirements.
* Most ModifierNode child classes can use the default implementation of this method.
*
* - 'updatedElement' is the element that was set by either updateExistingElement() or
diff --git a/src/mongo/db/update/object_replace_executor.cpp b/src/mongo/db/update/object_replace_executor.cpp
index 22af1870f62..e2d9262e001 100644
--- a/src/mongo/db/update/object_replace_executor.cpp
+++ b/src/mongo/db/update/object_replace_executor.cpp
@@ -105,11 +105,14 @@ UpdateExecutor::ApplyResult ObjectReplaceExecutor::applyReplacementUpdate(
ApplyResult ret;
- // Validate for storage and check if the document contains any '.'/'$' field name.
- storage_validation::storageValid(applyParams.element.getDocument(),
- allowTopLevelDollarPrefixedFields,
- applyParams.validateForStorage,
- &ret.containsDotsAndDollarsField);
+ if (!applyParams.skipDotsDollarsCheck || applyParams.validateForStorage) {
+ // Validate for storage and check if the document contains any '.'/'$' field name. We pass
+ // 'containsDotsAndDollarsField' unconditionally for now.
+ storage_validation::scanDocument(applyParams.element.getDocument(),
+ allowTopLevelDollarPrefixedFields,
+ applyParams.validateForStorage,
+ &ret.containsDotsAndDollarsField);
+ }
// Check immutable paths.
for (auto path = applyParams.immutablePaths.begin(); path != applyParams.immutablePaths.end();
diff --git a/src/mongo/db/update/pop_node.cpp b/src/mongo/db/update/pop_node.cpp
index c15f26fe790..c7942a32aa9 100644
--- a/src/mongo/db/update/pop_node.cpp
+++ b/src/mongo/db/update/pop_node.cpp
@@ -82,7 +82,7 @@ void PopNode::validateUpdate(mutablebson::ConstElement updatedElement,
// override validateUpdate to not validate storage constraints but we still want to know if
// there is any field name containing '.'/'$'.
bool doRecursiveCheck = true;
- storage_validation::storageValid(updatedElement,
+ storage_validation::scanDocument(updatedElement,
doRecursiveCheck,
recursionLevel,
false, /* allowTopLevelDollarPrefixedFields */
diff --git a/src/mongo/db/update/storage_validation.cpp b/src/mongo/db/update/storage_validation.cpp
index 3e04bf45f35..d94c645a588 100644
--- a/src/mongo/db/update/storage_validation.cpp
+++ b/src/mongo/db/update/storage_validation.cpp
@@ -44,7 +44,7 @@ namespace {
const StringData idFieldName = "_id"_sd;
-void storageValidChildren(mutablebson::ConstElement elem,
+void scanDocumentChildren(mutablebson::ConstElement elem,
const bool deep,
std::uint32_t recursionLevel,
const bool allowTopLevelDollarPrefixes,
@@ -56,7 +56,7 @@ void storageValidChildren(mutablebson::ConstElement elem,
auto curr = elem.leftChild();
while (curr.ok()) {
- storageValid(curr,
+ scanDocument(curr,
deep,
recursionLevel + 1,
allowTopLevelDollarPrefixes,
@@ -153,7 +153,7 @@ Status storageValidIdField(const mongo::BSONElement& element) {
return Status::OK();
}
-void storageValid(const mutablebson::Document& doc,
+void scanDocument(const mutablebson::Document& doc,
const bool allowTopLevelDollarPrefixes,
const bool shouldValidate,
bool* containsDotsAndDollarsField) {
@@ -166,7 +166,7 @@ void storageValid(const mutablebson::Document& doc,
// Validate this child element.
const auto deep = true;
const uint32_t recursionLevel = 1;
- storageValid(currElem,
+ scanDocument(currElem,
deep,
recursionLevel,
allowTopLevelDollarPrefixes,
@@ -177,7 +177,7 @@ void storageValid(const mutablebson::Document& doc,
}
}
-void storageValid(mutablebson::ConstElement elem,
+void scanDocument(mutablebson::ConstElement elem,
const bool deep,
std::uint32_t recursionLevel,
const bool allowTopLevelDollarPrefixes,
@@ -223,7 +223,7 @@ void storageValid(mutablebson::ConstElement elem,
if (deep) {
// Check children if there are any.
- storageValidChildren(elem,
+ scanDocumentChildren(elem,
deep,
recursionLevel,
allowTopLevelDollarPrefixes,
diff --git a/src/mongo/db/update/storage_validation.h b/src/mongo/db/update/storage_validation.h
index 381abf66a9b..c1ce7e5a951 100644
--- a/src/mongo/db/update/storage_validation.h
+++ b/src/mongo/db/update/storage_validation.h
@@ -42,12 +42,11 @@ namespace storage_validation {
Status storageValidIdField(const mongo::BSONElement& element);
/**
- * Validates that the MutableBSON document 'doc' is acceptable for storage in a collection. The
- * check is performed recursively on subdocuments. Uasserts if the validation fails or if the depth
- * exceeds the maximum allowable depth.
- *
- * If 'allowTopLevelDollarPrefixes' is set to false, reject $-prefixed fields at the top-level of a
- document.
+ * Validates that the MutableBSON document 'doc' is acceptable for storage in a collection and
+ * checks if there exists any field name containing '.'/'$'. The check is performed recursively on
+ * subdocuments. Uasserts if the validation fails or if the depth exceeds the maximum allowable
+ * depth. If 'allowTopLevelDollarPrefixes' is set to false, reject $-prefixed fields at the
+ * top-level of a document.
* 'shouldValidate' is true if the caller wants to validate for storage, otherwise this helper will
* only check top-level $-prefixed field names skipping all the validations.
@@ -55,15 +54,16 @@ Status storageValidIdField(const mongo::BSONElement& element);
* 'containsDotsAndDollarsField' is set to true if there exists any field name containing '.'/'$'
* during validation.
*/
-void storageValid(const mutablebson::Document& doc,
+void scanDocument(const mutablebson::Document& doc,
bool allowTopLevelDollarPrefixes,
bool shouldValidate,
bool* containsDotsAndDollarsField);
/**
- * Validates that the MutableBSON element 'elem' is acceptable for storage in a collection. If
- * 'deep' is true, the check is performed recursively on subdocuments. Uasserts if the validation
- * fails or if 'recursionLevel' exceeds the maximum allowable depth.
+ * Validates that the MutableBSON element 'elem' is acceptable for storage in a collection and
+ * checks if there exists any field name containing '.'/'$'. If 'deep' is true, the check is
+ * performed recursively on subdocuments. Uasserts if the validation fails or if 'recursionLevel'
+ * exceeds the maximum allowable depth.
*
* If 'allowTopLevelDollarPrefixes' is set to false, reject $-prefixed fields at the top-level of a
* document.
@@ -74,7 +74,7 @@ void storageValid(const mutablebson::Document& doc,
* 'containsDotsAndDollarsField' is set to true if there exists any field name containing '.'/'$'
* during validation.
*/
-void storageValid(mutablebson::ConstElement elem,
+void scanDocument(mutablebson::ConstElement elem,
bool deep,
std::uint32_t recursionLevel,
bool allowTopLevelDollarPrefixes,
diff --git a/src/mongo/db/update/unset_node.cpp b/src/mongo/db/update/unset_node.cpp
index 75612dba4be..be814cc73d1 100644
--- a/src/mongo/db/update/unset_node.cpp
+++ b/src/mongo/db/update/unset_node.cpp
@@ -72,7 +72,7 @@ void UnsetNode::validateUpdate(mutablebson::ConstElement updatedElement,
const uint32_t recursionLevelForCheck = 0;
if (leftSibling.ok()) {
- storage_validation::storageValid(leftSibling,
+ storage_validation::scanDocument(leftSibling,
doRecursiveCheck,
recursionLevelForCheck,
false, /* allowTopLevelDollarPrefixedFields */
@@ -81,7 +81,7 @@ void UnsetNode::validateUpdate(mutablebson::ConstElement updatedElement,
}
if (rightSibling.ok()) {
- storage_validation::storageValid(rightSibling,
+ storage_validation::scanDocument(rightSibling,
doRecursiveCheck,
recursionLevelForCheck,
false, /* allowTopLevelDollarPrefixedFields */
diff --git a/src/mongo/db/update/update_driver.cpp b/src/mongo/db/update/update_driver.cpp
index 2dd809aa99b..0df3cf38098 100644
--- a/src/mongo/db/update/update_driver.cpp
+++ b/src/mongo/db/update/update_driver.cpp
@@ -271,6 +271,7 @@ Status UpdateDriver::update(OperationContext* opCtx,
applyParams.matchedField = matchedField;
applyParams.insert = isInsert;
applyParams.fromOplogApplication = _fromOplogApplication;
+ applyParams.skipDotsDollarsCheck = _skipDotsDollarsCheck;
applyParams.validateForStorage = validateForStorage;
applyParams.indexData = _indexedFields;
applyParams.modifiedPaths = modifiedPaths;
diff --git a/src/mongo/db/update/update_driver.h b/src/mongo/db/update/update_driver.h
index 96f34b4cfaf..0f3fb02f455 100644
--- a/src/mongo/db/update/update_driver.h
+++ b/src/mongo/db/update/update_driver.h
@@ -174,6 +174,10 @@ public:
_fromOplogApplication = fromOplogApplication;
}
+ void setSkipDotsDollarsCheck(bool skipDotsDollarsCheck) {
+ _skipDotsDollarsCheck = skipDotsDollarsCheck;
+ }
+
mutablebson::Document& getDocument() {
return _objDoc;
}
@@ -237,6 +241,10 @@ private:
// True if this update comes from an oplog application.
bool _fromOplogApplication = false;
+ // True if this update is guaranteed not to contain dots or dollars fields and should skip the
+ // check.
+ bool _skipDotsDollarsCheck = false;
+
boost::intrusive_ptr<ExpressionContext> _expCtx;
// Are any of the fields mentioned in the mods participating in any index? Is set anew
diff --git a/src/mongo/db/update/update_executor.h b/src/mongo/db/update/update_executor.h
index a7ef7dd0837..539f044432b 100644
--- a/src/mongo/db/update/update_executor.h
+++ b/src/mongo/db/update/update_executor.h
@@ -86,6 +86,10 @@ public:
// replication.
bool fromOplogApplication = false;
+ // If true, it is guaranteed that the document doesn't contain dots or dollars fields and
+ // should skip the check.
+ bool skipDotsDollarsCheck = false;
+
// If true, UpdateNode::apply ensures that modified elements do not violate depth or DBRef
// constraints.
bool validateForStorage = true;