diff options
author | James Wahlin <james@mongodb.com> | 2019-04-11 15:13:50 -0400 |
---|---|---|
committer | James Wahlin <james@mongodb.com> | 2019-04-29 16:04:49 -0400 |
commit | 71e13919c25fbf839d2a65b8c7842f9466e3876a (patch) | |
tree | 2be3105b3c00849fcbed552ce892b3eaa40f3c71 /src/mongo/db | |
parent | 59a22d074e7d690b8db0eda76747ff3985907c98 (diff) | |
download | mongo-71e13919c25fbf839d2a65b8c7842f9466e3876a.tar.gz |
SERVER-40585 UpdateNode should not derive from UpdateExecutor
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/update/SConscript | 4 | ||||
-rw-r--r-- | src/mongo/db/update/object_replace_executor.cpp (renamed from src/mongo/db/update/object_replace_node.cpp) | 13 | ||||
-rw-r--r-- | src/mongo/db/update/object_replace_executor.h (renamed from src/mongo/db/update/object_replace_node.h) | 23 | ||||
-rw-r--r-- | src/mongo/db/update/object_replace_executor_test.cpp (renamed from src/mongo/db/update/object_replace_node_test.cpp) | 76 | ||||
-rw-r--r-- | src/mongo/db/update/pipeline_executor.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/update/pipeline_executor.h | 8 | ||||
-rw-r--r-- | src/mongo/db/update/update_driver.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/update/update_driver.h | 26 | ||||
-rw-r--r-- | src/mongo/db/update/update_executor.h | 17 | ||||
-rw-r--r-- | src/mongo/db/update/update_node.h | 25 | ||||
-rw-r--r-- | src/mongo/db/update/update_node_test_fixture.h | 2 | ||||
-rw-r--r-- | src/mongo/db/update/update_node_visitor.h | 4 | ||||
-rw-r--r-- | src/mongo/db/update/update_tree_executor.h | 69 |
13 files changed, 177 insertions, 110 deletions
diff --git a/src/mongo/db/update/SConscript b/src/mongo/db/update/SConscript index 819a9c6e834..29a37605244 100644 --- a/src/mongo/db/update/SConscript +++ b/src/mongo/db/update/SConscript @@ -75,7 +75,7 @@ env.Library( 'current_date_node.cpp', 'modifier_node.cpp', 'modifier_table.cpp', - 'object_replace_node.cpp', + 'object_replace_executor.cpp', 'pipeline_executor.cpp', 'pop_node.cpp', 'pull_node.cpp', @@ -107,7 +107,7 @@ env.CppUnitTest( 'bit_node_test.cpp', 'compare_node_test.cpp', 'current_date_node_test.cpp', - 'object_replace_node_test.cpp', + 'object_replace_executor_test.cpp', 'pipeline_executor_test.cpp', 'pop_node_test.cpp', 'pull_node_test.cpp', diff --git a/src/mongo/db/update/object_replace_node.cpp b/src/mongo/db/update/object_replace_executor.cpp index 42f89906181..8a65cd1b0ca 100644 --- a/src/mongo/db/update/object_replace_node.cpp +++ b/src/mongo/db/update/object_replace_executor.cpp @@ -29,7 +29,7 @@ #include "mongo/platform/basic.h" -#include "mongo/db/update/object_replace_node.h" +#include "mongo/db/update/object_replace_executor.h" #include "mongo/base/data_view.h" #include "mongo/db/bson/dotted_path_support.h" @@ -44,10 +44,11 @@ namespace { constexpr StringData kIdFieldName = "_id"_sd; } // namespace -ObjectReplaceNode::ObjectReplaceNode(BSONObj value) : val(value.getOwned()), _containsId(false) { +ObjectReplaceExecutor::ObjectReplaceExecutor(BSONObj replacement) + : _replacementDoc(replacement.getOwned()), _containsId(false) { // Replace all zero-valued timestamps with the current time and check for the existence of _id. - for (auto&& elem : val) { + for (auto&& elem : _replacementDoc) { // Do not change the _id field. if (elem.fieldNameStringData() == kIdFieldName) { @@ -69,7 +70,7 @@ ObjectReplaceNode::ObjectReplaceNode(BSONObj value) : val(value.getOwned()), _co } } -UpdateExecutor::ApplyResult ObjectReplaceNode::applyReplacementUpdate( +UpdateExecutor::ApplyResult ObjectReplaceExecutor::applyReplacementUpdate( ApplyParams applyParams, const BSONObj& replacementDoc, bool replacementDocContainsIdField) { auto originalDoc = applyParams.element.getDocument().getObject(); @@ -153,8 +154,8 @@ UpdateExecutor::ApplyResult ObjectReplaceNode::applyReplacementUpdate( return ApplyResult(); } -UpdateExecutor::ApplyResult ObjectReplaceNode::applyUpdate(ApplyParams applyParams) const { - return applyReplacementUpdate(applyParams, val, _containsId); +UpdateExecutor::ApplyResult ObjectReplaceExecutor::applyUpdate(ApplyParams applyParams) const { + return applyReplacementUpdate(applyParams, _replacementDoc, _containsId); } } // namespace mongo diff --git a/src/mongo/db/update/object_replace_node.h b/src/mongo/db/update/object_replace_executor.h index c2c570f9093..f141f169d6f 100644 --- a/src/mongo/db/update/object_replace_node.h +++ b/src/mongo/db/update/object_replace_executor.h @@ -42,7 +42,7 @@ namespace mongo { /** * An UpdateExecutor representing a replacement-style update. */ -class ObjectReplaceNode : public UpdateExecutor { +class ObjectReplaceExecutor : public UpdateExecutor { public: // Applies a replacement style update to 'applyParams.element'. If @@ -56,9 +56,7 @@ public: * Initializes the node with the document to replace with. Any zero-valued timestamps (except * for the _id) are updated to the current time. */ - explicit ObjectReplaceNode(BSONObj value); - - void setCollator(const CollatorInterface* collator) final {} + explicit ObjectReplaceExecutor(BSONObj replacement); /** * Replaces the document that 'applyParams.element' belongs to with 'val'. If 'val' does not @@ -68,19 +66,22 @@ public: */ ApplyResult applyUpdate(ApplyParams applyParams) const final; - BSONObj serialize() const { - return val; + Value serialize() const final { + return Value(_replacementDoc); } - void acceptVisitor(UpdateNodeVisitor* visitor) final { - visitor->visit(this); + const BSONObj& getReplacement() const { + return _replacementDoc; } - // Object to replace with. - BSONObj val; + void setReplacement(BSONObj doc) { + _replacementDoc = std::move(doc); + } private: - // True if val contains an _id. + BSONObj _replacementDoc; + + // True if '_replacementDoc' contains an _id. bool _containsId; }; diff --git a/src/mongo/db/update/object_replace_node_test.cpp b/src/mongo/db/update/object_replace_executor_test.cpp index 0a0e241cf0c..cef054fd289 100644 --- a/src/mongo/db/update/object_replace_node_test.cpp +++ b/src/mongo/db/update/object_replace_executor_test.cpp @@ -29,7 +29,7 @@ #include "mongo/platform/basic.h" -#include "mongo/db/update/object_replace_node.h" +#include "mongo/db/update/object_replace_executor.h" #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" @@ -41,13 +41,13 @@ namespace mongo { namespace { -using ObjectReplaceNodeTest = UpdateNodeTest; +using ObjectReplaceExecutorTest = UpdateNodeTest; using mongo::mutablebson::Element; using mongo::mutablebson::countChildren; -TEST_F(ObjectReplaceNodeTest, Noop) { +TEST_F(ObjectReplaceExecutorTest, Noop) { auto obj = fromjson("{a: 1, b: 2}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{a: 1, b: 2}")); auto result = node.applyUpdate(getApplyParams(doc.root())); @@ -58,9 +58,9 @@ TEST_F(ObjectReplaceNodeTest, Noop) { ASSERT_EQUALS(fromjson("{}"), getLogDoc()); } -TEST_F(ObjectReplaceNodeTest, ShouldNotCreateIdIfNoIdExistsAndNoneIsSpecified) { +TEST_F(ObjectReplaceExecutorTest, ShouldNotCreateIdIfNoIdExistsAndNoneIsSpecified) { auto obj = fromjson("{a: 1, b: 2}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{c: 1, d: 2}")); auto result = node.applyUpdate(getApplyParams(doc.root())); @@ -71,9 +71,9 @@ TEST_F(ObjectReplaceNodeTest, ShouldNotCreateIdIfNoIdExistsAndNoneIsSpecified) { ASSERT_EQUALS(fromjson("{a: 1, b: 2}"), getLogDoc()); } -TEST_F(ObjectReplaceNodeTest, ShouldPreserveIdOfExistingDocumentIfIdNotSpecified) { +TEST_F(ObjectReplaceExecutorTest, ShouldPreserveIdOfExistingDocumentIfIdNotSpecified) { auto obj = fromjson("{a: 1, b: 2}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{_id: 0, c: 1, d: 2}")); auto result = node.applyUpdate(getApplyParams(doc.root())); @@ -84,9 +84,9 @@ TEST_F(ObjectReplaceNodeTest, ShouldPreserveIdOfExistingDocumentIfIdNotSpecified ASSERT_EQUALS(fromjson("{_id: 0, a: 1, b: 2}"), getLogDoc()); } -TEST_F(ObjectReplaceNodeTest, ShouldSucceedWhenImmutableIdIsNotModified) { +TEST_F(ObjectReplaceExecutorTest, ShouldSucceedWhenImmutableIdIsNotModified) { auto obj = fromjson("{_id: 0, a: 1, b: 2}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{_id: 0, c: 1, d: 2}")); addImmutablePath("_id"); @@ -98,9 +98,9 @@ TEST_F(ObjectReplaceNodeTest, ShouldSucceedWhenImmutableIdIsNotModified) { ASSERT_EQUALS(fromjson("{_id: 0, a: 1, b: 2}"), getLogDoc()); } -TEST_F(ObjectReplaceNodeTest, IdTimestampNotModified) { +TEST_F(ObjectReplaceExecutorTest, IdTimestampNotModified) { auto obj = fromjson("{_id: Timestamp(0,0)}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{}")); auto result = node.applyUpdate(getApplyParams(doc.root())); @@ -111,9 +111,9 @@ TEST_F(ObjectReplaceNodeTest, IdTimestampNotModified) { ASSERT_EQUALS(fromjson("{_id: Timestamp(0,0)}"), getLogDoc()); } -TEST_F(ObjectReplaceNodeTest, NonIdTimestampsModified) { +TEST_F(ObjectReplaceExecutorTest, NonIdTimestampsModified) { auto obj = fromjson("{a: Timestamp(0,0), b: Timestamp(0,0)}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{}")); auto result = node.applyUpdate(getApplyParams(doc.root())); @@ -138,9 +138,9 @@ TEST_F(ObjectReplaceNodeTest, NonIdTimestampsModified) { ASSERT_EQUALS(doc, getLogDoc()); } -TEST_F(ObjectReplaceNodeTest, ComplexDoc) { +TEST_F(ObjectReplaceExecutorTest, ComplexDoc) { auto obj = fromjson("{a: 1, b: [0, 1, 2], c: {d: 1}}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{a: 1, b: [0, 2, 2], e: []}")); auto result = node.applyUpdate(getApplyParams(doc.root())); @@ -151,9 +151,9 @@ TEST_F(ObjectReplaceNodeTest, ComplexDoc) { ASSERT_EQUALS(fromjson("{a: 1, b: [0, 1, 2], c: {d: 1}}"), getLogDoc()); } -TEST_F(ObjectReplaceNodeTest, CannotRemoveImmutablePath) { +TEST_F(ObjectReplaceExecutorTest, CannotRemoveImmutablePath) { auto obj = fromjson("{_id: 0, c: 1}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{_id: 0, a: {b: 1}}")); addImmutablePath("a.b"); @@ -164,9 +164,9 @@ TEST_F(ObjectReplaceNodeTest, CannotRemoveImmutablePath) { "field was found to have been removed --{ _id: 0, a: { b: 1 } }"); } -TEST_F(ObjectReplaceNodeTest, IdFieldIsNotRemoved) { +TEST_F(ObjectReplaceExecutorTest, IdFieldIsNotRemoved) { auto obj = fromjson("{a: 1}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{_id: 0, b: 1}")); addImmutablePath("_id"); @@ -178,9 +178,9 @@ TEST_F(ObjectReplaceNodeTest, IdFieldIsNotRemoved) { ASSERT_EQUALS(fromjson("{_id: 0, a: 1}"), getLogDoc()); } -TEST_F(ObjectReplaceNodeTest, CannotReplaceImmutablePathWithArrayField) { +TEST_F(ObjectReplaceExecutorTest, CannotReplaceImmutablePathWithArrayField) { auto obj = fromjson("{_id: 0, a: [{b: 1}]}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{_id: 0, a: {b: 1}}")); addImmutablePath("a.b"); @@ -191,9 +191,9 @@ TEST_F(ObjectReplaceNodeTest, CannotReplaceImmutablePathWithArrayField) { "'a.b' was found to be an array or array descendant."); } -TEST_F(ObjectReplaceNodeTest, CannotMakeImmutablePathArrayDescendant) { +TEST_F(ObjectReplaceExecutorTest, CannotMakeImmutablePathArrayDescendant) { auto obj = fromjson("{_id: 0, a: [1]}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{_id: 0, a: {'0': 1}}")); addImmutablePath("a.0"); @@ -204,9 +204,9 @@ TEST_F(ObjectReplaceNodeTest, CannotMakeImmutablePathArrayDescendant) { "'a.0' was found to be an array or array descendant."); } -TEST_F(ObjectReplaceNodeTest, CannotModifyImmutablePath) { +TEST_F(ObjectReplaceExecutorTest, CannotModifyImmutablePath) { auto obj = fromjson("{_id: 0, a: {b: 2}}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{_id: 0, a: {b: 1}}")); addImmutablePath("a.b"); @@ -217,9 +217,9 @@ TEST_F(ObjectReplaceNodeTest, CannotModifyImmutablePath) { "to have been altered to b: 2"); } -TEST_F(ObjectReplaceNodeTest, CannotModifyImmutableId) { +TEST_F(ObjectReplaceExecutorTest, CannotModifyImmutableId) { auto obj = fromjson("{_id: 1}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{_id: 0}")); addImmutablePath("_id"); @@ -230,9 +230,9 @@ TEST_F(ObjectReplaceNodeTest, CannotModifyImmutableId) { "to have been altered to _id: 1"); } -TEST_F(ObjectReplaceNodeTest, CanAddImmutableField) { +TEST_F(ObjectReplaceExecutorTest, CanAddImmutableField) { auto obj = fromjson("{a: {b: 1}}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{c: 1}")); addImmutablePath("a.b"); @@ -244,9 +244,9 @@ TEST_F(ObjectReplaceNodeTest, CanAddImmutableField) { ASSERT_EQUALS(fromjson("{a: {b: 1}}"), getLogDoc()); } -TEST_F(ObjectReplaceNodeTest, CanAddImmutableId) { +TEST_F(ObjectReplaceExecutorTest, CanAddImmutableId) { auto obj = fromjson("{_id: 0}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{c: 1}")); addImmutablePath("_id"); @@ -258,9 +258,9 @@ TEST_F(ObjectReplaceNodeTest, CanAddImmutableId) { ASSERT_EQUALS(fromjson("{_id: 0}"), getLogDoc()); } -TEST_F(ObjectReplaceNodeTest, CannotCreateDollarPrefixedNameWhenValidateForStorageIsTrue) { +TEST_F(ObjectReplaceExecutorTest, CannotCreateDollarPrefixedNameWhenValidateForStorageIsTrue) { auto obj = fromjson("{a: {b: 1, $bad: 1}}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{}")); ASSERT_THROWS_CODE_AND_WHAT( @@ -270,9 +270,9 @@ TEST_F(ObjectReplaceNodeTest, CannotCreateDollarPrefixedNameWhenValidateForStora "The dollar ($) prefixed field '$bad' in 'a.$bad' is not valid for storage."); } -TEST_F(ObjectReplaceNodeTest, CanCreateDollarPrefixedNameWhenValidateForStorageIsFalse) { +TEST_F(ObjectReplaceExecutorTest, CanCreateDollarPrefixedNameWhenValidateForStorageIsFalse) { auto obj = fromjson("{a: {b: 1, $bad: 1}}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{}")); setValidateForStorage(false); @@ -284,9 +284,9 @@ TEST_F(ObjectReplaceNodeTest, CanCreateDollarPrefixedNameWhenValidateForStorageI ASSERT_EQUALS(fromjson("{a: {b: 1, $bad: 1}}"), getLogDoc()); } -TEST_F(ObjectReplaceNodeTest, NoLogBuilder) { +TEST_F(ObjectReplaceExecutorTest, NoLogBuilder) { auto obj = fromjson("{a: 1}"); - ObjectReplaceNode node(obj); + ObjectReplaceExecutor node(obj); mutablebson::Document doc(fromjson("{b: 1}")); setLogBuilderToNull(); diff --git a/src/mongo/db/update/pipeline_executor.cpp b/src/mongo/db/update/pipeline_executor.cpp index d3360ffb2c4..f2e66da44b9 100644 --- a/src/mongo/db/update/pipeline_executor.cpp +++ b/src/mongo/db/update/pipeline_executor.cpp @@ -34,7 +34,7 @@ #include "mongo/db/bson/dotted_path_support.h" #include "mongo/db/pipeline/document_source_mock.h" #include "mongo/db/pipeline/lite_parsed_pipeline.h" -#include "mongo/db/update/object_replace_node.h" +#include "mongo/db/update/object_replace_executor.h" #include "mongo/db/update/storage_validation.h" namespace mongo { @@ -80,7 +80,7 @@ UpdateExecutor::ApplyResult PipelineExecutor::applyUpdate(ApplyParams applyParam auto transformedDoc = _pipeline->getNext()->toBson(); auto transformedDocHasIdField = transformedDoc.hasField(kIdFieldName); - return ObjectReplaceNode::applyReplacementUpdate( + return ObjectReplaceExecutor::applyReplacementUpdate( applyParams, transformedDoc, transformedDocHasIdField); } diff --git a/src/mongo/db/update/pipeline_executor.h b/src/mongo/db/update/pipeline_executor.h index fb1c5d7a562..0fba04ad24b 100644 --- a/src/mongo/db/update/pipeline_executor.h +++ b/src/mongo/db/update/pipeline_executor.h @@ -61,7 +61,7 @@ public: */ ApplyResult applyUpdate(ApplyParams applyParams) const final; - Value serialize() const { + Value serialize() const final { std::vector<Value> valueArray; for (const auto& stage : _pipeline->getSources()) { // TODO SERVER-40539: Consider subclassing DocumentSourceQueue with a class that is @@ -77,12 +77,6 @@ public: return Value(valueArray); } - void acceptVisitor(UpdateNodeVisitor* visitor) final { - visitor->visit(this); - } - - void setCollator(const CollatorInterface* collator) final {} - private: boost::intrusive_ptr<ExpressionContext> _expCtx; std::unique_ptr<Pipeline, PipelineDeleter> _pipeline; diff --git a/src/mongo/db/update/update_driver.cpp b/src/mongo/db/update/update_driver.cpp index a897f5739cd..d66dcc8dab9 100644 --- a/src/mongo/db/update/update_driver.cpp +++ b/src/mongo/db/update/update_driver.cpp @@ -41,7 +41,7 @@ #include "mongo/db/server_options.h" #include "mongo/db/update/log_builder.h" #include "mongo/db/update/modifier_table.h" -#include "mongo/db/update/object_replace_node.h" +#include "mongo/db/update/object_replace_executor.h" #include "mongo/db/update/path_support.h" #include "mongo/db/update/storage_validation.h" #include "mongo/util/embedded_builder.h" @@ -165,9 +165,11 @@ void UpdateDriver::parse( // Check if the update expression is a full object replacement. if (isDocReplacement(updateMod)) { - uassert(ErrorCodes::FailedToParse, "multi update only works with $ operators", !multi); + uassert(ErrorCodes::FailedToParse, + "multi update is not supported for replacement-style update", + !multi); - _updateExecutor = stdx::make_unique<ObjectReplaceNode>(updateMod.getUpdateClassic()); + _updateExecutor = stdx::make_unique<ObjectReplaceExecutor>(updateMod.getUpdateClassic()); // Register the fact that this driver will only do full object replacements. _updateType = UpdateType::kReplacement; @@ -192,7 +194,7 @@ void UpdateDriver::parse( auto root = stdx::make_unique<UpdateObjectNode>(); _positional = parseUpdateExpression(updateExpr, root.get(), _expCtx, arrayFilters); - _updateExecutor = std::move(root); + _updateExecutor = stdx::make_unique<UpdateTreeExecutor>(std::move(root)); } Status UpdateDriver::populateDocumentWithQueryFields(OperationContext* opCtx, @@ -261,7 +263,7 @@ Status UpdateDriver::update(StringData matchedField, _logDoc.reset(); LogBuilder logBuilder(_logDoc.root()); - UpdateNode::ApplyParams applyParams(doc->root(), immutablePaths); + UpdateExecutor::ApplyParams applyParams(doc->root(), immutablePaths); applyParams.matchedField = matchedField; applyParams.insert = isInsert; applyParams.fromOplogApplication = _fromOplogApplication; @@ -305,11 +307,11 @@ Status UpdateDriver::update(StringData matchedField, } void UpdateDriver::setCollator(const CollatorInterface* collator) { + _expCtx->setCollator(collator); + if (_updateExecutor) { _updateExecutor->setCollator(collator); } - - _expCtx->setCollator(collator); } bool UpdateDriver::isDocReplacement(const write_ops::UpdateModification& updateMod) { diff --git a/src/mongo/db/update/update_driver.h b/src/mongo/db/update/update_driver.h index 4f400ce640c..24c0cd72edc 100644 --- a/src/mongo/db/update/update_driver.h +++ b/src/mongo/db/update/update_driver.h @@ -42,10 +42,11 @@ #include "mongo/db/pipeline/value.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/update/modifier_table.h" -#include "mongo/db/update/object_replace_node.h" +#include "mongo/db/update/object_replace_executor.h" #include "mongo/db/update/pipeline_executor.h" #include "mongo/db/update/update_node_visitor.h" #include "mongo/db/update/update_object_node.h" +#include "mongo/db/update/update_tree_executor.h" #include "mongo/db/update_index_data.h" namespace mongo { @@ -127,7 +128,17 @@ public: * implementing methods that operate on the nodes of the tree. */ void visitRoot(UpdateNodeVisitor* visitor) { - _updateExecutor->acceptVisitor(visitor); + if (_updateType == UpdateType::kOperator) { + UpdateTreeExecutor* exec = static_cast<UpdateTreeExecutor*>(_updateExecutor.get()); + invariant(exec); + return exec->getUpdateTree()->acceptVisitor(visitor); + } + + MONGO_UNREACHABLE; + } + + UpdateExecutor* getUpdateExecutor() { + return _updateExecutor.get(); } // @@ -178,16 +189,7 @@ public: * produce a logically equivalent update expression. */ Value serialize() const { - switch (_updateType) { - case UpdateType::kReplacement: - return Value(static_cast<ObjectReplaceNode*>(_updateExecutor.get())->serialize()); - case UpdateType::kPipeline: - return static_cast<PipelineExecutor*>(_updateExecutor.get())->serialize(); - case UpdateType::kOperator: - return Value(static_cast<UpdateObjectNode*>(_updateExecutor.get())->serialize()); - default: - MONGO_UNREACHABLE; - } + return _updateExecutor->serialize(); } /** diff --git a/src/mongo/db/update/update_executor.h b/src/mongo/db/update/update_executor.h index 0a3baf8779f..f7548b5b155 100644 --- a/src/mongo/db/update/update_executor.h +++ b/src/mongo/db/update/update_executor.h @@ -31,6 +31,7 @@ #include "mongo/bson/mutable/element.h" #include "mongo/db/field_ref_set.h" +#include "mongo/db/pipeline/value.h" #include "mongo/db/update/log_builder.h" #include "mongo/db/update/update_node_visitor.h" #include "mongo/db/update_index_data.h" @@ -102,27 +103,15 @@ public: UpdateExecutor() = default; virtual ~UpdateExecutor() = default; - /** - * Set the collation. This is a noop if the UpdateExecutor subclass does not require a collator. - * If setCollator() is called, it is required that the current collator is the simple collator - * (nullptr). The collator must outlive the modifier interface. This is used to override the - * collation after obtaining a collection lock if the update did not specify a collation and the - * collection has a non-simple default collation. - */ - virtual void setCollator(const CollatorInterface* collator) = 0; + virtual Value serialize() const = 0; + virtual void setCollator(const CollatorInterface* collator){}; /** * Applies the update to 'applyParams.element'. Returns an ApplyResult specifying whether the * operation was a no-op and whether indexes are affected. */ virtual ApplyResult applyUpdate(ApplyParams applyParams) const = 0; - - /** - * This allows an arbitrary class to implement logic which gets dispatched to at runtime - * depending on the type of the UpdateExecutor. - */ - virtual void acceptVisitor(UpdateNodeVisitor* visitor) = 0; }; } // namespace mongo diff --git a/src/mongo/db/update/update_node.h b/src/mongo/db/update/update_node.h index 9b3bee195ae..cca2bea0105 100644 --- a/src/mongo/db/update/update_node.h +++ b/src/mongo/db/update/update_node.h @@ -49,6 +49,9 @@ namespace mongo { class CollatorInterface; class FieldRef; +using ApplyParams = UpdateExecutor::ApplyParams; +using ApplyResult = UpdateExecutor::ApplyResult; + /** * Update modifier expressions are stored as a prefix tree of UpdateNodes, where two modifiers that * share a field path prefix share a path prefix in the tree. The prefix tree is used to enforce @@ -64,7 +67,7 @@ class FieldRef; * b / \ c * SetNode: _val = 5 IncNode: _val = 1 */ -class UpdateNode : public UpdateExecutor { +class UpdateNode { public: enum class Context { kAll, kInsertOnly }; enum class Type { Object, Array, Leaf, Replacement }; @@ -87,11 +90,6 @@ public: virtual std::unique_ptr<UpdateNode> clone() const = 0; - ApplyResult applyUpdate(ApplyParams applyParams) const final { - UpdateNodeApplyParams updateNodeApplyParams; - return apply(applyParams, updateNodeApplyParams); - } - virtual ApplyResult apply(ApplyParams applyParams, UpdateNodeApplyParams updateNodeApplyParams) const = 0; @@ -120,6 +118,21 @@ public: std::map<std::string, std::vector<std::pair<std::string, BSONObj>>>* operatorOrientedUpdates) const = 0; + /** + * Set the collation. This is a noop if the UpdateExecutor subclass does not require a collator. + * If setCollator() is called, it is required that the current collator is the simple collator + * (nullptr). The collator must outlive the modifier interface. This is used to override the + * collation after obtaining a collection lock if the update did not specify a collation and the + * collection has a non-simple default collation. + */ + virtual void setCollator(const CollatorInterface* collator) = 0; + + /** + * This allows an arbitrary class to implement logic which gets dispatched to at runtime + * depending on the type of the UpdateExecutor. + */ + virtual void acceptVisitor(UpdateNodeVisitor* visitor) = 0; + public: const Context context; const Type type; diff --git a/src/mongo/db/update/update_node_test_fixture.h b/src/mongo/db/update/update_node_test_fixture.h index 2f3506ea487..73953167ffc 100644 --- a/src/mongo/db/update/update_node_test_fixture.h +++ b/src/mongo/db/update/update_node_test_fixture.h @@ -45,7 +45,7 @@ protected: void setUp() override { resetApplyParams(); - // Set up the logical clock needed by CurrentDateNode and ObjectReplaceNode. + // Set up the logical clock needed by CurrentDateNode and ObjectReplaceExecutor. auto service = mongo::getGlobalServiceContext(); auto logicalClock = mongo::stdx::make_unique<mongo::LogicalClock>(service); mongo::LogicalClock::set(service, std::move(logicalClock)); diff --git a/src/mongo/db/update/update_node_visitor.h b/src/mongo/db/update/update_node_visitor.h index 55ede3a0e64..39abf1f181a 100644 --- a/src/mongo/db/update/update_node_visitor.h +++ b/src/mongo/db/update/update_node_visitor.h @@ -39,8 +39,6 @@ class BitNode; class CompareNode; class ConflictPlaceholderNode; class CurrentDateNode; -class ObjectReplaceNode; -class PipelineExecutor; class PopNode; class PullAllNode; class PullNode; @@ -72,8 +70,6 @@ public: virtual void visit(CompareNode*) = 0; virtual void visit(ConflictPlaceholderNode*) = 0; virtual void visit(CurrentDateNode*) = 0; - virtual void visit(ObjectReplaceNode*) = 0; - virtual void visit(PipelineExecutor*) = 0; virtual void visit(PopNode*) = 0; virtual void visit(PullAllNode*) = 0; virtual void visit(PullNode*) = 0; diff --git a/src/mongo/db/update/update_tree_executor.h b/src/mongo/db/update/update_tree_executor.h new file mode 100644 index 00000000000..e10bccc50c1 --- /dev/null +++ b/src/mongo/db/update/update_tree_executor.h @@ -0,0 +1,69 @@ +/** + * Copyright (C) 2019-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include "mongo/db/update/update_executor.h" + +#include "mongo/db/update/update_node.h" +#include "mongo/db/update/update_object_node.h" + +namespace mongo { + +class UpdateTreeExecutor : public UpdateExecutor { +public: + explicit UpdateTreeExecutor(std::unique_ptr<UpdateObjectNode> node) + : _updateTree(std::move(node)) {} + + ApplyResult applyUpdate(ApplyParams applyParams) const final { + UpdateNode::UpdateNodeApplyParams updateNodeApplyParams; + return _updateTree->apply(applyParams, updateNodeApplyParams); + } + + UpdateNode* getUpdateTree() { + return static_cast<UpdateNode*>(_updateTree.get()); + } + + /** + * Gather all update operators in the subtree rooted from '_updateTree' into a BSONObj in the + * format of the update command's update parameter. + */ + Value serialize() const final { + return Value(_updateTree->serialize()); + } + + void setCollator(const CollatorInterface* collator) final { + _updateTree->setCollator(collator); + } + +private: + std::unique_ptr<UpdateObjectNode> _updateTree; +}; + +} // namespace mongo |