summaryrefslogtreecommitdiff
path: root/src/mongo/db/ops/log_builder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/ops/log_builder.cpp')
-rw-r--r--src/mongo/db/ops/log_builder.cpp115
1 files changed, 115 insertions, 0 deletions
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