summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/ops/SConscript12
-rw-r--r--src/mongo/db/ops/log_builder.cpp115
-rw-r--r--src/mongo/db/ops/log_builder.h86
-rw-r--r--src/mongo/db/ops/log_builder_test.cpp244
-rw-r--r--src/mongo/db/ops/modifier_add_to_set.cpp19
-rw-r--r--src/mongo/db/ops/modifier_add_to_set.h4
-rw-r--r--src/mongo/db/ops/modifier_add_to_set_test.cpp42
-rw-r--r--src/mongo/db/ops/modifier_bit.cpp29
-rw-r--r--src/mongo/db/ops/modifier_bit.h4
-rw-r--r--src/mongo/db/ops/modifier_bit_test.cpp51
-rw-r--r--src/mongo/db/ops/modifier_inc.cpp21
-rw-r--r--src/mongo/db/ops/modifier_inc.h4
-rw-r--r--src/mongo/db/ops/modifier_inc_test.cpp30
-rw-r--r--src/mongo/db/ops/modifier_interface.h12
-rw-r--r--src/mongo/db/ops/modifier_object_replace.cpp25
-rw-r--r--src/mongo/db/ops/modifier_object_replace.h4
-rw-r--r--src/mongo/db/ops/modifier_pop.cpp37
-rw-r--r--src/mongo/db/ops/modifier_pop.h4
-rw-r--r--src/mongo/db/ops/modifier_pop_test.cpp21
-rw-r--r--src/mongo/db/ops/modifier_pull.cpp35
-rw-r--r--src/mongo/db/ops/modifier_pull.h2
-rw-r--r--src/mongo/db/ops/modifier_pull_all.cpp37
-rw-r--r--src/mongo/db/ops/modifier_pull_all.h4
-rw-r--r--src/mongo/db/ops/modifier_pull_all_test.cpp21
-rw-r--r--src/mongo/db/ops/modifier_pull_test.cpp45
-rw-r--r--src/mongo/db/ops/modifier_push.cpp27
-rw-r--r--src/mongo/db/ops/modifier_push.h4
-rw-r--r--src/mongo/db/ops/modifier_push_test.cpp57
-rw-r--r--src/mongo/db/ops/modifier_rename.cpp61
-rw-r--r--src/mongo/db/ops/modifier_rename.h4
-rw-r--r--src/mongo/db/ops/modifier_rename_test.cpp27
-rw-r--r--src/mongo/db/ops/modifier_set.cpp25
-rw-r--r--src/mongo/db/ops/modifier_set.h4
-rw-r--r--src/mongo/db/ops/modifier_set_test.cpp18
-rw-r--r--src/mongo/db/ops/modifier_unset.cpp20
-rw-r--r--src/mongo/db/ops/modifier_unset.h4
-rw-r--r--src/mongo/db/ops/modifier_unset_test.cpp15
-rw-r--r--src/mongo/db/ops/update_driver.cpp24
38 files changed, 833 insertions, 365 deletions
diff --git a/src/mongo/db/ops/SConscript b/src/mongo/db/ops/SConscript
index 6f8a369f43f..a56e2193c87 100644
--- a/src/mongo/db/ops/SConscript
+++ b/src/mongo/db/ops/SConscript
@@ -6,6 +6,7 @@ env.StaticLibrary(
target='update_common',
source=[
'field_checker.cpp',
+ 'log_builder.cpp',
'path_support.cpp',
],
LIBDEPS=[
@@ -26,6 +27,17 @@ env.CppUnitTest(
)
env.CppUnitTest(
+ target='log_builder_test',
+ source=[
+ 'log_builder_test.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/mutable_bson_test_utils',
+ 'update_common',
+ ],
+)
+
+env.CppUnitTest(
target='path_support_test',
source=[
'path_support_test.cpp',
diff --git a/src/mongo/db/ops/log_builder.cpp b/src/mongo/db/ops/log_builder.cpp
new file mode 100644
index 00000000000..cde2668f1ca
--- /dev/null
+++ b/src/mongo/db/ops/log_builder.cpp
@@ -0,0 +1,115 @@
+/**
+ * Copyright (C) 2013 10gen Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mongo/db/ops/log_builder.h"
+
+namespace mongo {
+
+ using mutablebson::Document;
+ using mutablebson::Element;
+
+ namespace {
+ const char kSet[] = "$set";
+ const char kUnset[] = "$unset";
+ } // namespace
+
+ inline Status LogBuilder::addToSection(Element newElt,
+ Element* section,
+ const char* sectionName) {
+
+ // If we don't already have this section, try to create it now.
+ if (!section->ok()) {
+
+ // If we already have object replacement data, we can't also have section entries.
+ if (hasObjectReplacement())
+ return Status(
+ ErrorCodes::IllegalOperation,
+ "LogBuilder: Invalid attempt to add a $set/$unset entry"
+ "to a log with an existing object replacement");
+
+ Document& doc = _logRoot.getDocument();
+
+ // We should not already have an element with the section name under the root.
+ dassert(_logRoot[sectionName] == doc.end());
+
+ // Construct a new object element to represent this section in the log.
+ const Element newElement = doc.makeElementObject(sectionName);
+ if (!newElement.ok())
+ return Status(ErrorCodes::InternalError,
+ "LogBuilder: failed to construct Object Element for $set/$unset");
+
+ // Enqueue the new section under the root, and record it as our out parameter.
+ Status result = _logRoot.pushBack(newElement);
+ if (!result.isOK())
+ return result;
+ *section = newElement;
+
+ // Invalidate attempts to add an object replacement, now that we have a named
+ // section under the root.
+ _objectReplacementAccumulator = doc.end();
+ }
+
+ // Whatever transpired, we should now have an ok accumulator for the section, and not
+ // have a replacement accumulator.
+ dassert(section->ok());
+ dassert(!_objectReplacementAccumulator.ok());
+
+ // Enqueue the provided element to the section and propagate the result.
+ return section->pushBack(newElt);
+ }
+
+ Status LogBuilder::addToSets(Element elt) {
+ return addToSection(elt, &_setAccumulator, kSet);
+ }
+
+ Status LogBuilder::addToUnsets(Element elt) {
+ return addToSection(elt, &_unsetAccumulator, kUnset);
+ }
+
+ Status LogBuilder::getReplacementObject(Element* outElt) {
+
+ // If the replacement accumulator is not ok, we must have started a $set or $unset
+ // already, so an object replacement is not permitted.
+ if (!_objectReplacementAccumulator.ok()) {
+ dassert(_setAccumulator.ok() || _unsetAccumulator.ok());
+ return Status(
+ ErrorCodes::IllegalOperation,
+ "LogBuilder: Invalid attempt to obtain the object replacement slot "
+ "for a log containing $set or $unset entries");
+ }
+
+ if (hasObjectReplacement())
+ return Status(
+ ErrorCodes::IllegalOperation,
+ "LogBuilder: Invalid attempt to acquire the replacement object "
+ "in a log with existing object replacement data");
+
+ // OK to enqueue object replacement items.
+ *outElt = _objectReplacementAccumulator;
+ return Status::OK();
+ }
+
+ inline bool LogBuilder::hasObjectReplacement() const {
+ if (!_objectReplacementAccumulator.ok())
+ return false;
+
+ dassert(!_setAccumulator.ok());
+ dassert(!_unsetAccumulator.ok());
+
+ return _objectReplacementAccumulator.hasChildren();
+ }
+
+} // namespace mongo
diff --git a/src/mongo/db/ops/log_builder.h b/src/mongo/db/ops/log_builder.h
new file mode 100644
index 00000000000..f0893aaf747
--- /dev/null
+++ b/src/mongo/db/ops/log_builder.h
@@ -0,0 +1,86 @@
+/**
+ * Copyright (C) 2013 10gen Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <mongo/base/status.h>
+#include <mongo/bson/mutable/document.h>
+
+namespace mongo {
+
+ /** LogBuilder abstracts away some of the details of producing a properly constructed oplog
+ * update entry. It manages separate regions into which it accumulates $set and $unset
+ * operations, and distinguishes object replacement style oplog generation from
+ * $set/$unset style generation and prevents admixture.
+ */
+ class LogBuilder {
+ public:
+ /** Construct a new LogBuilder. Log entries will be recorded as new children under the
+ * 'logRoot' Element, which must be of type mongo::Object and have no children.
+ */
+ inline LogBuilder(mutablebson::Element logRoot)
+ : _logRoot(logRoot)
+ , _objectReplacementAccumulator(_logRoot)
+ , _setAccumulator(_logRoot.getDocument().end())
+ , _unsetAccumulator(_setAccumulator) {
+ dassert(logRoot.isType(mongo::Object));
+ dassert(!logRoot.hasChildren());
+ }
+
+ /** Return the Document to which the logging root belongs. */
+ inline mutablebson::Document& getDocument() {
+ return _logRoot.getDocument();
+ }
+
+ /** Add the given Element as a new entry in the '$set' section of the log. If a $set
+ * section does not yet exist, it will be created. If this LogBuilder is currently
+ * configured to contain an object replacement, the request to add to the $set section
+ * will return an Error.
+ */
+ Status addToSets(mutablebson::Element elt);
+
+ /** Add the given Element as a new entry in the '$unset' section of the log. If an
+ * '$unset' section does not yet exist, it will be created. If this LogBuilder is
+ * currently configured to contain an object replacement, the request to add to the
+ * $unset section will return an Error.
+ */
+ Status addToUnsets(mutablebson::Element elt);
+
+ /** Obtain, via the out parameter 'outElt', a pointer to the mongo::Object type Element
+ * to which the components of an object replacement should be recorded. It is an error
+ * to call this if any Elements have been added by calling either addToSets or
+ * addToUnsets, and attempts to do so will return a non-OK Status. Similarly, if there
+ * is already object replacement data recorded for this log, the call will fail.
+ */
+ Status getReplacementObject(mutablebson::Element* outElt);
+
+ private:
+ // Returns true if the object replacement accumulator is valid and has children, false
+ // otherwise.
+ inline bool hasObjectReplacement() const;
+
+ inline Status addToSection(
+ mutablebson::Element newElt,
+ mutablebson::Element* section,
+ const char* sectionName);
+
+ mutablebson::Element _logRoot;
+ mutablebson::Element _objectReplacementAccumulator;
+ mutablebson::Element _setAccumulator;
+ mutablebson::Element _unsetAccumulator;
+ };
+
+} // namespace mongo
diff --git a/src/mongo/db/ops/log_builder_test.cpp b/src/mongo/db/ops/log_builder_test.cpp
new file mode 100644
index 00000000000..99684c43ccd
--- /dev/null
+++ b/src/mongo/db/ops/log_builder_test.cpp
@@ -0,0 +1,244 @@
+/**
+ * Copyright 2013 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mongo/db/ops/log_builder.h"
+
+#include "mongo/base/status.h"
+#include "mongo/bson/mutable/mutable_bson_test_utils.h"
+#include "mongo/db/json.h"
+#include "mongo/unittest/unittest.h"
+
+namespace {
+
+ namespace mmb = mongo::mutablebson;
+ using mongo::LogBuilder;
+
+ TEST(LogBuilder, Initialization) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+ ASSERT_EQUALS(&doc, &lb.getDocument());
+ }
+
+ TEST(LogBuilder, AddOneToSet) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+
+ const mmb::Element elt_ab = doc.makeElementInt("a.b", 1);
+ ASSERT_TRUE(elt_ab.ok());
+ ASSERT_OK(lb.addToSets(elt_ab));
+
+ ASSERT_EQUALS(mongo::fromjson("{ $set : { 'a.b' : 1 } }"), doc);
+ }
+
+ TEST(LogBuilder, AddOneToUnset) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+
+ const mmb::Element elt_xy = doc.makeElementInt("x.y", 1);
+ ASSERT_TRUE(elt_xy.ok());
+ ASSERT_OK(lb.addToUnsets(elt_xy));
+
+ ASSERT_EQUALS(mongo::fromjson("{ $unset : { 'x.y' : 1 } }"), doc);
+ }
+
+ TEST(LogBuilder, AddOneToEach) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+
+ const mmb::Element elt_ab = doc.makeElementInt("a.b", 1);
+ ASSERT_TRUE(elt_ab.ok());
+ ASSERT_OK(lb.addToSets(elt_ab));
+
+ const mmb::Element elt_xy = doc.makeElementInt("x.y", 1);
+ ASSERT_TRUE(elt_xy.ok());
+ ASSERT_OK(lb.addToUnsets(elt_xy));
+
+ ASSERT_EQUALS(
+ mongo::fromjson(
+ "{ "
+ " $set : { 'a.b' : 1 }, "
+ " $unset : { 'x.y' : 1 } "
+ "}"
+ ), doc);
+ }
+
+ TEST(LogBuilder, AddOneObjectReplacementEntry) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+
+ mmb::Element replacement = doc.end();
+ ASSERT_FALSE(replacement.ok());
+ ASSERT_OK(lb.getReplacementObject(&replacement));
+ ASSERT_TRUE(replacement.ok());
+ ASSERT_TRUE(replacement.isType(mongo::Object));
+
+ const mmb::Element elt_a = doc.makeElementInt("a", 1);
+ ASSERT_TRUE(elt_a.ok());
+ ASSERT_OK(replacement.pushBack(elt_a));
+
+ ASSERT_EQUALS(mongo::fromjson("{ a : 1 }"), doc);
+ }
+
+ TEST(LogBuilder, AddTwoObjectReplacementEntry) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+
+ mmb::Element replacement = doc.end();
+ ASSERT_FALSE(replacement.ok());
+ ASSERT_OK(lb.getReplacementObject(&replacement));
+ ASSERT_TRUE(replacement.ok());
+ ASSERT_TRUE(replacement.isType(mongo::Object));
+
+ const mmb::Element elt_a = doc.makeElementInt("a", 1);
+ ASSERT_TRUE(elt_a.ok());
+ ASSERT_OK(replacement.pushBack(elt_a));
+
+ const mmb::Element elt_b = doc.makeElementInt("b", 2);
+ ASSERT_TRUE(elt_b.ok());
+ ASSERT_OK(replacement.pushBack(elt_b));
+
+ ASSERT_EQUALS(mongo::fromjson("{ a : 1, b: 2 }"), doc);
+ }
+
+ TEST(LogBuilder, VerifySetsAreGrouped) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+
+ const mmb::Element elt_ab = doc.makeElementInt("a.b", 1);
+ ASSERT_TRUE(elt_ab.ok());
+ ASSERT_OK(lb.addToSets(elt_ab));
+
+ const mmb::Element elt_xy = doc.makeElementInt("x.y", 1);
+ ASSERT_TRUE(elt_xy.ok());
+ ASSERT_OK(lb.addToSets(elt_xy));
+
+ ASSERT_EQUALS(
+ mongo::fromjson(
+ "{ $set : {"
+ " 'a.b' : 1, "
+ " 'x.y' : 1 "
+ "} }"
+ ), doc);
+ }
+
+ TEST(LogBuilder, VerifyUnsetsAreGrouped) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+
+ const mmb::Element elt_ab = doc.makeElementInt("a.b", 1);
+ ASSERT_TRUE(elt_ab.ok());
+ ASSERT_OK(lb.addToUnsets(elt_ab));
+
+ const mmb::Element elt_xy = doc.makeElementInt("x.y", 1);
+ ASSERT_TRUE(elt_xy.ok());
+ ASSERT_OK(lb.addToUnsets(elt_xy));
+
+ ASSERT_EQUALS(
+ mongo::fromjson(
+ "{ $unset : {"
+ " 'a.b' : 1, "
+ " 'x.y' : 1 "
+ "} }"
+ ), doc);
+ }
+
+ TEST(LogBuilder, PresenceOfSetPreventsObjectReplacement) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+
+ mmb::Element replacement = doc.end();
+ ASSERT_FALSE(replacement.ok());
+ ASSERT_OK(lb.getReplacementObject(&replacement));
+ ASSERT_TRUE(replacement.ok());
+
+ const mmb::Element elt_ab = doc.makeElementInt("a.b", 1);
+ ASSERT_TRUE(elt_ab.ok());
+ ASSERT_OK(lb.addToSets(elt_ab));
+
+ replacement = doc.end();
+ ASSERT_FALSE(replacement.ok());
+ ASSERT_NOT_OK(lb.getReplacementObject(&replacement));
+ ASSERT_FALSE(replacement.ok());
+ }
+
+ TEST(LogBuilder, PresenceOfUnsetPreventsObjectReplacement) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+
+ mmb::Element replacement = doc.end();
+ ASSERT_FALSE(replacement.ok());
+ ASSERT_OK(lb.getReplacementObject(&replacement));
+ ASSERT_TRUE(replacement.ok());
+
+ const mmb::Element elt_ab = doc.makeElementInt("a.b", 1);
+ ASSERT_TRUE(elt_ab.ok());
+ ASSERT_OK(lb.addToSets(elt_ab));
+
+ replacement = doc.end();
+ ASSERT_FALSE(replacement.ok());
+ ASSERT_NOT_OK(lb.getReplacementObject(&replacement));
+ ASSERT_FALSE(replacement.ok());
+ }
+
+ TEST(LogBuilder, CantAddSetWithObjectReplacementDataPresent) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+
+ mmb::Element replacement = doc.end();
+ ASSERT_FALSE(replacement.ok());
+ ASSERT_OK(lb.getReplacementObject(&replacement));
+ ASSERT_TRUE(replacement.ok());
+ ASSERT_OK(replacement.appendInt("a", 1));
+
+ mmb::Element setCandidate = doc.makeElementInt("x", 0);
+ ASSERT_NOT_OK(lb.addToSets(setCandidate));
+ }
+
+ TEST(LogBuilder, CantAddUnsetWithObjectReplacementDataPresent) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+
+ mmb::Element replacement = doc.end();
+ ASSERT_FALSE(replacement.ok());
+ ASSERT_OK(lb.getReplacementObject(&replacement));
+ ASSERT_TRUE(replacement.ok());
+ ASSERT_OK(replacement.appendInt("a", 1));
+
+ mmb::Element setCandidate = doc.makeElementInt("x", 0);
+ ASSERT_NOT_OK(lb.addToUnsets(setCandidate));
+ }
+
+ // Ensure that once you have obtained the object replacement slot and mutated it, that the
+ // object replacement slot becomes in accessible. This is a bit paranoid, since in practice
+ // the modifier conflict detection logic should prevent that outcome at a higher level, but
+ // preventing it here costs us nothing and add an extra safety check.
+ TEST(LogBuilder, CantReacquireObjectReplacementData) {
+ mmb::Document doc;
+ LogBuilder lb(doc.root());
+
+ mmb::Element replacement = doc.end();
+ ASSERT_FALSE(replacement.ok());
+ ASSERT_OK(lb.getReplacementObject(&replacement));
+ ASSERT_TRUE(replacement.ok());
+ ASSERT_OK(replacement.appendInt("a", 1));
+
+ mmb::Element again = doc.end();
+ ASSERT_FALSE(again.ok());
+ ASSERT_NOT_OK(lb.getReplacementObject(&again));
+ ASSERT_FALSE(again.ok());
+ }
+
+} // namespace
diff --git a/src/mongo/db/ops/modifier_add_to_set.cpp b/src/mongo/db/ops/modifier_add_to_set.cpp
index ea733922bd4..d04f9199c44 100644
--- a/src/mongo/db/ops/modifier_add_to_set.cpp
+++ b/src/mongo/db/ops/modifier_add_to_set.cpp
@@ -19,6 +19,7 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/db/ops/field_checker.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/db/ops/path_support.h"
namespace mongo {
@@ -354,7 +355,7 @@ namespace mongo {
return Status::OK();
}
- Status ModifierAddToSet::log(mb::Element logRoot) const {
+ Status ModifierAddToSet::log(LogBuilder* logBuilder) const {
// TODO: This is copied more or less identically from $push. As a result, it copies the
// behavior in $push that relies on 'apply' having been called unless this is a no-op.
@@ -364,11 +365,7 @@ namespace mongo {
// We'd like to create an entry such as {$set: {<fieldname>: [<resulting aray>]}} under
// 'logRoot'. We start by creating the {$set: ...} Element.
- mb::Document& doc = logRoot.getDocument();
- mb::Element setElement = doc.makeElementObject("$set");
- if (!setElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot create log entry for $addToSet mod");
- }
+ mb::Document& doc = logBuilder->getDocument();
// Then we create the {<fieldname>:[]} Element, that is, an empty array.
mb::Element logElement = doc.makeElementArray(_fieldRef.dottedField());
@@ -397,15 +394,7 @@ namespace mongo {
curr = curr.rightSibling();
}
- // Now, we attach the {<fieldname>: [<filled array>]} Element under the {$set: ...}
- // one.
- Status status = setElement.pushBack(logElement);
- if (!status.isOK()) {
- return status;
- }
-
- // And attach the result under the 'logRoot' Element provided.
- return logRoot.pushBack(setElement);
+ return logBuilder->addToSets(logElement);
}
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_add_to_set.h b/src/mongo/db/ops/modifier_add_to_set.h
index 7e6111f991b..7683577a032 100644
--- a/src/mongo/db/ops/modifier_add_to_set.h
+++ b/src/mongo/db/ops/modifier_add_to_set.h
@@ -25,6 +25,8 @@
namespace mongo {
+ class LogBuilder;
+
class ModifierAddToSet : public ModifierInterface {
MONGO_DISALLOW_COPYING(ModifierAddToSet);
@@ -51,7 +53,7 @@ namespace mongo {
virtual Status apply() const;
/** Converts the effects of this $addToSet into one or more equivalent $set operations. */
- virtual Status log(mutablebson::Element logRoot) const;
+ virtual Status log(LogBuilder* logBuilder) const;
private:
// Access to each component of fieldName that's the target of this mod.
diff --git a/src/mongo/db/ops/modifier_add_to_set_test.cpp b/src/mongo/db/ops/modifier_add_to_set_test.cpp
index 4ec5a1b2b08..dd3a2d30ea4 100644
--- a/src/mongo/db/ops/modifier_add_to_set_test.cpp
+++ b/src/mongo/db/ops/modifier_add_to_set_test.cpp
@@ -22,12 +22,14 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/platform/cstdint.h"
#include "mongo/unittest/unittest.h"
namespace {
using mongo::BSONObj;
+ using mongo::LogBuilder;
using mongo::ModifierAddToSet;
using mongo::ModifierInterface;
using mongo::Status;
@@ -57,8 +59,8 @@ namespace {
return _mod.apply();
}
- Status log(Element logRoot) const {
- return _mod.log(logRoot);
+ Status log(LogBuilder* logBuilder) const {
+ return _mod.log(logBuilder);
}
ModifierAddToSet& mod() {
@@ -137,7 +139,8 @@ namespace {
ASSERT_TRUE(execInfo.noOp);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [ 1 ] } }"), logDoc);
}
@@ -171,7 +174,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [ 1 ] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [ 1 ] } }"), logDoc);
}
@@ -189,7 +193,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [ 1 ] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [ 1 ] } }"), logDoc);
}
@@ -207,7 +212,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [ 1, 2, 3 ] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
}
@@ -225,7 +231,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [ 1, 2, 3 ] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
}
@@ -243,7 +250,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [ 'x', 1 ] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [ 'x', 1 ] } }"), logDoc);
}
@@ -261,7 +269,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [ 'x', 1, 2, 3 ] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [ 'x', 1, 2, 3 ] } }"), logDoc);
}
@@ -275,7 +284,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
}
@@ -289,7 +299,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
}
@@ -303,7 +314,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 2, 3 ] } }"), logDoc);
}
@@ -321,7 +333,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [ 1, 1, 2, 1, 2, 2, 3] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 1, 2, 1, 2, 2, 3] } }"), logDoc);
}
@@ -339,7 +352,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [ 1, 1, 2, 1, 2, 2, 4, 3] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [ 1, 1, 2, 1, 2, 2, 4, 3] } }"), logDoc);
}
diff --git a/src/mongo/db/ops/modifier_bit.cpp b/src/mongo/db/ops/modifier_bit.cpp
index 26741c5cb25..2099b5f1a72 100644
--- a/src/mongo/db/ops/modifier_bit.cpp
+++ b/src/mongo/db/ops/modifier_bit.cpp
@@ -19,6 +19,7 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/document.h"
#include "mongo/db/ops/field_checker.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/db/ops/path_support.h"
#include "mongo/util/mongoutils/str.h"
@@ -242,31 +243,17 @@ namespace mongo {
elemToSet);
}
- Status ModifierBit::log(mutablebson::Element logRoot) const {
+ Status ModifierBit::log(LogBuilder* logBuilder) const {
- // We'd like to create an entry such as {$set: {<fieldname>: <value>}} under 'logRoot'.
- // We start by creating the {$set: ...} Element.
- mutablebson::Document& doc = logRoot.getDocument();
- mutablebson::Element setElement = doc.makeElementObject("$set");
- if (!setElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot append log entry for $set mod");
- }
+ mutablebson::Element logElement = logBuilder->getDocument().makeElementSafeNum(
+ _fieldRef.dottedField(),
+ _preparedState->newValue);
- // Then we create the {<fieldname>: <value>} Element.
- mutablebson::Element logElement = doc.makeElementSafeNum(_fieldRef.dottedField(),
- _preparedState->newValue);
- if (!logElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot append details for $set mod");
- }
+ if (!logElement.ok())
+ return Status(ErrorCodes::InternalError, "cannot append details for $bit mod");
- // Now, we attach the {<fieldname>: <value>} Element under the {$set: ...} one.
- Status status = setElement.pushBack(logElement);
- if (!status.isOK()) {
- return status;
- }
+ return logBuilder->addToSets(logElement);
- // And attach the result under the 'logRoot' Element provided.
- return logRoot.pushBack(setElement);
}
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_bit.h b/src/mongo/db/ops/modifier_bit.h
index 8c90fd23594..4be9a4a0acb 100644
--- a/src/mongo/db/ops/modifier_bit.h
+++ b/src/mongo/db/ops/modifier_bit.h
@@ -27,6 +27,8 @@
namespace mongo {
+ class LogBuilder;
+
class ModifierBit : public ModifierInterface {
MONGO_DISALLOW_COPYING(ModifierBit);
@@ -54,7 +56,7 @@ namespace mongo {
virtual Status apply() const;
/** Converts the effects of this $bit into an equivalent $set */
- virtual Status log(mutablebson::Element logRoot) const;
+ virtual Status log(LogBuilder* logBuilder) const;
private:
// Access to each component of fieldName that's the target of this mod.
diff --git a/src/mongo/db/ops/modifier_bit_test.cpp b/src/mongo/db/ops/modifier_bit_test.cpp
index be2e028fc31..e5f2ee05940 100644
--- a/src/mongo/db/ops/modifier_bit_test.cpp
+++ b/src/mongo/db/ops/modifier_bit_test.cpp
@@ -22,12 +22,14 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/platform/cstdint.h"
#include "mongo/unittest/unittest.h"
namespace {
using mongo::BSONObj;
+ using mongo::LogBuilder;
using mongo::ModifierBit;
using mongo::ModifierInterface;
using mongo::Status;
@@ -58,8 +60,8 @@ namespace {
return _mod.apply();
}
- Status log(Element logRoot) const {
- return _mod.log(logRoot);
+ Status log(LogBuilder* logBuilder) const {
+ return _mod.log(logBuilder);
}
ModifierBit& mod() { return _mod; }
@@ -136,7 +138,8 @@ namespace {
ASSERT_TRUE(execInfo.noOp);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : 1 } }"), logDoc);
}
@@ -178,7 +181,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : 0 }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : 0 } }"), logDoc);
}
@@ -195,7 +199,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : 1 }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : 1 } }"), logDoc);
}
@@ -212,7 +217,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : 4 }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : 4 } }"), logDoc);
}
@@ -229,7 +235,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : 7 }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : 7 } }"), logDoc);
}
@@ -243,7 +250,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(BSON("$set" << BSON("a" << static_cast<int>(1))), logDoc);
}
@@ -257,7 +265,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(BSON("$set" << BSON("a" << static_cast<int>(1))), logDoc);
}
@@ -271,7 +280,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(BSON("$set" << BSON("a" << static_cast<long long>(1))), logDoc);
}
@@ -285,7 +295,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(BSON("$set" << BSON("a" << static_cast<long long>(1))), logDoc);
}
@@ -319,7 +330,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(BSON("$set" << BSON("a" << static_cast<int>(0xABCD1234U))), logDoc);
}
@@ -333,7 +345,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(BSON("$set" << BSON("a" << static_cast<int>(0xABCD1234U))), logDoc);
}
@@ -347,7 +360,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(BSON("$set" << BSON("a" <<
static_cast<long long>(0xABCD1234EF981234ULL))), logDoc);
}
@@ -362,7 +376,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(BSON("$set" << BSON("a" <<
static_cast<long long>(0xABCD1234EF981234ULL))), logDoc);
}
@@ -440,7 +455,8 @@ namespace {
ASSERT_EQUALS(mongo::NumberInt, doc.root()["a"].getType());
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(BSON("$set" << BSON("a" << static_cast<int>(1))), logDoc);
}
@@ -458,7 +474,8 @@ namespace {
ASSERT_EQUALS(mongo::NumberInt, doc.root()["a"].getType());
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(BSON("$set" << BSON("b" << static_cast<int>(1))), logDoc);
}
diff --git a/src/mongo/db/ops/modifier_inc.cpp b/src/mongo/db/ops/modifier_inc.cpp
index 62af6efd6f5..c6e30c33263 100644
--- a/src/mongo/db/ops/modifier_inc.cpp
+++ b/src/mongo/db/ops/modifier_inc.cpp
@@ -19,6 +19,7 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/document.h"
#include "mongo/db/ops/field_checker.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/db/ops/path_support.h"
#include "mongo/util/mongoutils/str.h"
@@ -237,17 +238,13 @@ namespace mongo {
elemToSet);
}
- Status ModifierInc::log(mutablebson::Element logRoot) const {
+ Status ModifierInc::log(LogBuilder* logBuilder) const {
dassert(_preparedState->newValue.isValid());
// We'd like to create an entry such as {$set: {<fieldname>: <value>}} under 'logRoot'.
// We start by creating the {$set: ...} Element.
- mutablebson::Document& doc = logRoot.getDocument();
- mutablebson::Element setElement = doc.makeElementObject("$set");
- if (!setElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot append log entry for $set mod");
- }
+ mutablebson::Document& doc = logBuilder->getDocument();
// Then we create the {<fieldname>: <value>} Element.
mutablebson::Element logElement = doc.makeElementSafeNum(
@@ -255,17 +252,11 @@ namespace mongo {
_preparedState->newValue);
if (!logElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot append details for $set mod");
- }
-
- // Now, we attach the {<fieldname>: <value>} Element under the {$set: ...} one.
- Status status = setElement.pushBack(logElement);
- if (!status.isOK()) {
- return status;
+ return Status(ErrorCodes::InternalError, "cannot append details for $inc mod");
}
- // And attach the result under the 'logRoot' Element provided.
- return logRoot.pushBack(setElement);
+ // Now, we attach the {<fieldname>: <value>} Element under the {$set: ...} segment.
+ return logBuilder->addToSets(logElement);
}
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_inc.h b/src/mongo/db/ops/modifier_inc.h
index 5dc9f8fae95..73415fe83d7 100644
--- a/src/mongo/db/ops/modifier_inc.h
+++ b/src/mongo/db/ops/modifier_inc.h
@@ -26,6 +26,8 @@
namespace mongo {
+ class LogBuilder;
+
class ModifierInc : public ModifierInterface {
MONGO_DISALLOW_COPYING(ModifierInc);
@@ -53,7 +55,7 @@ namespace mongo {
virtual Status apply() const;
/** Converts the result of the $inc into an equivalent $set under logRoot */
- virtual Status log(mutablebson::Element logRoot) const;
+ virtual Status log(LogBuilder* logBuilder) const;
private:
diff --git a/src/mongo/db/ops/modifier_inc_test.cpp b/src/mongo/db/ops/modifier_inc_test.cpp
index 86e7a12a696..b5e76e8cfde 100644
--- a/src/mongo/db/ops/modifier_inc_test.cpp
+++ b/src/mongo/db/ops/modifier_inc_test.cpp
@@ -24,12 +24,14 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/platform/cstdint.h"
#include "mongo/unittest/unittest.h"
namespace {
using mongo::BSONObj;
+ using mongo::LogBuilder;
using mongo::ModifierInc;
using mongo::ModifierInterface;
using mongo::NumberInt;
@@ -62,8 +64,8 @@ namespace {
return _mod.apply();
}
- Status log(Element logRoot) const {
- return _mod.log(logRoot);
+ Status log(LogBuilder* logBuilder) const {
+ return _mod.log(logBuilder);
}
ModifierInc& mod() { return _mod; }
@@ -153,7 +155,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : 1 }"), doc);
Document logDoc;
- ASSERT_OK(incMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(incMod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : 1 } }"), logDoc);
}
@@ -167,7 +170,8 @@ namespace {
ASSERT_FALSE(execInfo.noOp);
Document logDoc;
- ASSERT_OK(incMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(incMod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : 1 } }"), logDoc);
}
@@ -184,7 +188,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : 3 }"), doc);
Document logDoc;
- ASSERT_OK(incMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(incMod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : 3 } }"), logDoc);
}
@@ -201,7 +206,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : { b : 3 } }"), doc);
Document logDoc;
- ASSERT_OK(incMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(incMod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { 'a.b' : 3 } }"), logDoc);
}
@@ -277,7 +283,8 @@ namespace {
ASSERT_EQUALS(mongo::NumberLong, doc.root()["a"].getType());
Document logDoc;
- ASSERT_OK(incMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(incMod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : 1 } }"), logDoc);
ASSERT_EQUALS(mongo::NumberLong, logDoc.root()["$set"]["a"].getType());
}
@@ -300,7 +307,8 @@ namespace {
ASSERT_EQUALS(mongo::NumberDouble, doc.root()["a"].getType());
Document logDoc;
- ASSERT_OK(incMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(incMod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : 1.0 } }"), logDoc);
ASSERT_EQUALS(mongo::NumberDouble, logDoc.root()["$set"]["a"].getType());
}
@@ -323,7 +331,8 @@ namespace {
ASSERT_EQUALS(mongo::NumberDouble, doc.root()["a"].getType());
Document logDoc;
- ASSERT_OK(incMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(incMod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : 1.0 } }"), logDoc);
ASSERT_EQUALS(mongo::NumberDouble, logDoc.root()["$set"]["a"].getType());
}
@@ -345,7 +354,8 @@ namespace {
ASSERT_EQUALS(mongo::NumberDouble, doc.root()["a"].getType());
Document logDoc;
- ASSERT_OK(incMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(incMod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : 2.0 } }"), logDoc);
ASSERT_EQUALS(mongo::NumberDouble, logDoc.root()["$set"]["a"].getType());
}
diff --git a/src/mongo/db/ops/modifier_interface.h b/src/mongo/db/ops/modifier_interface.h
index 476681e5639..3341de8ba20 100644
--- a/src/mongo/db/ops/modifier_interface.h
+++ b/src/mongo/db/ops/modifier_interface.h
@@ -24,6 +24,8 @@
namespace mongo {
+ class LogBuilder;
+
/**
* Abstract base class for update "modifiers" (a.k.a "$ operators"). To create a new
* operator, implement a new derived class.
@@ -104,10 +106,9 @@ namespace mongo {
virtual Status apply() const = 0 ;
/**
- * Returns OK and registers the result of this mod in 'logRoot', the document that
- * would eventually become a log entry. The mod must have kept enough state to
- * be able to produce the log record (see idempotency note below). This call may be
- * issued even if apply() was not.
+ * Returns OK and records the result of this mod in the provided LogBuilder. The mod
+ * must have kept enough state to be able to produce the log record (see idempotency
+ * note below). This call may be issued even if apply() was not.
*
* If the mod could not be logged, returns an error status with a reason description.
*
@@ -119,8 +120,7 @@ namespace mongo {
* for logging purposes. An array based operator may check the contents of the
* array before operating on it.
*/
- virtual Status log(mutablebson::Element logRoot) const = 0;
-
+ virtual Status log(LogBuilder* logBuilder) const = 0;
};
struct ModifierInterface::ExecInfo {
diff --git a/src/mongo/db/ops/modifier_object_replace.cpp b/src/mongo/db/ops/modifier_object_replace.cpp
index a8d6a128a85..70fdba5d718 100644
--- a/src/mongo/db/ops/modifier_object_replace.cpp
+++ b/src/mongo/db/ops/modifier_object_replace.cpp
@@ -18,6 +18,7 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/document.h"
+#include "mongo/db/ops/log_builder.h"
namespace mongo {
@@ -68,6 +69,8 @@ namespace mongo {
Status ModifierObjectReplace::init(const BSONElement& modExpr) {
+ // TODO: Check for ok for storage here.
+
if (modExpr.type() != Object) {
return Status(ErrorCodes::BadValue, "object replace expects full object");
}
@@ -134,20 +137,20 @@ namespace mongo {
return Status::OK();
}
- Status ModifierObjectReplace::log(mutablebson::Element logRoot) const {
+ Status ModifierObjectReplace::log(LogBuilder* logBuilder) const {
- // We'd like to create an entry such as {<object replacement>} under 'logRoot'.
- mutablebson::Document& doc = logRoot.getDocument();
- BSONObjIterator it(_val);
- while (it.more()) {
- BSONElement elem = it.next();
- Status status = doc.root().appendElement(elem);
- if (!status.isOK()) {
- return status;
- }
+ mutablebson::Document& doc = logBuilder->getDocument();
+
+ mutablebson::Element replacementObject = doc.end();
+ Status status = logBuilder->getReplacementObject(&replacementObject);
+
+ if (status.isOK()) {
+ BSONObjIterator it(_val);
+ while (status.isOK() && it.more())
+ status = replacementObject.appendElement(it.next());
}
- return Status::OK();
+ return status;
}
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_object_replace.h b/src/mongo/db/ops/modifier_object_replace.h
index edead81eeb1..f81ec8de299 100644
--- a/src/mongo/db/ops/modifier_object_replace.h
+++ b/src/mongo/db/ops/modifier_object_replace.h
@@ -24,6 +24,8 @@
namespace mongo {
+ class LogBuilder;
+
class ModifierObjectReplace : public ModifierInterface {
MONGO_DISALLOW_COPYING(ModifierObjectReplace);
@@ -65,7 +67,7 @@ namespace mongo {
* Adds a log entry to logRoot corresponding to full object replacement. Returns OK if
* successful or a status describing the error.
*/
- virtual Status log(mutablebson::Element logRoot) const;
+ virtual Status log(LogBuilder* logBuilder) const;
private:
diff --git a/src/mongo/db/ops/modifier_pop.cpp b/src/mongo/db/ops/modifier_pop.cpp
index 0aeb1406d72..6ce48efac8e 100644
--- a/src/mongo/db/ops/modifier_pop.cpp
+++ b/src/mongo/db/ops/modifier_pop.cpp
@@ -20,6 +20,7 @@
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/document.h"
#include "mongo/db/ops/field_checker.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/db/ops/path_support.h"
namespace mongo {
@@ -153,39 +154,27 @@ namespace mongo {
return _preparedState->elementToRemove.remove();
}
- Status ModifierPop::log(mutablebson::Element logRoot) const {
+ Status ModifierPop::log(LogBuilder* logBuilder) const {
// log document
- mutablebson::Document& doc = logRoot.getDocument();
+ mutablebson::Document& doc = logBuilder->getDocument();
const bool pathExists = _preparedState->pathFoundElement.ok() &&
- (_preparedState->pathFoundIndex ==
- static_cast<int32_t>(_fieldRef.numParts() - 1));
-
- // element to log, like $set/$unset
- mutablebson::Element opElement = pathExists ?
- doc.makeElementObject("$set") :
- doc.makeElementObject("$unset");
- if (!opElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot create log entry");
- }
+ (_preparedState->pathFoundIndex ==
+ static_cast<int32_t>(_fieldRef.numParts() - 1));
// value for the logElement ("field.path.name": <value>)
mutablebson::Element logElement = pathExists ?
- logRoot.getDocument().makeElementWithNewFieldName(
- _fieldRef.dottedField(),
- _preparedState->pathFoundElement
- ):
- doc.makeElementBool(_fieldRef.dottedField(), true);
+ doc.makeElementWithNewFieldName(
+ _fieldRef.dottedField(),
+ _preparedState->pathFoundElement) :
+ doc.makeElementBool(_fieldRef.dottedField(), true);
+
if (!logElement.ok()) {
return Status(ErrorCodes::InternalError, "cannot create details");
}
// Now, we attach the {<fieldname>: <value>} Element under the {$op: ...} one.
- Status status = opElement.pushBack(logElement);
- if (!status.isOK()) {
- return status;
- }
-
- // And attach the result under the 'logRoot' Element provided.
- return logRoot.pushBack(opElement);
+ return pathExists ?
+ logBuilder->addToSets(logElement) :
+ logBuilder->addToUnsets(logElement);
}
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_pop.h b/src/mongo/db/ops/modifier_pop.h
index 197e93af938..835712003c1 100644
--- a/src/mongo/db/ops/modifier_pop.h
+++ b/src/mongo/db/ops/modifier_pop.h
@@ -27,6 +27,8 @@
namespace mongo {
+ class LogBuilder;
+
class ModifierPop : public ModifierInterface {
MONGO_DISALLOW_COPYING(ModifierPop);
@@ -52,7 +54,7 @@ namespace mongo {
virtual Status apply() const;
- virtual Status log(mutablebson::Element logRoot) const;
+ virtual Status log(LogBuilder* logBuilder) const;
private:
diff --git a/src/mongo/db/ops/modifier_pop_test.cpp b/src/mongo/db/ops/modifier_pop_test.cpp
index 3a73b9fa446..5e278e9ac31 100644
--- a/src/mongo/db/ops/modifier_pop_test.cpp
+++ b/src/mongo/db/ops/modifier_pop_test.cpp
@@ -23,6 +23,7 @@
#include "mongo/bson/mutable/document.h"
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/db/json.h"
#include "mongo/platform/cstdint.h"
#include "mongo/unittest/unittest.h"
@@ -31,6 +32,7 @@ namespace {
using mongo::Array;
using mongo::BSONObj;
+ using mongo::LogBuilder;
using mongo::fromjson;
using mongo::ModifierInterface;
using mongo::ModifierPop;
@@ -59,8 +61,8 @@ namespace {
return _mod.apply();
}
- Status log(Element logRoot) const {
- return _mod.log(logRoot);
+ Status log(LogBuilder* logBuilder) const {
+ return _mod.log(logBuilder);
}
ModifierPop& mod() { return _mod; }
@@ -106,7 +108,8 @@ namespace {
ASSERT_TRUE(execInfo.noOp);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{$unset: {'s': true}}"), logDoc);
}
@@ -194,7 +197,8 @@ namespace {
ASSERT_EQUALS(fromjson(("{a:[1]}")), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), logDoc);
}
@@ -225,7 +229,8 @@ namespace {
ASSERT_EQUALS(fromjson(("{a:[]}")), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{$set: {a: []}}"), logDoc);
}
@@ -244,7 +249,8 @@ namespace {
ASSERT_EQUALS(fromjson(("{a:[[1], 1]}")), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{$set: { 'a.0': [1]}}"), logDoc);
}
@@ -263,7 +269,8 @@ namespace {
ASSERT_EQUALS(fromjson(("{a:[[], 1]}")), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{$set: { 'a.0': []}}"), logDoc);
}
diff --git a/src/mongo/db/ops/modifier_pull.cpp b/src/mongo/db/ops/modifier_pull.cpp
index 40b0d327ad6..204572a452f 100644
--- a/src/mongo/db/ops/modifier_pull.cpp
+++ b/src/mongo/db/ops/modifier_pull.cpp
@@ -20,6 +20,7 @@
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/db/matcher/expression_parser.h"
#include "mongo/db/ops/field_checker.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/db/ops/path_support.h"
namespace mongo {
@@ -184,12 +185,9 @@ namespace mongo {
return Status::OK();
}
- Status ModifierPull::log(mb::Element logRoot) const {
+ Status ModifierPull::log(LogBuilder* logBuilder) const {
- mb::Document& doc = logRoot.getDocument();
-
- mb::Element opElement = doc.end();
- mb::Element logElement = doc.end();
+ mb::Document& doc = logBuilder->getDocument();
if (!_preparedState->elemFound.ok() ||
_preparedState->idxFound < static_cast<int32_t>(_fieldRef.numParts() - 1)) {
@@ -197,12 +195,12 @@ namespace mongo {
// If we didn't find the element that we wanted to pull from, we log an unset for
// that element.
- opElement = doc.makeElementObject("$unset");
- if (!opElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot create log entry for $pull mod");
- }
+ mb::Element logElement = doc.makeElementInt(_fieldRef.dottedField(), 1);
+ if (!logElement.ok())
+ return Status(ErrorCodes::InternalError,
+ "cannot create log entry for $pull mod");
- logElement = doc.makeElementInt(_fieldRef.dottedField(), 1);
+ return logBuilder->addToUnsets(logElement);
} else {
@@ -215,13 +213,8 @@ namespace mongo {
// We'd like to create an entry such as {$set: {<fieldname>: [<resulting aray>]}} under
// 'logRoot'. We start by creating the {$set: ...} Element.
- opElement = doc.makeElementObject("$set");
- if (!opElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot create log entry for $pull mod");
- }
-
// Then we create the {<fieldname>:[]} Element, that is, an empty array.
- logElement = doc.makeElementArray(_fieldRef.dottedField());
+ mb::Element logElement = doc.makeElementArray(_fieldRef.dottedField());
if (!logElement.ok()) {
return Status(ErrorCodes::InternalError, "cannot create details for $pull mod");
}
@@ -246,16 +239,8 @@ namespace mongo {
curr = curr.rightSibling();
}
+ return logBuilder->addToSets(logElement);
}
-
- // Now, we attach log element under the op element.
- Status status = opElement.pushBack(logElement);
- if (!status.isOK()) {
- return status;
- }
-
- // And attach the result under the 'logRoot' Element provided by the caller.
- return logRoot.pushBack(opElement);
}
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_pull.h b/src/mongo/db/ops/modifier_pull.h
index 364f0e68549..afea9c3dbbb 100644
--- a/src/mongo/db/ops/modifier_pull.h
+++ b/src/mongo/db/ops/modifier_pull.h
@@ -46,7 +46,7 @@ namespace mongo {
virtual Status apply() const;
/** Converts the effects of this $pull into one or more equivalent $unset operations. */
- virtual Status log(mutablebson::Element logRoot) const;
+ virtual Status log(LogBuilder* logBuilder) const;
private:
// Access to each component of fieldName that's the target of this mod.
diff --git a/src/mongo/db/ops/modifier_pull_all.cpp b/src/mongo/db/ops/modifier_pull_all.cpp
index 88a23f87109..ea9d57faedb 100644
--- a/src/mongo/db/ops/modifier_pull_all.cpp
+++ b/src/mongo/db/ops/modifier_pull_all.cpp
@@ -20,6 +20,7 @@
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/document.h"
#include "mongo/db/ops/field_checker.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/db/ops/path_support.h"
namespace mongo {
@@ -191,41 +192,29 @@ namespace mongo {
return Status::OK();
}
- Status ModifierPullAll::log(mutablebson::Element logRoot) const {
+ Status ModifierPullAll::log(LogBuilder* logBuilder) const {
// log document
- mutablebson::Document& doc = logRoot.getDocument();
+ mutablebson::Document& doc = logBuilder->getDocument();
const bool pathExists = _preparedState->pathFoundElement.ok() &&
- (_preparedState->pathFoundIndex ==
- static_cast<int32_t>(_fieldRef.numParts() - 1));
-
- // element to log, like $set/$unset
- mutablebson::Element opElement = pathExists ?
- doc.makeElementObject("$set") :
- doc.makeElementObject("$unset");
- if (!opElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot create log entry");
- }
+ (_preparedState->pathFoundIndex ==
+ static_cast<int32_t>(_fieldRef.numParts() - 1));
// value for the logElement ("field.path.name": <value>)
mutablebson::Element logElement = pathExists ?
- logRoot.getDocument().makeElementWithNewFieldName(
- _fieldRef.dottedField(),
- _preparedState->pathFoundElement
- ):
- doc.makeElementBool(_fieldRef.dottedField(), true);
+ doc.makeElementWithNewFieldName(
+ _fieldRef.dottedField(),
+ _preparedState->pathFoundElement):
+ doc.makeElementBool(_fieldRef.dottedField(), true);
+
if (!logElement.ok()) {
return Status(ErrorCodes::InternalError, "cannot create details");
}
// Now, we attach the {<fieldname>: <value>} Element under the {$op: ...} one.
- Status status = opElement.pushBack(logElement);
- if (!status.isOK()) {
- return status;
- }
-
- // And attach the result under the 'logRoot' Element provided.
- return logRoot.pushBack(opElement);
+ return pathExists ?
+ logBuilder->addToSets(logElement) :
+ logBuilder->addToUnsets(logElement);
}
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_pull_all.h b/src/mongo/db/ops/modifier_pull_all.h
index d27637c2df5..8a157bf8271 100644
--- a/src/mongo/db/ops/modifier_pull_all.h
+++ b/src/mongo/db/ops/modifier_pull_all.h
@@ -27,6 +27,8 @@
namespace mongo {
+ class LogBuilder;
+
class ModifierPullAll : public ModifierInterface {
MONGO_DISALLOW_COPYING(ModifierPullAll);
@@ -50,7 +52,7 @@ namespace mongo {
virtual Status apply() const;
- virtual Status log(mutablebson::Element logRoot) const;
+ virtual Status log(LogBuilder* logBuilder) const;
private:
diff --git a/src/mongo/db/ops/modifier_pull_all_test.cpp b/src/mongo/db/ops/modifier_pull_all_test.cpp
index 880c71f5bec..1053cf8d74d 100644
--- a/src/mongo/db/ops/modifier_pull_all_test.cpp
+++ b/src/mongo/db/ops/modifier_pull_all_test.cpp
@@ -24,12 +24,14 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/platform/cstdint.h"
#include "mongo/unittest/unittest.h"
namespace {
using mongo::BSONObj;
+ using mongo::LogBuilder;
using mongo::ModifierPullAll;
using mongo::ModifierInterface;
using mongo::NumberInt;
@@ -61,8 +63,8 @@ namespace {
return _mod.apply();
}
- Status log(Element logRoot) const {
- return _mod.log(logRoot);
+ Status log(LogBuilder* logBuilder) const {
+ return _mod.log(logBuilder);
}
ModifierPullAll& mod() { return _mod; }
@@ -142,7 +144,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [] } }"), logDoc);
}
@@ -159,7 +162,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [] } }"), logDoc);
}
@@ -176,7 +180,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [] } }"), logDoc);
}
@@ -190,7 +195,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [1, 'a', {r:1, b:2}] } }"), logDoc);
}
@@ -204,7 +210,8 @@ namespace {
ASSERT_TRUE(execInfo.inPlace);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $unset : { b : true } }"), logDoc);
}
diff --git a/src/mongo/db/ops/modifier_pull_test.cpp b/src/mongo/db/ops/modifier_pull_test.cpp
index 53368379a42..064d717006a 100644
--- a/src/mongo/db/ops/modifier_pull_test.cpp
+++ b/src/mongo/db/ops/modifier_pull_test.cpp
@@ -22,12 +22,14 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/platform/cstdint.h"
#include "mongo/unittest/unittest.h"
namespace {
using mongo::BSONObj;
+ using mongo::LogBuilder;
using mongo::ModifierPull;
using mongo::ModifierInterface;
using mongo::Status;
@@ -57,8 +59,8 @@ namespace {
return _mod.apply();
}
- Status log(Element logRoot) const {
- return _mod.log(logRoot);
+ Status log(LogBuilder* logBuilder) const {
+ return _mod.log(logBuilder);
}
ModifierPull& mod() {
@@ -81,7 +83,8 @@ namespace {
ASSERT_TRUE(execInfo.noOp);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $unset : { a : 1 } }"), logDoc);
}
@@ -123,7 +126,8 @@ namespace {
ASSERT_TRUE(execInfo.noOp);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $unset : { a : 1 } }"), logDoc);
}
@@ -138,7 +142,8 @@ namespace {
ASSERT_TRUE(execInfo.noOp);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $unset : { 'a.b.c.d' : 1 } }"), logDoc);
}
@@ -153,7 +158,8 @@ namespace {
ASSERT_TRUE(execInfo.noOp);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [] } }"), logDoc);
}
@@ -168,7 +174,8 @@ namespace {
ASSERT_TRUE(execInfo.noOp);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [2, 3, 4, 5] } }"), logDoc);
}
@@ -186,7 +193,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [ 1, 2, 3, 4, 5 ] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [1, 2, 3, 4, 5] } }"), logDoc);
}
@@ -204,7 +212,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [ 1, 2, 3, 4, 5 ] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [1, 2, 3, 4, 5] } }"), logDoc);
}
@@ -222,7 +231,8 @@ namespace {
ASSERT_EQUALS(fromjson("{ a : [] }"), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson("{ $set : { a : [] } }"), logDoc);
}
@@ -262,7 +272,8 @@ namespace {
ASSERT_EQUALS(fromjson(strings[2]), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson(strings[3]), logDoc);
}
@@ -296,7 +307,8 @@ namespace {
ASSERT_EQUALS(fromjson(strings[2]), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson(strings[3]), logDoc);
}
#endif
@@ -330,7 +342,8 @@ namespace {
ASSERT_EQUALS(fromjson(strings[2]), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson(strings[3]), logDoc);
}
@@ -363,7 +376,8 @@ namespace {
ASSERT_EQUALS(fromjson(strings[2]), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson(strings[3]), logDoc);
}
@@ -396,7 +410,8 @@ namespace {
ASSERT_EQUALS(fromjson(strings[2]), doc);
Document logDoc;
- ASSERT_OK(mod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod.log(&logBuilder));
ASSERT_EQUALS(fromjson(strings[3]), logDoc);
}
diff --git a/src/mongo/db/ops/modifier_push.cpp b/src/mongo/db/ops/modifier_push.cpp
index cad0fdd10b1..875ea260f87 100644
--- a/src/mongo/db/ops/modifier_push.cpp
+++ b/src/mongo/db/ops/modifier_push.cpp
@@ -21,6 +21,7 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/db/ops/field_checker.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/db/ops/path_support.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/mongoutils/str.h"
@@ -515,36 +516,24 @@ namespace mongo {
return status;
}
- Status ModifierPush::log(mutablebson::Element logRoot) const {
+ Status ModifierPush::log(LogBuilder* logBuilder) const {
// TODO We can log just a positional set in several cases. For now, let's just log the
// full resulting array.
// We'd like to create an entry such as {$set: {<fieldname>: [<resulting aray>]}} under
// 'logRoot'. We start by creating the {$set: ...} Element.
- mutablebson::Document& doc = logRoot.getDocument();
- mutablebson::Element setElement = doc.makeElementObject("$set");
- if (!setElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot create log entry for $push mod");
- }
+ mutablebson::Document& doc = logBuilder->getDocument();
// value for the logElement ("field.path.name": <value>)
- mutablebson::Element logElement = logRoot.getDocument().makeElementWithNewFieldName(
- _fieldRef.dottedField(),
- _preparedState->elemFound);
+ mutablebson::Element logElement = doc.makeElementWithNewFieldName(
+ _fieldRef.dottedField(),
+ _preparedState->elemFound);
+
if (!logElement.ok()) {
return Status(ErrorCodes::InternalError, "cannot create details for $push mod");
}
- // Now, we attach the {<fieldname>: [<filled array>]} Element under the {$set: ...}
- // one.
- Status status = setElement.pushBack(logElement);
- if (!status.isOK()) {
- return status;
- }
-
- // And attach the result under the 'logRoot' Element provided.
- return logRoot.pushBack(setElement);
-
+ return logBuilder->addToSets(logElement);
}
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_push.h b/src/mongo/db/ops/modifier_push.h
index 42c0ff12dcc..9f5e0f99a13 100644
--- a/src/mongo/db/ops/modifier_push.h
+++ b/src/mongo/db/ops/modifier_push.h
@@ -28,6 +28,8 @@
namespace mongo {
+ class LogBuilder;
+
class ModifierPush : public ModifierInterface {
MONGO_DISALLOW_COPYING(ModifierPush);
@@ -83,7 +85,7 @@ namespace mongo {
*
* TODO Log a positional $set in the array, whenever possible.
*/
- virtual Status log(mutablebson::Element logRoot) const;
+ virtual Status log(LogBuilder* logBuilder) const;
private:
diff --git a/src/mongo/db/ops/modifier_push_test.cpp b/src/mongo/db/ops/modifier_push_test.cpp
index 0a8c46b670a..df12ff2fc2c 100644
--- a/src/mongo/db/ops/modifier_push_test.cpp
+++ b/src/mongo/db/ops/modifier_push_test.cpp
@@ -27,6 +27,7 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/platform/cstdint.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/mongoutils/str.h"
@@ -37,6 +38,7 @@ namespace {
using mongo::BSONObjBuilder;
using mongo::BSONArrayBuilder;
using mongo::fromjson;
+ using mongo::LogBuilder;
using mongo::ModifierInterface;
using mongo::ModifierPush;
using mongo::NumberInt;
@@ -437,8 +439,8 @@ namespace {
return _mod.apply();
}
- Status log(Element logRoot) const {
- return _mod.log(logRoot);
+ Status log(LogBuilder* logBuilder) const {
+ return _mod.log(logBuilder);
}
ModifierPush& mod() { return _mod; }
@@ -471,7 +473,8 @@ namespace {
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), logDoc);
}
@@ -491,7 +494,8 @@ namespace {
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), logDoc);
}
@@ -511,7 +515,8 @@ namespace {
ASSERT_EQUALS(fromjson("{a: [0,1]}"), doc);
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {a: [0,1]}}"), logDoc);
}
@@ -543,7 +548,8 @@ namespace {
ASSERT_EQUALS(fromjson("{a: [{b:1}]}"), doc);
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {a: [{b:1}]}}"), logDoc);
}
@@ -563,7 +569,8 @@ namespace {
ASSERT_EQUALS(fromjson("{a: [{b:1}]}"), doc);
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {a: [{b:1}]}}"), logDoc);
}
@@ -583,7 +590,8 @@ namespace {
ASSERT_EQUALS(fromjson("{a: [{b:0},{b:1}]}"), doc);
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {a: [{b:0},{b:1}]}}"), logDoc);
}
@@ -614,7 +622,8 @@ namespace {
doc);
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {'choices.first.votes':[1]}}"), logDoc);
}
@@ -639,7 +648,8 @@ namespace {
ASSERT_EQUALS(doc, fromjson("{a: [1]}"));
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_TRUE(checkDoc(logDoc, fromjson("{$set: {a: [1]}}")));
}
@@ -659,7 +669,8 @@ namespace {
ASSERT_EQUALS(doc, fromjson("{a: [1]}"));
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_TRUE(checkDoc(logDoc, fromjson("{$set: {a: [1]}}")));
}
@@ -679,7 +690,8 @@ namespace {
ASSERT_TRUE(checkDoc(doc, fromjson("{a: [0,1,2]}")));
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_TRUE(checkDoc(logDoc, fromjson("{$set: {a: [0,1,2]}}")));
}
@@ -711,7 +723,8 @@ namespace {
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), logDoc);
}
@@ -731,7 +744,8 @@ namespace {
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {a: [1]}}"), logDoc);
}
@@ -751,7 +765,8 @@ namespace {
ASSERT_EQUALS(fromjson("{a: [1, 2]}"), doc);
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {a: [1, 2]}}"), logDoc);
}
@@ -771,7 +786,8 @@ namespace {
ASSERT_EQUALS(fromjson("{a: [0,1]}"), doc);
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {a: [0,1]}}"), logDoc);
}
@@ -791,7 +807,8 @@ namespace {
ASSERT_EQUALS(fromjson("{a: [0,1,2]}"), doc);
Document logDoc;
- ASSERT_OK(pushMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(pushMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {a: [0,1,2]}}"), logDoc);
}
@@ -997,7 +1014,8 @@ namespace {
ASSERT_EQUALS(getObjectUsing(combinedVec), doc);
Document logDoc;
- ASSERT_OK(mod().log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod().log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(BSON("$set" << getObjectUsing(combinedVec)), logDoc);
@@ -1050,7 +1068,8 @@ namespace {
ASSERT_EQUALS(getObjectUsing(combinedVec), doc);
Document logDoc;
- ASSERT_OK(mod().log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(mod().log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(BSON("$set" << getObjectUsing(combinedVec)), logDoc);
diff --git a/src/mongo/db/ops/modifier_rename.cpp b/src/mongo/db/ops/modifier_rename.cpp
index 35e179e7747..ea7277b489e 100644
--- a/src/mongo/db/ops/modifier_rename.cpp
+++ b/src/mongo/db/ops/modifier_rename.cpp
@@ -19,6 +19,7 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/document.h"
#include "mongo/db/ops/field_checker.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/db/ops/path_support.h"
#include "mongo/util/mongoutils/str.h"
@@ -238,7 +239,7 @@ namespace mongo {
elemToSet);
}
- Status ModifierRename::log(mutablebson::Element logRoot) const {
+ Status ModifierRename::log(LogBuilder* logBuilder) const {
// If there was no element found then it was a noop, so return immediately
if (!_preparedState->fromElemFound.ok())
@@ -254,67 +255,37 @@ namespace mongo {
// We'd like to create an entry such as {$set: {<fieldname>: <value>}} under 'logRoot'.
// We start by creating the {$set: ...} Element.
- mutablebson::Document& doc = logRoot.getDocument();
+ mutablebson::Document& doc = logBuilder->getDocument();
- // Create $set
- mutablebson::Element setElement = doc.makeElementObject("$set");
- if (!setElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot create log entry for $set mod");
- }
-
- // Then we create the {<fieldname>: <value>} Element. Note that we log the mod with a
+ // Create the {<fieldname>: <value>} Element. Note that we log the mod with a
// dotted field, if it was applied over a dotted field. The rationale is that the
// secondary may be in a different state than the primary and thus make different
// decisions about creating the intermediate path in _fieldRef or not.
- mutablebson::Element logElement
- = doc.makeElementWithNewFieldName( setPath, _preparedState->fromElemFound.getValue());
- if (!logElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot create details for $set mod");
- }
+ mutablebson::Element logElement = doc.makeElementWithNewFieldName(
+ setPath, _preparedState->fromElemFound.getValue());
- // Now, we attach the {<fieldname>: <value>} Element under the {$set: ...} one.
- Status status = setElement.pushBack(logElement);
- if (!status.isOK()) {
- return status;
+ if (!logElement.ok()) {
+ return Status(ErrorCodes::InternalError, "cannot create details for $rename mod");
}
- mutablebson::Element unsetElement = doc.end();
- if (doUnset) {
- // Create $unset
- unsetElement = doc.makeElementObject("$unset");
- if (!setElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot create log entry for $unset mod");
- }
+ // Now, we attach the {<fieldname>: <value>} Element under the {$set: ...} section.
+ Status status = logBuilder->addToSets(logElement);
- // Then we create the {<fieldname>: <value>} Element. Note that we log the mod with a
+ if (status.isOK() && doUnset) {
+ // Create the {<fieldname>: <value>} Element. Note that we log the mod with a
// dotted field, if it was applied over a dotted field. The rationale is that the
// secondary may be in a different state than the primary and thus make different
// decisions about creating the intermediate path in _fieldRef or not.
mutablebson::Element unsetEntry = doc.makeElementBool(unsetPath, true);
if (!unsetEntry.ok()) {
- return Status(ErrorCodes::InternalError, "cannot create details for $unset mod");
+ return Status(ErrorCodes::InternalError, "cannot create details for $rename mod");
}
- // Now, we attach the {<fieldname>: <value>} Element under the {$set: ...} one.
- status = unsetElement.pushBack(unsetEntry);
- if (!status.isOK()) {
- return status;
- }
-
- }
-
- // And attach the result under the 'logRoot' Element provided.
- status = logRoot.pushBack(setElement);
- if (!status.isOK())
- return status;
-
- if (doUnset) {
- status = logRoot.pushBack(unsetElement);
- if (!status.isOK())
- return status;
+ // Now, we attach the Element under the {$unset: ...} section.
+ status = logBuilder->addToUnsets(unsetEntry);
}
- return Status::OK();
+ return status;
}
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_rename.h b/src/mongo/db/ops/modifier_rename.h
index ff6dad0fa1a..9a80f0ae0f2 100644
--- a/src/mongo/db/ops/modifier_rename.h
+++ b/src/mongo/db/ops/modifier_rename.h
@@ -27,6 +27,8 @@
namespace mongo {
+ class LogBuilder;
+
/**
* The $rename modifier moves the field from source to the destination to perform
* the rename.
@@ -68,7 +70,7 @@ namespace mongo {
* For the oplog entry we will generate an $unset on the 'from' field, and $set for
* the 'to' field. If no 'from' element is found then function will return immediately.
*/
- virtual Status log(mutablebson::Element logRoot) const;
+ virtual Status log(LogBuilder* logBuilder) const;
private:
diff --git a/src/mongo/db/ops/modifier_rename_test.cpp b/src/mongo/db/ops/modifier_rename_test.cpp
index e53a0349f73..6c6065c2303 100644
--- a/src/mongo/db/ops/modifier_rename_test.cpp
+++ b/src/mongo/db/ops/modifier_rename_test.cpp
@@ -23,6 +23,7 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/platform/cstdint.h"
#include "mongo/unittest/unittest.h"
@@ -30,6 +31,7 @@ namespace {
using mongo::BSONObj;
using mongo::fromjson;
+ using mongo::LogBuilder;
using mongo::ModifierInterface;
using mongo::NumberInt;
using mongo::ModifierRename;
@@ -59,8 +61,8 @@ namespace {
return _mod.apply();
}
- Status log(Element logRoot) const {
- return _mod.log(logRoot);
+ Status log(LogBuilder* logBuilder) const {
+ return _mod.log(logBuilder);
}
ModifierRename& mod() { return _mod; }
@@ -98,8 +100,9 @@ namespace {
ASSERT_OK(setMod.prepare(doc.root(), "", &execInfo));
Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
BSONObj logObj = fromjson("{}");
- ASSERT_OK(setMod.log(logDoc.root()));
+ ASSERT_OK(setMod.log(&logBuilder));
ASSERT_EQUALS(logDoc, logObj);
}
@@ -134,8 +137,9 @@ namespace {
ASSERT_EQUALS(doc, fromjson("{b:2}"));
Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
BSONObj logObj = fromjson("{$set:{ 'b': 2}, $unset: {'a': true}}");
- ASSERT_OK(setMod.log(logDoc.root()));
+ ASSERT_OK(setMod.log(&logBuilder));
ASSERT_EQUALS(logDoc, logObj);
}
@@ -155,8 +159,9 @@ namespace {
ASSERT_EQUALS(doc, fromjson("{b:2}"));
Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
BSONObj logObj = fromjson("{$set:{ 'b': 2}, $unset: {'a': true}}");
- ASSERT_OK(setMod.log(logDoc.root()));
+ ASSERT_OK(setMod.log(&logBuilder));
ASSERT_EQUALS(logDoc, logObj);
}
@@ -176,8 +181,9 @@ namespace {
ASSERT_EQUALS(doc, fromjson("{a: {}, b:{ d: 6}}"));
Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
BSONObj logObj = fromjson("{$set:{ 'b': {d: 6}}, $unset: {'a.c': true}}");
- ASSERT_OK(setMod.log(logDoc.root()));
+ ASSERT_OK(setMod.log(&logBuilder));
ASSERT_EQUALS(logDoc, logObj);
}
@@ -197,8 +203,9 @@ namespace {
ASSERT_EQUALS(doc, fromjson("{b:1, c: { r: { d: 2}}}"));
Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
BSONObj logObj = fromjson("{$set:{ 'c.r.d': 2}, $unset: {'a': true}}");
- ASSERT_OK(setMod.log(logDoc.root()));
+ ASSERT_OK(setMod.log(&logBuilder));
ASSERT_EQUALS(logDoc, logObj);
}
@@ -218,8 +225,9 @@ namespace {
ASSERT_EQUALS(doc, fromjson("{b: {c: {d: 2}}}"));
Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
BSONObj logObj = fromjson("{$set:{ 'b.c.d': 2}, $unset: {'a': true}}");
- ASSERT_OK(setMod.log(logDoc.root()));
+ ASSERT_OK(setMod.log(&logBuilder));
ASSERT_EQUALS(logDoc, logObj);
}
@@ -239,8 +247,9 @@ namespace {
ASSERT_EQUALS(doc, fromjson("{b: {c: {d: [ {a:2, b:1} ]}}}"));
Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
BSONObj logObj = fromjson("{$set:{ 'b.c.d': [ {a:2, b:1} ]}, $unset: {'a': true}}");
- ASSERT_OK(setMod.log(logDoc.root()));
+ ASSERT_OK(setMod.log(&logBuilder));
ASSERT_EQUALS(logDoc, logObj);
}
diff --git a/src/mongo/db/ops/modifier_set.cpp b/src/mongo/db/ops/modifier_set.cpp
index d940baf4a3d..2de14dc020b 100644
--- a/src/mongo/db/ops/modifier_set.cpp
+++ b/src/mongo/db/ops/modifier_set.cpp
@@ -19,6 +19,7 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/document.h"
#include "mongo/db/ops/field_checker.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/db/ops/path_support.h"
namespace mongo {
@@ -227,34 +228,24 @@ namespace mongo {
elemToSet);
}
- Status ModifierSet::log(mutablebson::Element logRoot) const {
+ Status ModifierSet::log(LogBuilder* logBuilder) const {
// We'd like to create an entry such as {$set: {<fieldname>: <value>}} under 'logRoot'.
// We start by creating the {$set: ...} Element.
- mutablebson::Document& doc = logRoot.getDocument();
- mutablebson::Element setElement = doc.makeElementObject("$set");
- if (!setElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot create log entry for $set mod");
- }
+ mutablebson::Document& doc = logBuilder->getDocument();
- // Then we create the {<fieldname>: <value>} Element. Note that we log the mod with a
+ // Create the {<fieldname>: <value>} Element. Note that we log the mod with a
// dotted field, if it was applied over a dotted field. The rationale is that the
// secondary may be in a different state than the primary and thus make different
// decisions about creating the intermediate path in _fieldRef or not.
- mutablebson::Element logElement = doc.makeElementWithNewFieldName(_fieldRef.dottedField(),
- _val);
+ mutablebson::Element logElement = doc.makeElementWithNewFieldName(
+ _fieldRef.dottedField(), _val);
+
if (!logElement.ok()) {
return Status(ErrorCodes::InternalError, "cannot create details for $set mod");
}
- // Now, we attach the {<fieldname>: <value>} Element under the {$set: ...} one.
- Status status = setElement.pushBack(logElement);
- if (!status.isOK()) {
- return status;
- }
-
- // And attach the result under the 'logRoot' Element provided.
- return logRoot.pushBack(setElement);
+ return logBuilder->addToSets(logElement);
}
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_set.h b/src/mongo/db/ops/modifier_set.h
index 6e5a2df1e0f..71d44abe9cd 100644
--- a/src/mongo/db/ops/modifier_set.h
+++ b/src/mongo/db/ops/modifier_set.h
@@ -27,6 +27,8 @@
namespace mongo {
+ class LogBuilder;
+
class ModifierSet : public ModifierInterface {
MONGO_DISALLOW_COPYING(ModifierSet);
@@ -70,7 +72,7 @@ namespace mongo {
* Adds a log entry to logRoot corresponding to the operation applied here. Returns OK
* if successful or a status describing the error.
*/
- virtual Status log(mutablebson::Element logRoot) const;
+ virtual Status log(LogBuilder* logBuilder) const;
private:
diff --git a/src/mongo/db/ops/modifier_set_test.cpp b/src/mongo/db/ops/modifier_set_test.cpp
index 1e036fb5987..daa2f1ae852 100644
--- a/src/mongo/db/ops/modifier_set_test.cpp
+++ b/src/mongo/db/ops/modifier_set_test.cpp
@@ -24,6 +24,7 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/platform/cstdint.h"
#include "mongo/unittest/unittest.h"
@@ -31,6 +32,7 @@ namespace {
using mongo::BSONObj;
using mongo::fromjson;
+ using mongo::LogBuilder;
using mongo::ModifierInterface;
using mongo::NumberInt;
using mongo::ModifierSet;
@@ -64,8 +66,8 @@ namespace {
return _mod.apply();
}
- Status log(Element logRoot) const {
- return _mod.log(logRoot);
+ Status log(LogBuilder* logBuilder) const {
+ return _mod.log(logBuilder);
}
ModifierSet& mod() { return _mod; }
@@ -204,7 +206,8 @@ namespace {
ASSERT_OK(setMod.prepare(doc.root(), "", &dummy));
Document logDoc;
- ASSERT_OK(setMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(setMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {a: 2}}"), logDoc);
}
@@ -514,7 +517,8 @@ namespace {
ASSERT_OK(setMod.prepare(doc.root(), "", &execInfo));
Document logDoc;
- ASSERT_OK(setMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(setMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), logDoc);
}
@@ -528,7 +532,8 @@ namespace {
ASSERT_OK(setMod.prepare(doc.root(), "", &execInfo));
Document logDoc;
- ASSERT_OK(setMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(setMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), logDoc);
}
@@ -542,7 +547,8 @@ namespace {
ASSERT_OK(setMod.prepare(doc.root(), "", &execInfo));
Document logDoc;
- ASSERT_OK(setMod.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(setMod.log(&logBuilder));
ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), logDoc);
}
diff --git a/src/mongo/db/ops/modifier_unset.cpp b/src/mongo/db/ops/modifier_unset.cpp
index 6e029cdf1ea..1431f06bcc2 100644
--- a/src/mongo/db/ops/modifier_unset.cpp
+++ b/src/mongo/db/ops/modifier_unset.cpp
@@ -19,6 +19,7 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/document.h"
#include "mongo/db/ops/field_checker.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/db/ops/path_support.h"
namespace mongo {
@@ -163,17 +164,13 @@ namespace mongo {
}
}
- Status ModifierUnset::log(mutablebson::Element logRoot) const {
+ Status ModifierUnset::log(LogBuilder* logBuilder) const {
// We'd like to create an entry such as {$unset: {<fieldname>: 1}} under 'logRoot'.
// We start by creating the {$unset: ...} Element.
- mutablebson::Document& doc = logRoot.getDocument();
- mutablebson::Element unsetElement = doc.makeElementObject("$unset");
- if (!unsetElement.ok()) {
- return Status(ErrorCodes::InternalError, "cannot create log entry for $unset mod");
- }
+ mutablebson::Document& doc = logBuilder->getDocument();
- // Then we create the {<fieldname>: <value>} Element. Note that <fieldname> must be a
+ // Create the {<fieldname>: <value>} Element. Note that <fieldname> must be a
// dotted field, and not only the last part of that field. The rationale here is that
// somoene picking up this log entry -- e.g., a secondary -- must be capable of doing
// the same path find/creation that was done in the previous calls here.
@@ -182,14 +179,7 @@ namespace mongo {
return Status(ErrorCodes::InternalError, "cannot create log details for $unset mod");
}
- // Now, we attach the {<fieldname>: `} Element under the {$unset: ...} one.
- Status status = unsetElement.pushBack(logElement);
- if (!status.isOK()) {
- return status;
- }
-
- // And attach the result under the 'logRoot' Element provided.
- return logRoot.pushBack(unsetElement);
+ return logBuilder->addToUnsets(logElement);
}
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_unset.h b/src/mongo/db/ops/modifier_unset.h
index 0b591969cf9..a4a64135284 100644
--- a/src/mongo/db/ops/modifier_unset.h
+++ b/src/mongo/db/ops/modifier_unset.h
@@ -27,6 +27,8 @@
namespace mongo {
+ class LogBuilder;
+
class ModifierUnset : public ModifierInterface {
MONGO_DISALLOW_COPYING(ModifierUnset);
@@ -65,7 +67,7 @@ namespace mongo {
/**
* Adds the exact $unset mod to the log.
*/
- virtual Status log(mutablebson::Element logRoot) const;
+ virtual Status log(LogBuilder* logBuilder) const;
private:
diff --git a/src/mongo/db/ops/modifier_unset_test.cpp b/src/mongo/db/ops/modifier_unset_test.cpp
index bc0058ae3fe..f2a1416a111 100644
--- a/src/mongo/db/ops/modifier_unset_test.cpp
+++ b/src/mongo/db/ops/modifier_unset_test.cpp
@@ -24,6 +24,7 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/platform/cstdint.h"
#include "mongo/unittest/unittest.h"
@@ -32,6 +33,7 @@ namespace {
using mongo::Array;
using mongo::BSONObj;
using mongo::fromjson;
+ using mongo::LogBuilder;
using mongo::ModifierInterface;
using mongo::ModifierUnset;
using mongo::Status;
@@ -59,8 +61,8 @@ namespace {
return _mod.apply();
}
- Status log(Element logRoot) const {
- return _mod.log(logRoot);
+ Status log(LogBuilder* logBuilder) const {
+ return _mod.log(logBuilder);
}
ModifierUnset& mod() { return _mod; }
@@ -161,7 +163,8 @@ namespace {
ASSERT_FALSE(execInfo.noOp);
Document logDoc;
- ASSERT_OK(modUnset.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(modUnset.log(&logBuilder));
ASSERT_EQUALS(modUnset.modObj(), logDoc);
}
@@ -326,7 +329,8 @@ namespace {
ASSERT_OK(modUnset.prepare(doc.root(), "", &execInfo));
Document logDoc;
- ASSERT_OK(modUnset.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(modUnset.log(&logBuilder));
ASSERT_EQUALS(modUnset.modObj(), logDoc);
}
@@ -411,7 +415,8 @@ namespace {
ASSERT_FALSE(execInfo.noOp);
Document logDoc;
- ASSERT_OK(modUnset.log(logDoc.root()));
+ LogBuilder logBuilder(logDoc.root());
+ ASSERT_OK(modUnset.log(&logBuilder));
ASSERT_EQUALS(fromjson("{$unset: {'a.0.b': 1}}"), logDoc);
}
diff --git a/src/mongo/db/ops/update_driver.cpp b/src/mongo/db/ops/update_driver.cpp
index c0987e28c1b..893bdb2f640 100644
--- a/src/mongo/db/ops/update_driver.cpp
+++ b/src/mongo/db/ops/update_driver.cpp
@@ -21,6 +21,7 @@
#include "mongo/bson/mutable/document.h"
#include "mongo/db/field_ref.h"
#include "mongo/db/field_ref_set.h"
+#include "mongo/db/ops/log_builder.h"
#include "mongo/db/ops/modifier_object_replace.h"
#include "mongo/db/ops/modifier_table.h"
#include "mongo/util/embedded_builder.h"
@@ -167,6 +168,13 @@ namespace mongo {
FieldRefSet targetFields;
_affectIndices = false;
+ // TODO: Should logBuilder own the document? Should we hold it by pointer to avoid
+ // creating it if we are not interested in logging? Or maybe by boost optional? For
+ // now, it is logically harmless to construct this and not use it, but a Document
+ // object isn't cheap, so we should avoid building it if we can.
+ mutablebson::Document logDoc;
+ LogBuilder logBuilder(logDoc.root());
+
// Ask each of the mods to type check whether they can operate over the current document
// and, if so, to change that document accordingly.
for (vector<ModifierInterface*>::iterator it = _mods.begin(); it != _mods.end(); ++it) {
@@ -218,25 +226,25 @@ namespace mongo {
}
if (!execInfo.noOp && validContext) {
- Status status = (*it)->apply();
+ status = (*it)->apply();
if (!status.isOK()) {
return status;
}
}
- }
- // If we require a replication oplog entry for this update, go ahead and generate one.
- if (_logOp && logOpRec) {
- mutablebson::Document logDoc;
- for (vector<ModifierInterface*>::iterator it = _mods.begin(); it != _mods.end(); ++it) {
- Status status = (*it)->log(logDoc.root());
+ // If we require a replication oplog entry for this update, go ahead and generate one.
+ if (_logOp && logOpRec) {
+ status = (*it)->log(&logBuilder);
if (!status.isOK()) {
return status;
}
}
- *logOpRec = logDoc.getObject();
+
}
+ if (_logOp && logOpRec)
+ *logOpRec = logDoc.getObject();
+
return Status::OK();
}