summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Tuckman <ted.tuckman@mongodb.com>2019-03-05 11:22:06 -0500
committerTed Tuckman <ted.tuckman@mongodb.com>2019-03-26 09:55:54 -0400
commit1053cf8347e7aeaca24d47039980c765dae75d5b (patch)
tree10a3a00d7a72137048cb8ad79339f614dca1adbb
parent233a4f7cfdf13fa0cfa55c6209644f7e3dbbed4b (diff)
downloadmongo-1053cf8347e7aeaca24d47039980c765dae75d5b.tar.gz
SERVER-39257 Implement visitor pattern for UpdateNode
-rw-r--r--src/mongo/db/update/addtoset_node.h4
-rw-r--r--src/mongo/db/update/arithmetic_node.h4
-rw-r--r--src/mongo/db/update/bit_node.h4
-rw-r--r--src/mongo/db/update/compare_node.h4
-rw-r--r--src/mongo/db/update/conflict_placeholder_node.h4
-rw-r--r--src/mongo/db/update/current_date_node.h4
-rw-r--r--src/mongo/db/update/object_replace_node.cpp10
-rw-r--r--src/mongo/db/update/object_replace_node.h16
-rw-r--r--src/mongo/db/update/pop_node.h4
-rw-r--r--src/mongo/db/update/pull_node.h4
-rw-r--r--src/mongo/db/update/pullall_node.h4
-rw-r--r--src/mongo/db/update/push_node.h4
-rw-r--r--src/mongo/db/update/rename_node.cpp8
-rw-r--r--src/mongo/db/update/rename_node.h4
-rw-r--r--src/mongo/db/update/set_node.cpp10
-rw-r--r--src/mongo/db/update/set_node.h10
-rw-r--r--src/mongo/db/update/unset_node.h4
-rw-r--r--src/mongo/db/update/update_array_node.h4
-rw-r--r--src/mongo/db/update/update_driver.h9
-rw-r--r--src/mongo/db/update/update_node.h7
-rw-r--r--src/mongo/db/update/update_node_visitor.h86
-rw-r--r--src/mongo/db/update/update_object_node.h8
22 files changed, 193 insertions, 23 deletions
diff --git a/src/mongo/db/update/addtoset_node.h b/src/mongo/db/update/addtoset_node.h
index 6ab894e031a..d634691011f 100644
--- a/src/mongo/db/update/addtoset_node.h
+++ b/src/mongo/db/update/addtoset_node.h
@@ -51,6 +51,10 @@ public:
void setCollator(const CollatorInterface* collator) final;
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
protected:
ModifyResult updateExistingElement(mutablebson::Element* element,
std::shared_ptr<FieldRef> elementPath) const final;
diff --git a/src/mongo/db/update/arithmetic_node.h b/src/mongo/db/update/arithmetic_node.h
index 6e32a69e87e..b24c3391f4e 100644
--- a/src/mongo/db/update/arithmetic_node.h
+++ b/src/mongo/db/update/arithmetic_node.h
@@ -52,6 +52,10 @@ public:
void setCollator(const CollatorInterface* collator) final {}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
protected:
ModifyResult updateExistingElement(mutablebson::Element* element,
std::shared_ptr<FieldRef> elementPath) const final;
diff --git a/src/mongo/db/update/bit_node.h b/src/mongo/db/update/bit_node.h
index f558c688b14..96840fdec1e 100644
--- a/src/mongo/db/update/bit_node.h
+++ b/src/mongo/db/update/bit_node.h
@@ -49,6 +49,10 @@ public:
void setCollator(const CollatorInterface* collator) final {}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
protected:
ModifyResult updateExistingElement(mutablebson::Element* element,
std::shared_ptr<FieldRef> elementPath) const final;
diff --git a/src/mongo/db/update/compare_node.h b/src/mongo/db/update/compare_node.h
index 80fb7d26b8a..95bcd666d8f 100644
--- a/src/mongo/db/update/compare_node.h
+++ b/src/mongo/db/update/compare_node.h
@@ -52,6 +52,10 @@ public:
void setCollator(const CollatorInterface* collator) final;
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
protected:
ModifyResult updateExistingElement(mutablebson::Element* element,
std::shared_ptr<FieldRef> elementPath) const final;
diff --git a/src/mongo/db/update/conflict_placeholder_node.h b/src/mongo/db/update/conflict_placeholder_node.h
index 88f2545d291..66d29e854c8 100644
--- a/src/mongo/db/update/conflict_placeholder_node.h
+++ b/src/mongo/db/update/conflict_placeholder_node.h
@@ -71,6 +71,10 @@ public:
FieldRef* currentPath,
std::map<std::string, std::vector<std::pair<std::string, BSONObj>>>*
operatorOrientedUpdates) const final {}
+
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
};
} // namespace mongo
diff --git a/src/mongo/db/update/current_date_node.h b/src/mongo/db/update/current_date_node.h
index b2e1963c632..7872dadce9a 100644
--- a/src/mongo/db/update/current_date_node.h
+++ b/src/mongo/db/update/current_date_node.h
@@ -48,6 +48,10 @@ public:
void setCollator(const CollatorInterface* collator) final {}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
protected:
ModifyResult updateExistingElement(mutablebson::Element* element,
std::shared_ptr<FieldRef> elementPath) const final;
diff --git a/src/mongo/db/update/object_replace_node.cpp b/src/mongo/db/update/object_replace_node.cpp
index 414a49c41a0..88d836d0303 100644
--- a/src/mongo/db/update/object_replace_node.cpp
+++ b/src/mongo/db/update/object_replace_node.cpp
@@ -44,11 +44,11 @@ namespace {
constexpr StringData kIdFieldName = "_id"_sd;
} // namespace
-ObjectReplaceNode::ObjectReplaceNode(BSONObj val)
- : UpdateNode(Type::Replacement), _val(val.getOwned()), _containsId(false) {
+ObjectReplaceNode::ObjectReplaceNode(BSONObj value)
+ : UpdateNode(Type::Replacement), val(value.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 : val) {
// Do not change the _id field.
if (elem.fieldNameStringData() == kIdFieldName) {
@@ -77,7 +77,7 @@ UpdateNode::ApplyResult ObjectReplaceNode::apply(ApplyParams applyParams) const
auto original = applyParams.element.getDocument().getObject();
// Check for noop.
- if (original.binaryEqual(_val)) {
+ if (original.binaryEqual(val)) {
return ApplyResult::noopResult();
}
@@ -97,7 +97,7 @@ UpdateNode::ApplyResult ObjectReplaceNode::apply(ApplyParams applyParams) const
}
// Insert the provided contents instead.
- for (auto&& elem : _val) {
+ for (auto&& elem : val) {
invariant(applyParams.element.appendElement(elem));
}
diff --git a/src/mongo/db/update/object_replace_node.h b/src/mongo/db/update/object_replace_node.h
index 4f243d876ab..340f0ec6c0b 100644
--- a/src/mongo/db/update/object_replace_node.h
+++ b/src/mongo/db/update/object_replace_node.h
@@ -49,7 +49,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 val);
+ explicit ObjectReplaceNode(BSONObj value);
std::unique_ptr<UpdateNode> clone() const final {
return stdx::make_unique<ObjectReplaceNode>(*this);
@@ -58,7 +58,7 @@ public:
void setCollator(const CollatorInterface* collator) final {}
/**
- * Replaces the document that 'applyParams.element' belongs to with '_val'. If '_val' does not
+ * Replaces the document that 'applyParams.element' belongs to with 'val'. If 'val' does not
* contain an _id, the _id from the original document is preserved. 'applyParams.element' must
* be the root of the document. 'applyParams.pathToCreate' and 'applyParams.pathTaken' must be
* empty. Always returns a result stating that indexes are affected when the replacement is not
@@ -67,7 +67,7 @@ public:
ApplyResult apply(ApplyParams applyParams) const final;
BSONObj serialize() const {
- return _val;
+ return val;
}
/**
@@ -80,11 +80,15 @@ public:
MONGO_UNREACHABLE;
}
-private:
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
// Object to replace with.
- BSONObj _val;
+ BSONObj val;
- // True if _val contains an _id.
+private:
+ // True if val contains an _id.
bool _containsId;
};
diff --git a/src/mongo/db/update/pop_node.h b/src/mongo/db/update/pop_node.h
index 86b5e6b64ee..bf15cb2731a 100644
--- a/src/mongo/db/update/pop_node.h
+++ b/src/mongo/db/update/pop_node.h
@@ -62,6 +62,10 @@ public:
return _popFromFront;
}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
private:
StringData operatorName() const final {
return "$pop";
diff --git a/src/mongo/db/update/pull_node.h b/src/mongo/db/update/pull_node.h
index 98e17a16b83..71ecf81bae7 100644
--- a/src/mongo/db/update/pull_node.h
+++ b/src/mongo/db/update/pull_node.h
@@ -50,6 +50,10 @@ public:
return stdx::make_unique<PullNode>(*this);
}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
private:
StringData operatorName() const final {
return "$pull";
diff --git a/src/mongo/db/update/pullall_node.h b/src/mongo/db/update/pullall_node.h
index d22dfcd9d6a..e529123e5ef 100644
--- a/src/mongo/db/update/pullall_node.h
+++ b/src/mongo/db/update/pullall_node.h
@@ -50,6 +50,10 @@ public:
return stdx::make_unique<PullAllNode>(*this);
}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
private:
StringData operatorName() const final {
return "$pullAll";
diff --git a/src/mongo/db/update/push_node.h b/src/mongo/db/update/push_node.h
index e716c8e5c31..beab21950cc 100644
--- a/src/mongo/db/update/push_node.h
+++ b/src/mongo/db/update/push_node.h
@@ -55,6 +55,10 @@ public:
}
}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
protected:
ModifyResult updateExistingElement(mutablebson::Element* element,
std::shared_ptr<FieldRef> elementPath) const final;
diff --git a/src/mongo/db/update/rename_node.cpp b/src/mongo/db/update/rename_node.cpp
index 24f9c8329ce..75815485982 100644
--- a/src/mongo/db/update/rename_node.cpp
+++ b/src/mongo/db/update/rename_node.cpp
@@ -41,8 +41,6 @@
namespace mongo {
-namespace {
-
/**
* The SetElementNode class provides the $set functionality for $rename. A $rename from a source
* field to a destination field behaves logically like a $set on the destination followed by a
@@ -78,6 +76,10 @@ public:
std::map<std::string, std::vector<std::pair<std::string, BSONObj>>>*
operatorOrientedUpdates) const final {}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
protected:
ModifierNode::ModifyResult updateExistingElement(
mutablebson::Element* element, std::shared_ptr<FieldRef> elementPath) const final {
@@ -109,8 +111,6 @@ private:
mutablebson::Element _elemToSet;
};
-} // namespace
-
Status RenameNode::init(BSONElement modExpr,
const boost::intrusive_ptr<ExpressionContext>& expCtx) {
invariant(modExpr.ok());
diff --git a/src/mongo/db/update/rename_node.h b/src/mongo/db/update/rename_node.h
index 3631fc8d7b2..285f63f6c5e 100644
--- a/src/mongo/db/update/rename_node.h
+++ b/src/mongo/db/update/rename_node.h
@@ -72,6 +72,10 @@ public:
BSON("" << currentPath->dottedField()));
}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
private:
BSONElement _val;
};
diff --git a/src/mongo/db/update/set_node.cpp b/src/mongo/db/update/set_node.cpp
index 00a2d855e3f..a2ee3562dfe 100644
--- a/src/mongo/db/update/set_node.cpp
+++ b/src/mongo/db/update/set_node.cpp
@@ -38,7 +38,7 @@ namespace mongo {
Status SetNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) {
invariant(modExpr.ok());
- _val = modExpr;
+ val = modExpr;
return Status::OK();
}
@@ -46,17 +46,17 @@ Status SetNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionC
ModifierNode::ModifyResult SetNode::updateExistingElement(
mutablebson::Element* element, std::shared_ptr<FieldRef> elementPath) const {
// If 'element' is deserialized, then element.getValue() will be EOO, which will never equal
- // _val.
- if (element->getValue().binaryEqualValues(_val)) {
+ // val.
+ if (element->getValue().binaryEqualValues(val)) {
return ModifyResult::kNoOp;
} else {
- invariant(element->setValueBSONElement(_val));
+ invariant(element->setValueBSONElement(val));
return ModifyResult::kNormalUpdate;
}
}
void SetNode::setValueForNewElement(mutablebson::Element* element) const {
- invariant(element->setValueBSONElement(_val));
+ invariant(element->setValueBSONElement(val));
}
} // namespace mongo
diff --git a/src/mongo/db/update/set_node.h b/src/mongo/db/update/set_node.h
index 673e42b3402..f16c752f84d 100644
--- a/src/mongo/db/update/set_node.h
+++ b/src/mongo/db/update/set_node.h
@@ -50,6 +50,12 @@ public:
void setCollator(const CollatorInterface* collator) final {}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
+ BSONElement val;
+
protected:
ModifyResult updateExistingElement(mutablebson::Element* element,
std::shared_ptr<FieldRef> elementPath) const final;
@@ -69,10 +75,8 @@ private:
}
BSONObj operatorValue() const final {
- return BSON("" << _val);
+ return BSON("" << val);
}
-
- BSONElement _val;
};
} // namespace mongo
diff --git a/src/mongo/db/update/unset_node.h b/src/mongo/db/update/unset_node.h
index 7cdae9f8dac..7a773a821aa 100644
--- a/src/mongo/db/update/unset_node.h
+++ b/src/mongo/db/update/unset_node.h
@@ -66,6 +66,10 @@ public:
return true;
}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
private:
StringData operatorName() const final {
return "$unset";
diff --git a/src/mongo/db/update/update_array_node.h b/src/mongo/db/update/update_array_node.h
index 61e3dd6a443..88f3996afa1 100644
--- a/src/mongo/db/update/update_array_node.h
+++ b/src/mongo/db/update/update_array_node.h
@@ -91,6 +91,10 @@ public:
}
}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
private:
const std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>>& _arrayFilters;
std::map<std::string, clonable_ptr<UpdateNode>> _children;
diff --git a/src/mongo/db/update/update_driver.h b/src/mongo/db/update/update_driver.h
index 40224a80a21..50469e056cd 100644
--- a/src/mongo/db/update/update_driver.h
+++ b/src/mongo/db/update/update_driver.h
@@ -40,6 +40,7 @@
#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/update_node_visitor.h"
#include "mongo/db/update/update_object_node.h"
#include "mongo/db/update_index_data.h"
@@ -115,6 +116,14 @@ public:
bool* docWasModified = nullptr,
FieldRefSetWithStorage* modifiedPaths = nullptr);
+ /**
+ * Passes the visitor through to the root of the update tree. The visitor is responsible for
+ * implementing methods that operate on the nodes of the tree.
+ */
+ void visitRoot(UpdateNodeVisitor* visitor) {
+ _root->acceptVisitor(visitor);
+ }
+
//
// Accessors
//
diff --git a/src/mongo/db/update/update_node.h b/src/mongo/db/update/update_node.h
index 183b8eeb4fa..be4a1b09155 100644
--- a/src/mongo/db/update/update_node.h
+++ b/src/mongo/db/update/update_node.h
@@ -39,6 +39,7 @@
#include "mongo/bson/mutable/element.h"
#include "mongo/db/field_ref_set.h"
#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/update_node_visitor.h"
#include "mongo/db/update_index_data.h"
#include "mongo/util/assert_util.h"
@@ -179,6 +180,12 @@ public:
std::map<std::string, std::vector<std::pair<std::string, BSONObj>>>*
operatorOrientedUpdates) const = 0;
+ /**
+ * This allows an arbitrary class to implement logic which gets dispatched to at runtime
+ * depending on the type of the UpdateNode.
+ */
+ virtual void acceptVisitor(UpdateNodeVisitor* visitor) = 0;
+
public:
const Context context;
const Type type;
diff --git a/src/mongo/db/update/update_node_visitor.h b/src/mongo/db/update/update_node_visitor.h
new file mode 100644
index 00000000000..886ce6e112f
--- /dev/null
+++ b/src/mongo/db/update/update_node_visitor.h
@@ -0,0 +1,86 @@
+/**
+ * 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/platform/basic.h"
+
+namespace mongo {
+
+class AddToSetNode;
+class ArithmeticNode;
+class BitNode;
+class CompareNode;
+class ConflictPlaceholderNode;
+class CurrentDateNode;
+class ObjectReplaceNode;
+class PopNode;
+class PullAllNode;
+class PullNode;
+class PushNode;
+class RenameNode;
+class SetElementNode;
+class SetNode;
+class UnsetNode;
+class UpdateArrayNode;
+class UpdateObjectNode;
+
+/**
+ * This is a base class to allow for traversal of an update tree. It implements the visitor
+ * pattern, in which every derived class from update node implements an acceptVisitor() method,
+ * which simply calls the appropriate visit() method on the derived UpdateNodeVisitor class. The
+ * derived class can do whatever it needs to do for each specific node type in the corresponding
+ * visit() method.
+ * Derived classes are responsible for making the recursive calls to visit() if they wish
+ * to visit all the nodes in the update node tree. UpdateNodeVisitor's purpose is not actually to
+ * ensure that every node in the tree is visited, but rather to handle dynamic dispatch without
+ * having to add virtual methods to the UpdateNode interface itself.
+ */
+class UpdateNodeVisitor {
+public:
+ virtual ~UpdateNodeVisitor() = default;
+ virtual void visit(AddToSetNode*) = 0;
+ virtual void visit(ArithmeticNode*) = 0;
+ virtual void visit(BitNode*) = 0;
+ virtual void visit(CompareNode*) = 0;
+ virtual void visit(ConflictPlaceholderNode*) = 0;
+ virtual void visit(CurrentDateNode*) = 0;
+ virtual void visit(ObjectReplaceNode*) = 0;
+ virtual void visit(PopNode*) = 0;
+ virtual void visit(PullAllNode*) = 0;
+ virtual void visit(PullNode*) = 0;
+ virtual void visit(PushNode*) = 0;
+ virtual void visit(RenameNode*) = 0;
+ virtual void visit(SetElementNode*) = 0;
+ virtual void visit(SetNode*) = 0;
+ virtual void visit(UnsetNode*) = 0;
+ virtual void visit(UpdateArrayNode*) = 0;
+ virtual void visit(UpdateObjectNode*) = 0;
+};
+} // namespace mongo
diff --git a/src/mongo/db/update/update_object_node.h b/src/mongo/db/update/update_object_node.h
index 37322a191fa..2eee5c4d8f3 100644
--- a/src/mongo/db/update/update_object_node.h
+++ b/src/mongo/db/update/update_object_node.h
@@ -121,6 +121,14 @@ public:
}
}
+ void acceptVisitor(UpdateNodeVisitor* visitor) final {
+ visitor->visit(this);
+ }
+
+ const std::map<std::string, clonable_ptr<UpdateNode>>& getChildren() const {
+ return _children;
+ }
+
private:
std::map<std::string, clonable_ptr<UpdateNode>> _children;
clonable_ptr<UpdateNode> _positionalChild;